summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/mmc/sdhci-msm.txt5
-rw-r--r--Documentation/devicetree/bindings/pci/msm_pcie.txt10
-rw-r--r--arch/arm/boot/dts/qcom/dsi-panel-sharp-split-link-wuxga-video.dtsi68
-rw-r--r--arch/arm/boot/dts/qcom/fg-gen3-batterydata-itech-3000mah.dtsi2
-rw-r--r--arch/arm/boot/dts/qcom/fg-gen3-batterydata-qrd-skuk-4v4-3000mah.dtsi1
-rw-r--r--arch/arm/boot/dts/qcom/msm-pm660l.dtsi9
-rw-r--r--arch/arm/boot/dts/qcom/msm-pmi8998.dtsi9
-rw-r--r--arch/arm/boot/dts/qcom/msm8996-auto-cdp.dtsi4
-rw-r--r--arch/arm/boot/dts/qcom/msm8996.dtsi6
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-interposer-sdm660.dtsi4
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi14
-rw-r--r--arch/arm/boot/dts/qcom/msm8998.dtsi4
-rw-r--r--arch/arm/boot/dts/qcom/sdm630-mdss.dtsi4
-rw-r--r--arch/arm/boot/dts/qcom/sdm630.dtsi10
-rw-r--r--arch/arm/boot/dts/qcom/sdm660-pinctrl.dtsi14
-rw-r--r--arch/arm/boot/dts/qcom/sdm660.dtsi10
-rw-r--r--arch/arm64/configs/msmcortex-perf_defconfig6
-rw-r--r--arch/arm64/configs/msmcortex_defconfig6
-rw-r--r--drivers/android/binder.c6
-rw-r--r--drivers/char/adsprpc.c5
-rw-r--r--drivers/clk/msm/mdss/mdss-dsi-pll-8998.c112
-rw-r--r--drivers/crypto/msm/ice.c3
-rw-r--r--drivers/gpu/msm/adreno_ringbuffer.c6
-rw-r--r--drivers/leds/leds-qpnp-flash-v2.c151
-rw-r--r--drivers/media/platform/msm/vidc/msm_vdec.c32
-rw-r--r--drivers/media/platform/msm/vidc/msm_vidc_common.c13
-rw-r--r--drivers/media/platform/msm/vidc/msm_vidc_res_parse.c2
-rw-r--r--drivers/mmc/card/block.c58
-rw-r--r--drivers/mmc/core/core.c4
-rw-r--r--drivers/mmc/core/core.h1
-rw-r--r--drivers/mmc/core/sd.c2
-rw-r--r--drivers/mmc/host/sdhci-msm.c3
-rw-r--r--drivers/mmc/host/sdhci-msm.h1
-rw-r--r--drivers/mmc/host/sdhci.c5
-rw-r--r--drivers/net/ethernet/msm/msm_rmnet_mhi.c453
-rw-r--r--drivers/net/wireless/ath/wil6210/pm.c16
-rw-r--r--drivers/net/wireless/ath/wil6210/wil6210.h1
-rw-r--r--drivers/pci/host/pci-msm.c103
-rw-r--r--drivers/platform/msm/ipa/ipa_v2/ipa.c11
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa.c11
-rw-r--r--drivers/platform/msm/mhi_uci/mhi_uci.c36
-rw-r--r--drivers/power/power_supply_sysfs.c1
-rw-r--r--drivers/power/qcom/msm-core.c4
-rw-r--r--drivers/power/supply/qcom/battery.c139
-rw-r--r--drivers/power/supply/qcom/qpnp-smb2.c30
-rw-r--r--drivers/power/supply/qcom/smb-lib.c188
-rw-r--r--drivers/power/supply/qcom/smb-lib.h8
-rw-r--r--drivers/power/supply/qcom/smb-reg.h1
-rw-r--r--drivers/power/supply/qcom/smb1351-charger.c2
-rw-r--r--drivers/power/supply/qcom/smb138x-charger.c12
-rw-r--r--drivers/pps/clients/pps-gpio.c2
-rw-r--r--drivers/scsi/sd.c8
-rw-r--r--drivers/scsi/sd.h5
-rw-r--r--drivers/scsi/ufs/ufshcd.c20
-rw-r--r--drivers/soc/qcom/icnss.c3
-rw-r--r--drivers/soc/qcom/msm_glink_pkt.c3
-rw-r--r--drivers/spi/spi_qsd.c197
-rw-r--r--drivers/spi/spi_qsd.h12
-rw-r--r--drivers/usb/gadget/function/f_gsi.c17
-rw-r--r--drivers/video/fbdev/msm/mdss_dp.c18
-rw-r--r--include/linux/mmc/card.h2
-rw-r--r--include/linux/mmc/core.h1
-rw-r--r--include/linux/mmc/host.h11
-rw-r--r--include/linux/power_supply.h1
-rw-r--r--include/linux/sched.h9
-rw-r--r--kernel/cpu.c39
-rw-r--r--kernel/sched/core.c21
-rw-r--r--sound/soc/codecs/wcd934x/wcd934x.c5
68 files changed, 1309 insertions, 671 deletions
diff --git a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
index 0b46fd3d8ebf..d00e26b4d5ed 100644
--- a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
+++ b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
@@ -75,6 +75,11 @@ Optional Properties:
during clock scaling. If this property is not
defined, then it falls back to the default HS
bus speed mode to maintain backward compatibility.
+ - qcom,sdr104-wa: On Certain chipsets, SDR104 mode might be unstable causing CRC errors
+ on the interface. So there is a workaround implemented to skip printing
+ register dumps on CRC errors and also downgrade bus speed mode to
+ SDR50/DDR50 in case of continuous CRC errors. Set this flag to enable
+ this workaround.
In the following, <supply> can be vdd (flash core voltage) or vdd-io (I/O voltage).
- qcom,<supply>-always-on - specifies whether supply should be kept "on" always.
diff --git a/Documentation/devicetree/bindings/pci/msm_pcie.txt b/Documentation/devicetree/bindings/pci/msm_pcie.txt
index a50e0c2b2c35..fc019bda50a7 100644
--- a/Documentation/devicetree/bindings/pci/msm_pcie.txt
+++ b/Documentation/devicetree/bindings/pci/msm_pcie.txt
@@ -79,8 +79,12 @@ Optional Properties:
PCIe port PHY.
Should be specified in groups (offset, value, delay).
- qcom,use-19p2mhz-aux-clk: The frequency of PCIe AUX clock is 19.2MHz.
- - qcom,ep-wakeirq: The endpoint will issue wake signal when it is up, and the
- root complex has the capability to enumerate the endpoint for this case.
+ - qcom,boot-option: Bits that alter PCIe bus driver boot sequence.
+ Below details what happens when each bit is set
+ BIT(0): PCIe bus driver will not start enumeration during its probe.
+ Clients will control when PCIe bus driver should do enumeration.
+ BIT(1): PCIe bus driver will not start enumeration if it receives a WAKE
+ interrupt.
- qcom,msi-gicm-addr: MSI address for GICv2m.
- qcom,msi-gicm-base: MSI IRQ base for GICv2m.
- qcom,ext-ref-clk: The reference clock is external.
@@ -263,7 +267,7 @@ Example:
qcom,aux-clk-sync;
qcom,n-fts = <0x50>;
qcom,pcie-phy-ver = <1>;
- qcom,ep-wakeirq;
+ qcom,boot-option = <0x1>;
qcom,msi-gicm-addr = <0xf9040040>;
qcom,msi-gicm-base = <0x160>;
qcom,ext-ref-clk;
diff --git a/arch/arm/boot/dts/qcom/dsi-panel-sharp-split-link-wuxga-video.dtsi b/arch/arm/boot/dts/qcom/dsi-panel-sharp-split-link-wuxga-video.dtsi
new file mode 100644
index 000000000000..143b0152dcf4
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/dsi-panel-sharp-split-link-wuxga-video.dtsi
@@ -0,0 +1,68 @@
+/* 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.
+ */
+
+&mdss_mdp {
+ dsi_sharp_split_link_wuxga_video:
+ qcom,mdss_dsi_sharp_split_link_wuxga_video {
+ qcom,mdss-dsi-panel-name =
+ "SHARP split DSI video mode dsi panel";
+ qcom,mdss-dsi-panel-type = "dsi_video_mode";
+ qcom,mdss-dsi-panel-framerate = <60>;
+ qcom,mdss-dsi-virtual-channel-id = <0>;
+ qcom,mdss-dsi-stream = <0>;
+ qcom,mdss-dsi-panel-width = <600>;
+ qcom,mdss-dsi-panel-height = <1920>;
+ qcom,mdss-dsi-h-front-porch = <54>;
+ qcom,mdss-dsi-h-back-porch = <4>;
+ qcom,mdss-dsi-h-pulse-width = <6>;
+ qcom,mdss-dsi-h-sync-skew = <0>;
+ qcom,mdss-dsi-v-back-porch = <6>;
+ qcom,mdss-dsi-v-front-porch = <12>;
+ qcom,mdss-dsi-v-pulse-width = <2>;
+ qcom,mdss-dsi-bpp = <24>;
+ qcom,mdss-dsi-underflow-color = <0x654321>;
+ qcom,mdss-dsi-border-color = <0>;
+ qcom,mdss-dsi-on-command = [05 01 00 00 a0 00 02 11 00];
+ qcom,mdss-dsi-pre-off-command = [05 01 00 00 02 00 02 28 00
+ 05 01 00 00 a0 00 02 10 00];
+ qcom,mdss-dsi-post-panel-on-command =
+ [05 01 00 00 a0 00 02 29 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 = <0>;
+ qcom,mdss-dsi-traffic-mode = "non_burst_sync_event";
+ qcom,mdss-dsi-bllp-eof-power-mode;
+ qcom,mdss-dsi-bllp-power-mode;
+ qcom,mdss-dsi-lane-0-state;
+ qcom,mdss-dsi-lane-1-state;
+ qcom,mdss-dsi-lane-2-state;
+ qcom,mdss-dsi-lane-3-state;
+ qcom,mdss-dsi-panel-timings =
+ [00 24 07 08 0e 14 07 09 07 03 04 00];
+ qcom,mdss-dsi-t-clk-post = <0x0e>;
+ qcom,mdss-dsi-t-clk-pre = <0x35>;
+ qcom,mdss-dsi-bl-min-level = <1>;
+ qcom,mdss-dsi-bl-max-level = <4095>;
+ qcom,mdss-dsi-dma-trigger = "trigger_sw";
+ qcom,mdss-dsi-mdp-trigger = "none";
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm";
+ qcom,mdss-dsi-bl-pmic-pwm-frequency = <50>;
+ qcom,mdss-dsi-bl-pmic-bank-select = <2>;
+ qcom,mdss-dsi-reset-sequence = <1 2>, <0 5>, <1 120>;
+ qcom,mdss-pan-physical-width-dimension = <83>;
+ qcom,mdss-pan-physical-height-dimension = <133>;
+ qcom,mdss-dsi-tx-eot-append;
+ qcom,split-link-enabled = <1>;
+ qcom,sublinks-count = <2>;
+ qcom,lanes-per-sublink = <2>;
+ };
+};
diff --git a/arch/arm/boot/dts/qcom/fg-gen3-batterydata-itech-3000mah.dtsi b/arch/arm/boot/dts/qcom/fg-gen3-batterydata-itech-3000mah.dtsi
index 03801ee90589..3888047b9f8c 100644
--- a/arch/arm/boot/dts/qcom/fg-gen3-batterydata-itech-3000mah.dtsi
+++ b/arch/arm/boot/dts/qcom/fg-gen3-batterydata-itech-3000mah.dtsi
@@ -14,7 +14,7 @@ qcom,itech_3000mah {
/* #Itech_B00826LF_3000mAh_ver1660_averaged_MasterSlave_Jan10th2017*/
qcom,max-voltage-uv = <4350000>;
qcom,fg-cc-cv-threshold-mv = <4340>;
- qcom,fastchg-current-ma = <3000>;
+ qcom,fastchg-current-ma = <2000>;
qcom,batt-id-kohm = <100>;
qcom,battery-beta = <3435>;
qcom,battery-type = "itech_b00826lf_3000mah_ver1660_jan10th2017";
diff --git a/arch/arm/boot/dts/qcom/fg-gen3-batterydata-qrd-skuk-4v4-3000mah.dtsi b/arch/arm/boot/dts/qcom/fg-gen3-batterydata-qrd-skuk-4v4-3000mah.dtsi
index 8cbb29aac927..11600ef2bfd3 100644
--- a/arch/arm/boot/dts/qcom/fg-gen3-batterydata-qrd-skuk-4v4-3000mah.dtsi
+++ b/arch/arm/boot/dts/qcom/fg-gen3-batterydata-qrd-skuk-4v4-3000mah.dtsi
@@ -13,6 +13,7 @@
qcom,qrd_msm8998_skuk_3000mah {
/* QRD8997_ST1031GA_3000mAh_averaged_MasterSlave_Jan10th2017 */
qcom,max-voltage-uv = <4400000>;
+ qcom,fg-cc-cv-threshold-mv = <4390>;
qcom,fastchg-current-ma = <3000>;
qcom,batt-id-kohm = <68>;
qcom,battery-beta = <3380>;
diff --git a/arch/arm/boot/dts/qcom/msm-pm660l.dtsi b/arch/arm/boot/dts/qcom/msm-pm660l.dtsi
index 7f386957d555..fdc04b9726b4 100644
--- a/arch/arm/boot/dts/qcom/msm-pm660l.dtsi
+++ b/arch/arm/boot/dts/qcom/msm-pm660l.dtsi
@@ -330,9 +330,6 @@
qcom,ires-ua = <12500>;
qcom,hdrm-voltage-mv = <325>;
qcom,hdrm-vol-hi-lo-win-mv = <100>;
- pinctrl-names = "led_enable","led_disable";
- pinctrl-0 = <&led_enable>;
- pinctrl-1 = <&led_disable>;
};
pm660l_torch0: qcom,torch_0 {
@@ -369,9 +366,6 @@
qcom,ires-ua = <12500>;
qcom,hdrm-voltage-mv = <325>;
qcom,hdrm-vol-hi-lo-win-mv = <100>;
- pinctrl-names = "led_enable","led_disable";
- pinctrl-0 = <&led_enable>;
- pinctrl-1 = <&led_disable>;
};
pm660l_switch0: qcom,led_switch_0 {
@@ -386,6 +380,9 @@
qcom,led-name = "led:switch_1";
qcom,led-mask = <4>;
qcom,default-led-trigger = "switch1_trigger";
+ pinctrl-names = "led_enable","led_disable";
+ pinctrl-0 = <&led_enable>;
+ pinctrl-1 = <&led_disable>;
};
};
diff --git a/arch/arm/boot/dts/qcom/msm-pmi8998.dtsi b/arch/arm/boot/dts/qcom/msm-pmi8998.dtsi
index 0cf67dd938e6..2d2b628ca815 100644
--- a/arch/arm/boot/dts/qcom/msm-pmi8998.dtsi
+++ b/arch/arm/boot/dts/qcom/msm-pmi8998.dtsi
@@ -712,9 +712,6 @@
qcom,ires-ua = <12500>;
qcom,hdrm-voltage-mv = <325>;
qcom,hdrm-vol-hi-lo-win-mv = <100>;
- pinctrl-names = "led_enable","led_disable";
- pinctrl-0 = <&led_enable>;
- pinctrl-1 = <&led_disable>;
};
pmi8998_torch0: qcom,torch_0 {
@@ -751,9 +748,6 @@
qcom,ires-ua = <12500>;
qcom,hdrm-voltage-mv = <325>;
qcom,hdrm-vol-hi-lo-win-mv = <100>;
- pinctrl-names = "led_enable","led_disable";
- pinctrl-0 = <&led_enable>;
- pinctrl-1 = <&led_disable>;
};
pmi8998_switch0: qcom,led_switch_0 {
@@ -768,6 +762,9 @@
qcom,led-name = "led:switch_1";
qcom,led-mask = <4>;
qcom,default-led-trigger = "switch1_trigger";
+ pinctrl-names = "led_enable","led_disable";
+ pinctrl-0 = <&led_enable>;
+ pinctrl-1 = <&led_disable>;
};
};
};
diff --git a/arch/arm/boot/dts/qcom/msm8996-auto-cdp.dtsi b/arch/arm/boot/dts/qcom/msm8996-auto-cdp.dtsi
index 97036ae144ae..7fffe81c7614 100644
--- a/arch/arm/boot/dts/qcom/msm8996-auto-cdp.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8996-auto-cdp.dtsi
@@ -974,14 +974,14 @@
};
&pcie1 {
- /delete-property/ qcom,ep-wakeirq;
+ /delete-property/ qcom,boot-option;
};
&pcie2 {
perst-gpio = <&tlmm 90 0>;
wake-gpio = <&tlmm 54 0>;
- /delete-property/ qcom,ep-wakeirq;
+ /delete-property/ qcom,boot-option;
};
&wsa881x_211 {
diff --git a/arch/arm/boot/dts/qcom/msm8996.dtsi b/arch/arm/boot/dts/qcom/msm8996.dtsi
index 7c0f8e3c331f..c73a2ff23369 100644
--- a/arch/arm/boot/dts/qcom/msm8996.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8996.dtsi
@@ -1371,7 +1371,7 @@
iommus = <&anoc0_smmu>;
- qcom,ep-wakeirq;
+ qcom,boot-option = <0x1>;
linux,pci-domain = <0>;
@@ -1524,7 +1524,7 @@
iommus = <&anoc0_smmu>;
- qcom,ep-wakeirq;
+ qcom,boot-option = <0x1>;
qcom,ep-latency = <10>;
@@ -1677,7 +1677,7 @@
iommus = <&anoc0_smmu>;
- qcom,ep-wakeirq;
+ qcom,boot-option = <0x1>;
qcom,ep-latency = <10>;
diff --git a/arch/arm/boot/dts/qcom/msm8998-interposer-sdm660.dtsi b/arch/arm/boot/dts/qcom/msm8998-interposer-sdm660.dtsi
index cfb71e3b1cb3..4a47942ce5dd 100644
--- a/arch/arm/boot/dts/qcom/msm8998-interposer-sdm660.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8998-interposer-sdm660.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
@@ -1590,7 +1590,7 @@
qcom,ep-latency = <10>;
- qcom,ep-wakeirq;
+ qcom,boot-option = <0x1>;
linux,pci-domain = <0>;
diff --git a/arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi b/arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi
index d2e18db982ef..220bad31d7f8 100644
--- a/arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi
@@ -1960,16 +1960,28 @@
led_enable: led_enable {
mux {
pins = "gpio21";
- drive_strength = <16>;
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio21";
+ drive_strength = <2>;
output-high;
+ bias-disable;
};
};
led_disable: led_disable {
mux {
pins = "gpio21";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio21";
drive_strength = <2>;
output-low;
+ bias-disable;
};
};
diff --git a/arch/arm/boot/dts/qcom/msm8998.dtsi b/arch/arm/boot/dts/qcom/msm8998.dtsi
index 02b7a44ee0d2..7a0ed2497a7e 100644
--- a/arch/arm/boot/dts/qcom/msm8998.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8998.dtsi
@@ -1575,6 +1575,8 @@
qcom,bus-bw-vectors-bps = <0 400000 20000000 25000000 50000000
100000000 200000000 4294967295>;
+ qcom,sdr104-wa;
+
status = "disabled";
};
@@ -2676,7 +2678,7 @@
qcom,ep-latency = <10>;
- qcom,ep-wakeirq;
+ qcom,boot-option = <0x1>;
linux,pci-domain = <0>;
diff --git a/arch/arm/boot/dts/qcom/sdm630-mdss.dtsi b/arch/arm/boot/dts/qcom/sdm630-mdss.dtsi
index 9ac76f7e2f6e..d35704224f45 100644
--- a/arch/arm/boot/dts/qcom/sdm630-mdss.dtsi
+++ b/arch/arm/boot/dts/qcom/sdm630-mdss.dtsi
@@ -38,8 +38,8 @@
qcom,mdss-ib-factor = <1 1>; /* 1 time */
qcom,mdss-clk-factor = <105 100>; /* 1.05 times */
- qcom,max-mixer-width = <2560>;
- qcom,max-pipe-width = <2560>;
+ qcom,max-mixer-width = <2048>;
+ qcom,max-pipe-width = <2048>;
qcom,max-dest-scaler-input-width = <2048>;
qcom,max-dest-scaler-output-width = <2560>;
diff --git a/arch/arm/boot/dts/qcom/sdm630.dtsi b/arch/arm/boot/dts/qcom/sdm630.dtsi
index 9626e0548789..67e899d8ba5e 100644
--- a/arch/arm/boot/dts/qcom/sdm630.dtsi
+++ b/arch/arm/boot/dts/qcom/sdm630.dtsi
@@ -1628,6 +1628,8 @@
reg-names = "membase", "smmu_iova_base", "smmu_iova_ipa";
iommus = <&anoc2_smmu 0x1a00>,
<&anoc2_smmu 0x1a01>;
+ clocks = <&clock_rpmcc RPM_RF_CLK1_PIN>;
+ clock-names = "cxo_ref_clk_pin";
interrupts = <0 413 0>, /* CE0 */
<0 414 0>, /* CE1 */
<0 415 0>, /* CE2 */
@@ -1640,6 +1642,14 @@
<0 423 0>, /* CE9 */
<0 424 0>, /* CE10 */
<0 425 0>; /* CE11 */
+ vdd-0.8-cx-mx-supply = <&pm660_l5>;
+ vdd-1.8-xo-supply = <&pm660_l9_pin_ctrl>;
+ vdd-1.3-rfa-supply = <&pm660_l6_pin_ctrl>;
+ vdd-3.3-ch0-supply = <&pm660_l19_pin_ctrl>;
+ qcom,vdd-0.8-cx-mx-config = <525000 950000>;
+ qcom,vdd-1.8-xo-config = <1750000 1900000>;
+ qcom,vdd-1.3-rfa-config = <1200000 1370000>;
+ qcom,vdd-3.3-ch0-config = <3200000 3400000>;
qcom,wlan-msa-memory = <0x100000>;
qcom,smmu-s1-bypass;
};
diff --git a/arch/arm/boot/dts/qcom/sdm660-pinctrl.dtsi b/arch/arm/boot/dts/qcom/sdm660-pinctrl.dtsi
index 37a88ea0dcec..efe58563a1f3 100644
--- a/arch/arm/boot/dts/qcom/sdm660-pinctrl.dtsi
+++ b/arch/arm/boot/dts/qcom/sdm660-pinctrl.dtsi
@@ -36,16 +36,28 @@
led_enable: led_enable {
mux {
pins = "gpio40";
- drive_strength = <16>;
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio40";
+ drive_strength = <2>;
output-high;
+ bias-disable;
};
};
led_disable: led_disable {
mux {
pins = "gpio40";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio40";
drive_strength = <2>;
output-low;
+ bias-disable;
};
};
diff --git a/arch/arm/boot/dts/qcom/sdm660.dtsi b/arch/arm/boot/dts/qcom/sdm660.dtsi
index 1e0b6136e1b4..be200f8dd531 100644
--- a/arch/arm/boot/dts/qcom/sdm660.dtsi
+++ b/arch/arm/boot/dts/qcom/sdm660.dtsi
@@ -1879,6 +1879,8 @@
reg-names = "membase", "smmu_iova_base", "smmu_iova_ipa";
iommus = <&anoc2_smmu 0x1a00>,
<&anoc2_smmu 0x1a01>;
+ clocks = <&clock_rpmcc RPM_RF_CLK1_PIN>;
+ clock-names = "cxo_ref_clk_pin";
interrupts = <0 413 0>, /* CE0 */
<0 414 0>, /* CE1 */
<0 415 0>, /* CE2 */
@@ -1891,6 +1893,14 @@
<0 423 0>, /* CE9 */
<0 424 0>, /* CE10 */
<0 425 0>; /* CE11 */
+ vdd-0.8-cx-mx-supply = <&pm660_l5>;
+ vdd-1.8-xo-supply = <&pm660_l9_pin_ctrl>;
+ vdd-1.3-rfa-supply = <&pm660_l6_pin_ctrl>;
+ vdd-3.3-ch0-supply = <&pm660_l19_pin_ctrl>;
+ qcom,vdd-0.8-cx-mx-config = <525000 950000>;
+ qcom,vdd-1.8-xo-config = <1750000 1900000>;
+ qcom,vdd-1.3-rfa-config = <1200000 1370000>;
+ qcom,vdd-3.3-ch0-config = <3200000 3400000>;
qcom,wlan-msa-memory = <0x100000>;
qcom,smmu-s1-bypass;
};
diff --git a/arch/arm64/configs/msmcortex-perf_defconfig b/arch/arm64/configs/msmcortex-perf_defconfig
index 94f9a8edfd12..4f55414454fc 100644
--- a/arch/arm64/configs/msmcortex-perf_defconfig
+++ b/arch/arm64/configs/msmcortex-perf_defconfig
@@ -273,9 +273,15 @@ CONFIG_SMSC911X=y
CONFIG_PPP=y
CONFIG_PPP_BSDCOMP=y
CONFIG_PPP_DEFLATE=y
+CONFIG_PPP_FILTER=y
CONFIG_PPP_MPPE=y
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPPOE=y
+CONFIG_PPPOL2TP=y
CONFIG_PPPOLAC=y
CONFIG_PPPOPNS=y
+CONFIG_PPP_ASYNC=y
+CONFIG_PPP_SYNC_TTY=y
CONFIG_USB_USBNET=y
CONFIG_WCNSS_MEM_PRE_ALLOC=y
CONFIG_ATH_CARDS=y
diff --git a/arch/arm64/configs/msmcortex_defconfig b/arch/arm64/configs/msmcortex_defconfig
index b86787f5f467..dc50257f5b7a 100644
--- a/arch/arm64/configs/msmcortex_defconfig
+++ b/arch/arm64/configs/msmcortex_defconfig
@@ -273,9 +273,15 @@ CONFIG_RNDIS_IPA=y
CONFIG_PPP=y
CONFIG_PPP_BSDCOMP=y
CONFIG_PPP_DEFLATE=y
+CONFIG_PPP_FILTER=y
CONFIG_PPP_MPPE=y
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPPOE=y
+CONFIG_PPPOL2TP=y
CONFIG_PPPOLAC=y
CONFIG_PPPOPNS=y
+CONFIG_PPP_ASYNC=y
+CONFIG_PPP_SYNC_TTY=y
CONFIG_USB_USBNET=y
CONFIG_WCNSS_MEM_PRE_ALLOC=y
CONFIG_ATH_CARDS=y
diff --git a/drivers/android/binder.c b/drivers/android/binder.c
index d0334e50f2f9..37b9eecf5c71 100644
--- a/drivers/android/binder.c
+++ b/drivers/android/binder.c
@@ -3440,7 +3440,7 @@ static int binder_mmap(struct file *filp, struct vm_area_struct *vma)
const char *failure_string;
struct binder_buffer *buffer;
- if (proc->tsk != current)
+ if (proc->tsk != current->group_leader)
return -EINVAL;
if ((vma->vm_end - vma->vm_start) > SZ_4M)
@@ -3546,8 +3546,8 @@ static int binder_open(struct inode *nodp, struct file *filp)
proc = kzalloc(sizeof(*proc), GFP_KERNEL);
if (proc == NULL)
return -ENOMEM;
- get_task_struct(current);
- proc->tsk = current;
+ get_task_struct(current->group_leader);
+ proc->tsk = current->group_leader;
INIT_LIST_HEAD(&proc->todo);
init_waitqueue_head(&proc->wait);
proc->default_priority = task_nice(current);
diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c
index 8dd03e6695cb..479599473381 100644
--- a/drivers/char/adsprpc.c
+++ b/drivers/char/adsprpc.c
@@ -553,7 +553,7 @@ static void fastrpc_mmap_free(struct fastrpc_mmap *map)
if (!IS_ERR_OR_NULL(map->handle))
ion_free(fl->apps->client, map->handle);
- if (sess->smmu.enabled) {
+ if (sess && sess->smmu.enabled) {
if (map->size || map->phys)
msm_dma_unmap_sg(sess->smmu.dev,
map->table->sgl,
@@ -645,6 +645,9 @@ static int fastrpc_mmap_create(struct fastrpc_file *fl, int fd, unsigned attr,
else
sess = fl->sctx;
+ VERIFY(err, !IS_ERR_OR_NULL(sess));
+ if (err)
+ goto bail;
VERIFY(err, !IS_ERR_OR_NULL(map->buf = dma_buf_get(fd)));
if (err)
goto bail;
diff --git a/drivers/clk/msm/mdss/mdss-dsi-pll-8998.c b/drivers/clk/msm/mdss/mdss-dsi-pll-8998.c
index e51cd437cf7c..eb69ed35f46d 100644
--- a/drivers/clk/msm/mdss/mdss-dsi-pll-8998.c
+++ b/drivers/clk/msm/mdss/mdss-dsi-pll-8998.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -38,41 +38,76 @@
/* Register Offsets from PLL base address */
#define PLL_ANALOG_CONTROLS_ONE 0x000
#define PLL_ANALOG_CONTROLS_TWO 0x004
+#define PLL_INT_LOOP_SETTINGS 0x008
+#define PLL_INT_LOOP_SETTINGS_TWO 0x00c
#define PLL_ANALOG_CONTROLS_THREE 0x010
-#define PLL_DSM_DIVIDER 0x01c
+#define PLL_ANALOG_CONTROLS_FOUR 0x014
+#define PLL_INT_LOOP_CONTROLS 0x018
+#define PLL_DSM_DIVIDER 0x01c
#define PLL_FEEDBACK_DIVIDER 0x020
#define PLL_SYSTEM_MUXES 0x024
+#define PLL_FREQ_UPDATE_CONTROL_OVERRIDES 0x028
#define PLL_CMODE 0x02c
#define PLL_CALIBRATION_SETTINGS 0x030
+#define PLL_BAND_SEL_CAL_TIMER_LOW 0x034
+#define PLL_BAND_SEL_CAL_TIMER_HIGH 0x038
+#define PLL_BAND_SEL_CAL_SETTINGS 0x03c
+#define PLL_BAND_SEL_MIN 0x040
+#define PLL_BAND_SEL_MAX 0x044
+#define PLL_BAND_SEL_PFILT 0x048
+#define PLL_BAND_SEL_IFILT 0x04c
+#define PLL_BAND_SEL_CAL_SETTINGS_TWO 0x050
#define PLL_BAND_SEL_CAL_SETTINGS_THREE 0x054
+#define PLL_BAND_SEL_CAL_SETTINGS_FOUR 0x058
+#define PLL_BAND_SEL_ICODE_HIGH 0x05c
+#define PLL_BAND_SEL_ICODE_LOW 0x060
#define PLL_FREQ_DETECT_SETTINGS_ONE 0x064
#define PLL_PFILT 0x07c
#define PLL_IFILT 0x080
+#define PLL_GAIN 0x084
+#define PLL_ICODE_LOW 0x088
+#define PLL_ICODE_HIGH 0x08c
+#define PLL_LOCKDET 0x090
#define PLL_OUTDIV 0x094
-#define PLL_CORE_OVERRIDE 0x0a4
+#define PLL_FASTLOCK_CONTROL 0x098
+#define PLL_PASS_OUT_OVERRIDE_ONE 0x09c
+#define PLL_PASS_OUT_OVERRIDE_TWO 0x0a0
+#define PLL_CORE_OVERRIDE 0x0a4
#define PLL_CORE_INPUT_OVERRIDE 0x0a8
+#define PLL_RATE_CHANGE 0x0ac
+#define PLL_PLL_DIGITAL_TIMERS 0x0b0
#define PLL_PLL_DIGITAL_TIMERS_TWO 0x0b4
+#define PLL_DEC_FRAC_MUXES 0x0c8
#define PLL_DECIMAL_DIV_START_1 0x0cc
#define PLL_FRAC_DIV_START_LOW_1 0x0d0
#define PLL_FRAC_DIV_START_MID_1 0x0d4
#define PLL_FRAC_DIV_START_HIGH_1 0x0d8
+#define PLL_MASH_CONTROL 0x0ec
+#define PLL_SSC_MUX_CONTROL 0x108
#define PLL_SSC_STEPSIZE_LOW_1 0x10c
#define PLL_SSC_STEPSIZE_HIGH_1 0x110
#define PLL_SSC_DIV_PER_LOW_1 0x114
#define PLL_SSC_DIV_PER_HIGH_1 0x118
#define PLL_SSC_DIV_ADJPER_LOW_1 0x11c
#define PLL_SSC_DIV_ADJPER_HIGH_1 0x120
-#define PLL_SSC_CONTROL 0x13c
-#define PLL_PLL_OUTDIV_RATE 0x140
+#define PLL_SSC_CONTROL 0x13c
+#define PLL_PLL_OUTDIV_RATE 0x140
#define PLL_PLL_LOCKDET_RATE_1 0x144
#define PLL_PLL_PROP_GAIN_RATE_1 0x14c
#define PLL_PLL_BAND_SET_RATE_1 0x154
#define PLL_PLL_INT_GAIN_IFILT_BAND_1 0x15c
#define PLL_PLL_FL_INT_GAIN_PFILT_BAND_1 0x164
-#define PLL_PLL_LOCK_OVERRIDE 0x180
-#define PLL_PLL_LOCK_DELAY 0x184
-#define PLL_CLOCK_INVERTERS 0x18c
-#define PLL_COMMON_STATUS_ONE 0x1a0
+#define PLL_FASTLOCK_EN_BAND 0x16c
+#define PLL_FREQ_TUNE_ACCUM_INIT_MUX 0x17c
+#define PLL_PLL_LOCK_OVERRIDE 0x180
+#define PLL_PLL_LOCK_DELAY 0x184
+#define PLL_PLL_LOCK_MIN_DELAY 0x188
+#define PLL_CLOCK_INVERTERS 0x18c
+#define PLL_SPARE_AND_JPC_OVERRIDES 0x190
+#define PLL_BIAS_CONTROL_1 0x194
+#define PLL_BIAS_CONTROL_2 0x198
+#define PLL_ALOG_OBSV_BUS_CTRL_1 0x19c
+#define PLL_COMMON_STATUS_ONE 0x1a0
/* Register Offsets from PHY base address */
#define PHY_CMN_CLK_CFG0 0x010
@@ -384,6 +419,49 @@ static void dsi_pll_config_hzindep_reg(struct dsi_pll_8998 *pll,
MDSS_PLL_REG_W(pll_base, PLL_IFILT, 0x3f);
}
+static void dsi_pll_init_val(struct mdss_pll_resources *rsc)
+{
+ void __iomem *pll_base = rsc->pll_base;
+
+ MDSS_PLL_REG_W(pll_base, PLL_CORE_INPUT_OVERRIDE, 0x10);
+ MDSS_PLL_REG_W(pll_base, PLL_INT_LOOP_SETTINGS, 0x3f);
+ MDSS_PLL_REG_W(pll_base, PLL_INT_LOOP_SETTINGS_TWO, 0x0);
+ MDSS_PLL_REG_W(pll_base, PLL_ANALOG_CONTROLS_FOUR, 0x0);
+ MDSS_PLL_REG_W(pll_base, PLL_INT_LOOP_CONTROLS, 0x80);
+ MDSS_PLL_REG_W(pll_base, PLL_FREQ_UPDATE_CONTROL_OVERRIDES, 0x0);
+ MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_CAL_TIMER_LOW, 0x0);
+ MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_CAL_TIMER_HIGH, 0x02);
+ MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_CAL_SETTINGS, 0x82);
+ MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_MIN, 0x00);
+ MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_MAX, 0xff);
+ MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_PFILT, 0x00);
+ MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_IFILT, 0x00);
+ MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_CAL_SETTINGS_TWO, 0x25);
+ MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_CAL_SETTINGS_FOUR, 0x4f);
+ MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_ICODE_HIGH, 0x0a);
+ MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_ICODE_LOW, 0x0);
+ MDSS_PLL_REG_W(pll_base, PLL_GAIN, 0x42);
+ MDSS_PLL_REG_W(pll_base, PLL_ICODE_LOW, 0x00);
+ MDSS_PLL_REG_W(pll_base, PLL_ICODE_HIGH, 0x00);
+ MDSS_PLL_REG_W(pll_base, PLL_LOCKDET, 0x30);
+ MDSS_PLL_REG_W(pll_base, PLL_FASTLOCK_CONTROL, 0x04);
+ MDSS_PLL_REG_W(pll_base, PLL_PASS_OUT_OVERRIDE_ONE, 0x00);
+ MDSS_PLL_REG_W(pll_base, PLL_PASS_OUT_OVERRIDE_TWO, 0x00);
+ MDSS_PLL_REG_W(pll_base, PLL_RATE_CHANGE, 0x01);
+ MDSS_PLL_REG_W(pll_base, PLL_PLL_DIGITAL_TIMERS, 0x08);
+ MDSS_PLL_REG_W(pll_base, PLL_DEC_FRAC_MUXES, 0x00);
+ MDSS_PLL_REG_W(pll_base, PLL_MASH_CONTROL, 0x03);
+ MDSS_PLL_REG_W(pll_base, PLL_SSC_MUX_CONTROL, 0x0);
+ MDSS_PLL_REG_W(pll_base, PLL_SSC_CONTROL, 0x0);
+ MDSS_PLL_REG_W(pll_base, PLL_FASTLOCK_EN_BAND, 0x03);
+ MDSS_PLL_REG_W(pll_base, PLL_FREQ_TUNE_ACCUM_INIT_MUX, 0x0);
+ MDSS_PLL_REG_W(pll_base, PLL_PLL_LOCK_MIN_DELAY, 0x19);
+ MDSS_PLL_REG_W(pll_base, PLL_SPARE_AND_JPC_OVERRIDES, 0x0);
+ MDSS_PLL_REG_W(pll_base, PLL_BIAS_CONTROL_1, 0x40);
+ MDSS_PLL_REG_W(pll_base, PLL_BIAS_CONTROL_2, 0x20);
+ MDSS_PLL_REG_W(pll_base, PLL_ALOG_OBSV_BUS_CTRL_1, 0x0);
+}
+
static void dsi_pll_commit(struct dsi_pll_8998 *pll,
struct mdss_pll_resources *rsc)
{
@@ -440,6 +518,8 @@ static int vco_8998_set_rate(struct clk *c, unsigned long rate)
return rc;
}
+ dsi_pll_init_val(rsc);
+
dsi_pll_setup_config(pll, rsc);
dsi_pll_calc_dec_frac(pll, rsc);
@@ -554,7 +634,6 @@ error:
static void dsi_pll_disable_sub(struct mdss_pll_resources *rsc)
{
- dsi_pll_disable_global_clk(rsc);
MDSS_PLL_REG_W(rsc->phy_base, PHY_CMN_RBUF_CTRL, 0);
dsi_pll_disable_pll_bias(rsc);
}
@@ -573,11 +652,20 @@ static void dsi_pll_disable(struct dsi_pll_vco_clk *vco)
pr_debug("stop PLL (%d)\n", rsc->index);
+ /*
+ * To avoid any stray glitches while
+ * abruptly powering down the PLL
+ * make sure to gate the clock using
+ * the clock enable bit before powering
+ * down the PLL
+ **/
+ dsi_pll_disable_global_clk(rsc);
MDSS_PLL_REG_W(rsc->phy_base, PHY_CMN_PLL_CNTRL, 0);
dsi_pll_disable_sub(rsc);
- if (rsc->slave)
+ if (rsc->slave) {
+ dsi_pll_disable_global_clk(rsc->slave);
dsi_pll_disable_sub(rsc->slave);
-
+ }
/* flush, ensure all register writes are done*/
wmb();
rsc->pll_on = false;
diff --git a/drivers/crypto/msm/ice.c b/drivers/crypto/msm/ice.c
index ab21334d5813..4002a5b57250 100644
--- a/drivers/crypto/msm/ice.c
+++ b/drivers/crypto/msm/ice.c
@@ -1608,7 +1608,8 @@ static struct ice_device *get_ice_device_from_storage_type
list_for_each_entry(ice_dev, &ice_devices, list) {
if (!strcmp(ice_dev->ice_instance_type, storage_type)) {
- pr_info("%s: found ice device %p\n", __func__, ice_dev);
+ pr_debug("%s: found ice device %pK\n",
+ __func__, ice_dev);
break;
}
}
diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c
index 161b718b8a38..d79d9613043f 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.c
+++ b/drivers/gpu/msm/adreno_ringbuffer.c
@@ -813,10 +813,10 @@ int adreno_ringbuffer_submitcmd(struct adreno_device *adreno_dev,
dwords += 6;
/*
- * REG_TO_MEM packet on A5xx needs another ordinal.
+ * REG_TO_MEM packet on A5xx and above needs another ordinal.
* Add 2 more dwords since we do profiling before and after.
*/
- if (adreno_is_a5xx(adreno_dev))
+ if (!ADRENO_LEGACY_PM4(adreno_dev))
dwords += 2;
/*
@@ -833,7 +833,7 @@ int adreno_ringbuffer_submitcmd(struct adreno_device *adreno_dev,
if (test_bit(CMDOBJ_PROFILE, &cmdobj->priv)) {
kernel_profiling = true;
dwords += 6;
- if (adreno_is_a5xx(adreno_dev))
+ if (!ADRENO_LEGACY_PM4(adreno_dev))
dwords += 2;
}
diff --git a/drivers/leds/leds-qpnp-flash-v2.c b/drivers/leds/leds-qpnp-flash-v2.c
index 54d395d5e78d..4c28e0922c84 100644
--- a/drivers/leds/leds-qpnp-flash-v2.c
+++ b/drivers/leds/leds-qpnp-flash-v2.c
@@ -175,9 +175,7 @@ enum {
struct flash_node_data {
struct platform_device *pdev;
struct led_classdev cdev;
- struct pinctrl *pinctrl;
- struct pinctrl_state *gpio_state_active;
- struct pinctrl_state *gpio_state_suspend;
+ struct pinctrl *strobe_pinctrl;
struct pinctrl_state *hw_strobe_state_active;
struct pinctrl_state *hw_strobe_state_suspend;
int hw_strobe_gpio;
@@ -198,6 +196,9 @@ struct flash_node_data {
struct flash_switch_data {
struct platform_device *pdev;
struct regulator *vreg;
+ struct pinctrl *led_en_pinctrl;
+ struct pinctrl_state *gpio_state_active;
+ struct pinctrl_state *gpio_state_suspend;
struct led_classdev cdev;
int led_mask;
bool regulator_on;
@@ -509,7 +510,7 @@ static int qpnp_flash_led_init_settings(struct qpnp_flash_led *led)
if (led->pdata->led1n2_iclamp_low_ma) {
val = CURRENT_MA_TO_REG_VAL(led->pdata->led1n2_iclamp_low_ma,
- led->fnode[0].ires_ua);
+ led->fnode[LED1].ires_ua);
rc = qpnp_flash_led_masked_write(led,
FLASH_LED_REG_LED1N2_ICLAMP_LOW(led->base),
FLASH_LED_CURRENT_MASK, val);
@@ -519,7 +520,7 @@ static int qpnp_flash_led_init_settings(struct qpnp_flash_led *led)
if (led->pdata->led1n2_iclamp_mid_ma) {
val = CURRENT_MA_TO_REG_VAL(led->pdata->led1n2_iclamp_mid_ma,
- led->fnode[0].ires_ua);
+ led->fnode[LED1].ires_ua);
rc = qpnp_flash_led_masked_write(led,
FLASH_LED_REG_LED1N2_ICLAMP_MID(led->base),
FLASH_LED_CURRENT_MASK, val);
@@ -529,7 +530,7 @@ static int qpnp_flash_led_init_settings(struct qpnp_flash_led *led)
if (led->pdata->led3_iclamp_low_ma) {
val = CURRENT_MA_TO_REG_VAL(led->pdata->led3_iclamp_low_ma,
- led->fnode[3].ires_ua);
+ led->fnode[LED3].ires_ua);
rc = qpnp_flash_led_masked_write(led,
FLASH_LED_REG_LED3_ICLAMP_LOW(led->base),
FLASH_LED_CURRENT_MASK, val);
@@ -539,7 +540,7 @@ static int qpnp_flash_led_init_settings(struct qpnp_flash_led *led)
if (led->pdata->led3_iclamp_mid_ma) {
val = CURRENT_MA_TO_REG_VAL(led->pdata->led3_iclamp_mid_ma,
- led->fnode[3].ires_ua);
+ led->fnode[LED3].ires_ua);
rc = qpnp_flash_led_masked_write(led,
FLASH_LED_REG_LED3_ICLAMP_MID(led->base),
FLASH_LED_CURRENT_MASK, val);
@@ -570,9 +571,9 @@ static int qpnp_flash_led_hw_strobe_enable(struct flash_node_data *fnode,
if (gpio_is_valid(fnode->hw_strobe_gpio)) {
gpio_set_value(fnode->hw_strobe_gpio, on ? 1 : 0);
- } else if (fnode->hw_strobe_state_active &&
+ } else if (fnode->strobe_pinctrl && fnode->hw_strobe_state_active &&
fnode->hw_strobe_state_suspend) {
- rc = pinctrl_select_state(fnode->pinctrl,
+ rc = pinctrl_select_state(fnode->strobe_pinctrl,
on ? fnode->hw_strobe_state_active :
fnode->hw_strobe_state_suspend);
if (rc < 0) {
@@ -948,15 +949,6 @@ static int qpnp_flash_led_switch_disable(struct flash_switch_data *snode)
led->fnode[i].led_on = false;
- if (led->fnode[i].pinctrl) {
- rc = pinctrl_select_state(led->fnode[i].pinctrl,
- led->fnode[i].gpio_state_suspend);
- if (rc < 0) {
- pr_err("failed to disable GPIO, rc=%d\n", rc);
- return rc;
- }
- }
-
if (led->fnode[i].trigger & FLASH_LED_HW_SW_STROBE_SEL_BIT) {
rc = qpnp_flash_led_hw_strobe_enable(&led->fnode[i],
led->pdata->hw_strobe_option, false);
@@ -968,6 +960,17 @@ static int qpnp_flash_led_switch_disable(struct flash_switch_data *snode)
}
}
+ if (snode->led_en_pinctrl) {
+ pr_debug("Selecting suspend state for %s\n", snode->cdev.name);
+ rc = pinctrl_select_state(snode->led_en_pinctrl,
+ snode->gpio_state_suspend);
+ if (rc < 0) {
+ pr_err("failed to select pinctrl suspend state rc=%d\n",
+ rc);
+ return rc;
+ }
+ }
+
snode->enabled = false;
return 0;
}
@@ -1038,15 +1041,6 @@ static int qpnp_flash_led_switch_set(struct flash_switch_data *snode, bool on)
val |= FLASH_LED_ENABLE << led->fnode[i].id;
- if (led->fnode[i].pinctrl) {
- rc = pinctrl_select_state(led->fnode[i].pinctrl,
- led->fnode[i].gpio_state_active);
- if (rc < 0) {
- pr_err("failed to enable GPIO rc=%d\n", rc);
- return rc;
- }
- }
-
if (led->fnode[i].trigger & FLASH_LED_HW_SW_STROBE_SEL_BIT) {
rc = qpnp_flash_led_hw_strobe_enable(&led->fnode[i],
led->pdata->hw_strobe_option, true);
@@ -1058,6 +1052,17 @@ static int qpnp_flash_led_switch_set(struct flash_switch_data *snode, bool on)
}
}
+ if (snode->led_en_pinctrl) {
+ pr_debug("Selecting active state for %s\n", snode->cdev.name);
+ rc = pinctrl_select_state(snode->led_en_pinctrl,
+ snode->gpio_state_active);
+ if (rc < 0) {
+ pr_err("failed to select pinctrl active state rc=%d\n",
+ rc);
+ return rc;
+ }
+ }
+
if (led->enable == 0) {
rc = qpnp_flash_led_masked_write(led,
FLASH_LED_REG_MOD_CTRL(led->base),
@@ -1460,6 +1465,20 @@ static int qpnp_flash_led_parse_each_led_dt(struct qpnp_flash_led *led,
}
fnode->trigger = (strobe_sel << 2) | (edge_trigger << 1) | active_high;
+ rc = led_classdev_register(&led->pdev->dev, &fnode->cdev);
+ if (rc < 0) {
+ pr_err("Unable to register led node %d\n", fnode->id);
+ return rc;
+ }
+
+ fnode->cdev.dev->of_node = node;
+ fnode->strobe_pinctrl = devm_pinctrl_get(fnode->cdev.dev);
+ if (IS_ERR_OR_NULL(fnode->strobe_pinctrl)) {
+ pr_debug("No pinctrl defined for %s, err=%ld\n",
+ fnode->cdev.name, PTR_ERR(fnode->strobe_pinctrl));
+ fnode->strobe_pinctrl = NULL;
+ }
+
if (fnode->trigger & FLASH_LED_HW_SW_STROBE_SEL_BIT) {
if (of_find_property(node, "qcom,hw-strobe-gpio", NULL)) {
fnode->hw_strobe_gpio = of_get_named_gpio(node,
@@ -1469,11 +1488,11 @@ static int qpnp_flash_led_parse_each_led_dt(struct qpnp_flash_led *led,
return fnode->hw_strobe_gpio;
}
gpio_direction_output(fnode->hw_strobe_gpio, 0);
- } else {
+ } else if (fnode->strobe_pinctrl) {
fnode->hw_strobe_gpio = -1;
fnode->hw_strobe_state_active =
- pinctrl_lookup_state(fnode->pinctrl,
- "strobe_enable");
+ pinctrl_lookup_state(fnode->strobe_pinctrl,
+ "strobe_enable");
if (IS_ERR_OR_NULL(fnode->hw_strobe_state_active)) {
pr_err("No active pin for hardware strobe, rc=%ld\n",
PTR_ERR(fnode->hw_strobe_state_active));
@@ -1481,8 +1500,8 @@ static int qpnp_flash_led_parse_each_led_dt(struct qpnp_flash_led *led,
}
fnode->hw_strobe_state_suspend =
- pinctrl_lookup_state(fnode->pinctrl,
- "strobe_disable");
+ pinctrl_lookup_state(fnode->strobe_pinctrl,
+ "strobe_disable");
if (IS_ERR_OR_NULL(fnode->hw_strobe_state_suspend)) {
pr_err("No suspend pin for hardware strobe, rc=%ld\n",
PTR_ERR(fnode->hw_strobe_state_suspend)
@@ -1492,38 +1511,6 @@ static int qpnp_flash_led_parse_each_led_dt(struct qpnp_flash_led *led,
}
}
- rc = led_classdev_register(&led->pdev->dev, &fnode->cdev);
- if (rc < 0) {
- pr_err("Unable to register led node %d\n", fnode->id);
- return rc;
- }
-
- fnode->cdev.dev->of_node = node;
-
- fnode->pinctrl = devm_pinctrl_get(fnode->cdev.dev);
- if (IS_ERR_OR_NULL(fnode->pinctrl)) {
- pr_debug("No pinctrl defined\n");
- fnode->pinctrl = NULL;
- } else {
- fnode->gpio_state_active =
- pinctrl_lookup_state(fnode->pinctrl, "led_enable");
- if (IS_ERR_OR_NULL(fnode->gpio_state_active)) {
- pr_err("Cannot lookup LED active state\n");
- devm_pinctrl_put(fnode->pinctrl);
- fnode->pinctrl = NULL;
- return PTR_ERR(fnode->gpio_state_active);
- }
-
- fnode->gpio_state_suspend =
- pinctrl_lookup_state(fnode->pinctrl, "led_disable");
- if (IS_ERR_OR_NULL(fnode->gpio_state_suspend)) {
- pr_err("Cannot lookup LED disable state\n");
- devm_pinctrl_put(fnode->pinctrl);
- fnode->pinctrl = NULL;
- return PTR_ERR(fnode->gpio_state_suspend);
- }
- }
-
return 0;
}
@@ -1588,6 +1575,36 @@ static int qpnp_flash_led_parse_and_register_switch(struct qpnp_flash_led *led,
}
snode->cdev.dev->of_node = node;
+
+ snode->led_en_pinctrl = devm_pinctrl_get(snode->cdev.dev);
+ if (IS_ERR_OR_NULL(snode->led_en_pinctrl)) {
+ pr_debug("No pinctrl defined for %s, err=%ld\n",
+ snode->cdev.name, PTR_ERR(snode->led_en_pinctrl));
+ snode->led_en_pinctrl = NULL;
+ }
+
+ if (snode->led_en_pinctrl) {
+ snode->gpio_state_active =
+ pinctrl_lookup_state(snode->led_en_pinctrl,
+ "led_enable");
+ if (IS_ERR_OR_NULL(snode->gpio_state_active)) {
+ pr_err("Cannot lookup LED active state\n");
+ devm_pinctrl_put(snode->led_en_pinctrl);
+ snode->led_en_pinctrl = NULL;
+ return PTR_ERR(snode->gpio_state_active);
+ }
+
+ snode->gpio_state_suspend =
+ pinctrl_lookup_state(snode->led_en_pinctrl,
+ "led_disable");
+ if (IS_ERR_OR_NULL(snode->gpio_state_suspend)) {
+ pr_err("Cannot lookup LED disable state\n");
+ devm_pinctrl_put(snode->led_en_pinctrl);
+ snode->led_en_pinctrl = NULL;
+ return PTR_ERR(snode->gpio_state_suspend);
+ }
+ }
+
return 0;
}
@@ -2094,22 +2111,24 @@ static int qpnp_flash_led_probe(struct platform_device *pdev)
if (!strcmp("flash", temp_string) ||
!strcmp("torch", temp_string)) {
rc = qpnp_flash_led_parse_each_led_dt(led,
- &led->fnode[i++], temp);
+ &led->fnode[i], temp);
if (rc < 0) {
pr_err("Unable to parse flash node %d rc=%d\n",
i, rc);
goto error_led_register;
}
+ i++;
}
if (!strcmp("switch", temp_string)) {
rc = qpnp_flash_led_parse_and_register_switch(led,
- &led->snode[j++], temp);
+ &led->snode[j], temp);
if (rc < 0) {
pr_err("Unable to parse and register switch node, rc=%d\n",
rc);
goto error_switch_register;
}
+ j++;
}
}
diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c
index 24eb8fff905b..953780e3c220 100644
--- a/drivers/media/platform/msm/vidc/msm_vdec.c
+++ b/drivers/media/platform/msm/vidc/msm_vdec.c
@@ -2587,6 +2587,12 @@ static int try_set_ext_ctrl(struct msm_vidc_inst *inst,
int rc = 0, i = 0, fourcc = 0;
struct v4l2_ext_control *ext_control;
struct v4l2_control control;
+ u32 old_mode = 0;
+ bool mode_changed = false;
+ enum mode {
+ PRIMARY = V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_PRIMARY,
+ SECONDARY = V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_SECONDARY
+ };
if (!inst || !inst->core || !ctrl) {
dprintk(VIDC_ERR,
@@ -2595,19 +2601,21 @@ static int try_set_ext_ctrl(struct msm_vidc_inst *inst,
}
ext_control = ctrl->controls;
- control.id =
- V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_MODE;
+ control.id = V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_MODE;
+ old_mode = msm_comm_g_ctrl_for_id(inst, control.id);
for (i = 0; i < ctrl->count; i++) {
switch (ext_control[i].id) {
case V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_MODE:
control.value = ext_control[i].value;
-
rc = msm_comm_s_ctrl(inst, &control);
if (rc)
dprintk(VIDC_ERR,
"%s Failed setting stream output mode : %d\n",
__func__, rc);
+
+ if (old_mode == SECONDARY && control.value == PRIMARY)
+ mode_changed = true;
break;
case V4L2_CID_MPEG_VIDC_VIDEO_DPB_COLOR_FORMAT:
switch (ext_control[i].value) {
@@ -2620,6 +2628,24 @@ static int try_set_ext_ctrl(struct msm_vidc_inst *inst,
"%s Release output buffers failed\n",
__func__);
}
+ /* Update buffer reqmt for split to comb mode */
+ if (mode_changed) {
+ fourcc =
+ inst->fmts[CAPTURE_PORT].fourcc;
+ msm_comm_set_color_format(inst,
+ HAL_BUFFER_OUTPUT, fourcc);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "%s Failed setting output color format : %d\n",
+ __func__, rc);
+ break;
+ }
+ rc = msm_comm_try_get_bufreqs(inst);
+ if (rc)
+ dprintk(VIDC_ERR,
+ "%s Failed to get buffer requirements : %d\n",
+ __func__, rc);
+ }
break;
case V4L2_MPEG_VIDC_VIDEO_DPB_COLOR_FMT_UBWC:
case V4L2_MPEG_VIDC_VIDEO_DPB_COLOR_FMT_TP10_UBWC:
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index 8b459e4da618..7b28e80979f2 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -902,7 +902,7 @@ static int wait_for_sess_signal_receipt(struct msm_vidc_inst *inst,
dprintk(VIDC_ERR,
"sess resp timeout can potentially crash the system\n");
msm_comm_print_debug_info(inst);
- BUG_ON(inst->core->resources.debug_timeout);
+ BUG_ON(msm_vidc_debug_timeout);
msm_comm_kill_session(inst);
rc = -EIO;
} else {
@@ -1748,7 +1748,7 @@ static void handle_sys_error(enum hal_command_response cmd, void *data)
msm_comm_print_inst_info(inst);
mutex_unlock(&core->lock);
- BUG_ON(core->resources.debug_timeout);
+ BUG_ON(msm_vidc_debug_timeout);
}
void msm_comm_session_clean(struct msm_vidc_inst *inst)
@@ -2543,7 +2543,7 @@ static int msm_comm_session_abort(struct msm_vidc_inst *inst)
"ABORT timeout can potentially crash the system\n");
msm_comm_print_debug_info(inst);
- BUG_ON(inst->core->resources.debug_timeout);
+ BUG_ON(msm_vidc_debug_timeout);
rc = -EBUSY;
} else {
rc = 0;
@@ -2645,7 +2645,7 @@ int msm_comm_check_core_init(struct msm_vidc_core *core)
msm_comm_print_debug_info(inst);
mutex_lock(&core->lock);
- BUG_ON(core->resources.debug_timeout);
+ BUG_ON(msm_vidc_debug_timeout);
rc = -EIO;
goto exit;
} else {
@@ -4110,10 +4110,9 @@ int msm_comm_try_get_prop(struct msm_vidc_inst *inst, enum hal_property ptype,
call_hfi_op(hdev, flush_debug_queue, hdev->hfi_device_data);
dprintk(VIDC_ERR,
"SESS_PROP timeout can potentially crash the system\n");
- if (inst->core->resources.debug_timeout)
- msm_comm_print_debug_info(inst);
+ msm_comm_print_debug_info(inst);
- BUG_ON(inst->core->resources.debug_timeout);
+ BUG_ON(msm_vidc_debug_timeout);
msm_comm_kill_session(inst);
rc = -ETIMEDOUT;
goto exit;
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c
index a65e22c66e30..4cc977e568ee 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c
@@ -1123,7 +1123,7 @@ int read_platform_resources_from_dt(
res->debug_timeout = of_property_read_bool(pdev->dev.of_node,
"qcom,debug-timeout");
- res->debug_timeout |= msm_vidc_debug_timeout;
+ msm_vidc_debug_timeout |= res->debug_timeout;
of_property_read_u32(pdev->dev.of_node,
"qcom,pm-qos-latency-us", &res->pm_qos_latency_us);
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 5d6c44b00bc2..e9f1a19dfe3f 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -2189,6 +2189,17 @@ static int mmc_blk_err_check(struct mmc_card *card,
int need_retune = card->host->need_retune;
int ecc_err = 0, gen_err = 0;
+ if (card->host->sdr104_wa && mmc_card_sd(card) &&
+ (card->host->ios.timing == MMC_TIMING_UHS_SDR104) &&
+ !card->sdr104_blocked &&
+ (brq->data.error == -EILSEQ ||
+ brq->data.error == -EIO ||
+ brq->data.error == -ETIMEDOUT ||
+ brq->cmd.error == -EILSEQ ||
+ brq->cmd.error == -EIO ||
+ brq->cmd.error == -ETIMEDOUT))
+ card->err_in_sdr104 = true;
+
/*
* sbc.error indicates a problem with the set block count
* command. No data will have been transferred.
@@ -3645,6 +3656,7 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
struct mmc_async_req *areq;
const u8 packed_nr = 2;
u8 reqs = 0;
+ bool reset = false;
#ifdef CONFIG_MMC_SIMULATE_MAX_SPEED
unsigned long waitfor = jiffies;
#endif
@@ -3690,6 +3702,26 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
type = rq_data_dir(req) == READ ? MMC_BLK_READ : MMC_BLK_WRITE;
mmc_queue_bounce_post(mq_rq);
+ if (card->err_in_sdr104) {
+ /*
+ * Data CRC/timeout errors will manifest as CMD/DATA
+ * ERR. But we'd like to retry these too.
+ * Moreover, no harm done if this fails too for multiple
+ * times, we anyway reduce the bus-speed and retry the
+ * same request.
+ * If that fails too, we don't override this status.
+ */
+ if (status == MMC_BLK_ABORT ||
+ status == MMC_BLK_CMD_ERR ||
+ status == MMC_BLK_DATA_ERR ||
+ status == MMC_BLK_RETRY)
+ /* reset on all of these errors and retry */
+ reset = true;
+
+ status = MMC_BLK_RETRY;
+ card->err_in_sdr104 = false;
+ }
+
switch (status) {
case MMC_BLK_SUCCESS:
case MMC_BLK_PARTIAL:
@@ -3730,8 +3762,32 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
break;
case MMC_BLK_RETRY:
retune_retry_done = brq->retune_retry_done;
- if (retry++ < MMC_BLK_MAX_RETRIES)
+ if (retry++ < MMC_BLK_MAX_RETRIES) {
break;
+ } else if (reset) {
+ reset = false;
+ /*
+ * If we exhaust all the retries due to
+ * CRC/timeout errors in SDR140 mode with UHS SD
+ * cards, re-configure the card in SDR50
+ * bus-speed mode.
+ * All subsequent re-init of this card will be
+ * in SDR50 mode, unless it is removed and
+ * re-inserted. When new UHS SD cards are
+ * inserted, it may start at SDR104 mode if
+ * supported by the card.
+ */
+ pr_err("%s: blocked SDR104, lower the bus-speed (SDR50 / DDR50)\n",
+ req->rq_disk->disk_name);
+ mmc_host_clear_sdr104(card->host);
+ mmc_suspend_clk_scaling(card->host);
+ mmc_blk_reset(md, card->host, type);
+ /* SDR104 mode is blocked from now on */
+ card->sdr104_blocked = true;
+ /* retry 5 times again */
+ retry = 0;
+ break;
+ }
/* Fall through */
case MMC_BLK_ABORT:
if (!mmc_blk_reset(md, card->host, type) &&
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index c409f713d4f0..41f0935440fd 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -4040,6 +4040,10 @@ int _mmc_detect_card_removed(struct mmc_host *host)
if (ret) {
mmc_card_set_removed(host->card);
+ if (host->card->sdr104_blocked) {
+ mmc_host_set_sdr104(host);
+ host->card->sdr104_blocked = false;
+ }
pr_debug("%s: card remove detected\n", mmc_hostname(host));
}
diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h
index 1116544eebc1..c66187299598 100644
--- a/drivers/mmc/core/core.h
+++ b/drivers/mmc/core/core.h
@@ -80,7 +80,6 @@ void mmc_init_context_info(struct mmc_host *host);
extern bool mmc_can_scale_clk(struct mmc_host *host);
extern int mmc_init_clk_scaling(struct mmc_host *host);
-extern int mmc_suspend_clk_scaling(struct mmc_host *host);
extern int mmc_resume_clk_scaling(struct mmc_host *host);
extern int mmc_exit_clk_scaling(struct mmc_host *host);
extern unsigned long mmc_get_max_frequency(struct mmc_host *host);
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index 9e147a667edf..5b4d5d74fe55 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -1285,6 +1285,8 @@ static int _mmc_sd_resume(struct mmc_host *host)
#endif
mmc_card_clr_suspended(host->card);
+ if (host->card->sdr104_blocked)
+ goto out;
err = mmc_resume_clk_scaling(host);
if (err) {
pr_err("%s: %s: fail to resume clock scaling (%d)\n",
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index 2eaac11ec8ba..987d61bdda2d 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -1960,6 +1960,8 @@ struct sdhci_msm_pltfm_data *sdhci_msm_populate_pdata(struct device *dev,
if (of_get_property(np, "qcom,core_3_0v_support", NULL))
pdata->core_3_0v_support = true;
+ pdata->sdr104_wa = of_property_read_bool(np, "qcom,sdr104-wa");
+
return pdata;
out:
return NULL;
@@ -4579,6 +4581,7 @@ static int sdhci_msm_probe(struct platform_device *pdev)
if (msm_host->pdata->nonhotplug)
msm_host->mmc->caps2 |= MMC_CAP2_NONHOTPLUG;
+ msm_host->mmc->sdr104_wa = msm_host->pdata->sdr104_wa;
/* Initialize ICE if present */
if (msm_host->ice.pdev) {
diff --git a/drivers/mmc/host/sdhci-msm.h b/drivers/mmc/host/sdhci-msm.h
index 2e4f2179378e..92f61708001e 100644
--- a/drivers/mmc/host/sdhci-msm.h
+++ b/drivers/mmc/host/sdhci-msm.h
@@ -153,6 +153,7 @@ struct sdhci_msm_pltfm_data {
u32 ice_clk_min;
struct sdhci_msm_pm_qos_data pm_qos_data;
bool core_3_0v_support;
+ bool sdr104_wa;
};
struct sdhci_msm_bus_vote {
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 44633dc5d2be..40a34c283955 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -3083,7 +3083,10 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
mmc_hostname(host->mmc), intmask,
host->data->error, ktime_to_ms(ktime_sub(
ktime_get(), host->data_start_time)));
- sdhci_dumpregs(host);
+
+ if (!host->mmc->sdr104_wa ||
+ (host->mmc->ios.timing != MMC_TIMING_UHS_SDR104))
+ sdhci_dumpregs(host);
}
sdhci_finish_data(host);
} else {
diff --git a/drivers/net/ethernet/msm/msm_rmnet_mhi.c b/drivers/net/ethernet/msm/msm_rmnet_mhi.c
index bf6502e27bdd..015cb99d445b 100644
--- a/drivers/net/ethernet/msm/msm_rmnet_mhi.c
+++ b/drivers/net/ethernet/msm/msm_rmnet_mhi.c
@@ -35,6 +35,7 @@
#define MHI_NAPI_WEIGHT_VALUE 12
#define WATCHDOG_TIMEOUT (30 * HZ)
#define RMNET_IPC_LOG_PAGES (100)
+#define IRQ_MASKED_BIT (0)
enum DBG_LVL {
MSG_VERBOSE = 0x1,
@@ -100,14 +101,15 @@ struct rmnet_mhi_private {
u32 mhi_enabled;
struct platform_device *pdev;
struct net_device *dev;
- atomic_t irq_masked_cntr;
+ unsigned long flags;
+ int wake_count;
spinlock_t out_chan_full_lock; /* tx queue lock */
- atomic_t pending_data;
struct sk_buff *frag_skb;
struct work_struct alloc_work;
/* lock to queue hardware and internal queue */
spinlock_t alloc_lock;
void *rmnet_ipc_log;
+ rwlock_t pm_lock; /* state change lock */
struct debug_params debug;
struct dentry *dentry;
};
@@ -130,12 +132,12 @@ static int rmnet_mhi_process_fragment(struct rmnet_mhi_private *rmnet_mhi_ptr,
rmnet_mhi_ptr->frag_skb = NULL;
return -ENOMEM;
}
- kfree_skb(rmnet_mhi_ptr->frag_skb);
+ dev_kfree_skb_any(rmnet_mhi_ptr->frag_skb);
rmnet_mhi_ptr->frag_skb = temp_skb;
memcpy(skb_put(rmnet_mhi_ptr->frag_skb, skb->len),
skb->data,
skb->len);
- kfree_skb(skb);
+ dev_kfree_skb_any(skb);
if (!frag) {
/* Last fragmented piece was received, ship it */
netif_receive_skb(rmnet_mhi_ptr->frag_skb);
@@ -196,7 +198,6 @@ static int rmnet_alloc_rx(struct rmnet_mhi_private *rmnet_mhi_ptr,
{
u32 cur_mru = rmnet_mhi_ptr->mru;
struct mhi_skb_priv *skb_priv;
- unsigned long flags;
int ret;
struct sk_buff *skb;
@@ -215,7 +216,7 @@ static int rmnet_alloc_rx(struct rmnet_mhi_private *rmnet_mhi_ptr,
skb_priv->dma_addr = 0;
/* These steps must be in atomic context */
- spin_lock_irqsave(&rmnet_mhi_ptr->alloc_lock, flags);
+ spin_lock_bh(&rmnet_mhi_ptr->alloc_lock);
/* It's possible by the time alloc_skb (GFP_KERNEL)
* returns we already called rmnet_alloc_rx
@@ -224,14 +225,22 @@ static int rmnet_alloc_rx(struct rmnet_mhi_private *rmnet_mhi_ptr,
*/
if (unlikely(atomic_read(&rmnet_mhi_ptr->rx_pool_len) >=
rmnet_mhi_ptr->rx_buffers_max)) {
- spin_unlock_irqrestore(&rmnet_mhi_ptr->alloc_lock,
- flags);
+ spin_unlock_bh(&rmnet_mhi_ptr->alloc_lock);
dev_kfree_skb_any(skb);
return 0;
}
- ret = mhi_queue_xfer(
- rmnet_mhi_ptr->rx_client_handle,
+ read_lock_bh(&rmnet_mhi_ptr->pm_lock);
+ if (unlikely(!rmnet_mhi_ptr->mhi_enabled)) {
+ rmnet_log(rmnet_mhi_ptr, MSG_INFO,
+ "!interface is disabled\n");
+ dev_kfree_skb_any(skb);
+ read_unlock_bh(&rmnet_mhi_ptr->pm_lock);
+ spin_unlock_bh(&rmnet_mhi_ptr->alloc_lock);
+ return -EIO;
+ }
+
+ ret = mhi_queue_xfer(rmnet_mhi_ptr->rx_client_handle,
skb->data,
skb_priv->dma_size,
MHI_EOT);
@@ -239,14 +248,15 @@ static int rmnet_alloc_rx(struct rmnet_mhi_private *rmnet_mhi_ptr,
rmnet_log(rmnet_mhi_ptr,
MSG_CRITICAL,
"mhi_queue_xfer failed, error %d", ret);
- spin_unlock_irqrestore(&rmnet_mhi_ptr->alloc_lock,
- flags);
+ read_unlock_bh(&rmnet_mhi_ptr->pm_lock);
+ spin_unlock_bh(&rmnet_mhi_ptr->alloc_lock);
dev_kfree_skb_any(skb);
return ret;
}
skb_queue_tail(&rmnet_mhi_ptr->rx_buffers, skb);
atomic_inc(&rmnet_mhi_ptr->rx_pool_len);
- spin_unlock_irqrestore(&rmnet_mhi_ptr->alloc_lock, flags);
+ read_unlock_bh(&rmnet_mhi_ptr->pm_lock);
+ spin_unlock_bh(&rmnet_mhi_ptr->alloc_lock);
}
return 0;
@@ -258,13 +268,25 @@ static void rmnet_mhi_alloc_work(struct work_struct *work)
struct rmnet_mhi_private,
alloc_work);
int ret;
+ /* sleep about 1 sec and retry, that should be enough time
+ * for system to reclaim freed memory back.
+ */
+ const int sleep_ms = 1000;
+ int retry = 60;
rmnet_log(rmnet_mhi_ptr, MSG_INFO, "Entered\n");
- ret = rmnet_alloc_rx(rmnet_mhi_ptr,
- rmnet_mhi_ptr->allocation_flags);
+ do {
+ ret = rmnet_alloc_rx(rmnet_mhi_ptr,
+ rmnet_mhi_ptr->allocation_flags);
+ /* sleep and try again */
+ if (ret == -ENOMEM) {
+ msleep(sleep_ms);
+ retry--;
+ }
+ } while (ret == -ENOMEM && retry);
- WARN_ON(ret == -ENOMEM);
- rmnet_log(rmnet_mhi_ptr, MSG_INFO, "Exit\n");
+ rmnet_log(rmnet_mhi_ptr, MSG_INFO, "Exit with status:%d retry:%d\n",
+ ret, retry);
}
static int rmnet_mhi_poll(struct napi_struct *napi, int budget)
@@ -281,6 +303,12 @@ static int rmnet_mhi_poll(struct napi_struct *napi, int budget)
rmnet_log(rmnet_mhi_ptr, MSG_VERBOSE, "Entered\n");
+ read_lock_bh(&rmnet_mhi_ptr->pm_lock);
+ if (unlikely(!rmnet_mhi_ptr->mhi_enabled)) {
+ rmnet_log(rmnet_mhi_ptr, MSG_INFO, "interface is disabled!\n");
+ read_unlock_bh(&rmnet_mhi_ptr->pm_lock);
+ return 0;
+ }
while (received_packets < budget) {
struct mhi_result *result =
mhi_poll(rmnet_mhi_ptr->rx_client_handle);
@@ -338,77 +366,50 @@ static int rmnet_mhi_poll(struct napi_struct *napi, int budget)
dev->stats.rx_bytes += result->bytes_xferd;
} /* while (received_packets < budget) or any other error */
+ read_unlock_bh(&rmnet_mhi_ptr->pm_lock);
/* Queue new buffers */
res = rmnet_alloc_rx(rmnet_mhi_ptr, GFP_ATOMIC);
- if (res == -ENOMEM) {
- rmnet_log(rmnet_mhi_ptr,
- MSG_INFO,
- "out of mem, queuing bg worker\n");
- rmnet_mhi_ptr->alloc_fail++;
- schedule_work(&rmnet_mhi_ptr->alloc_work);
- }
- napi_complete(napi);
+ read_lock_bh(&rmnet_mhi_ptr->pm_lock);
+ if (likely(rmnet_mhi_ptr->mhi_enabled)) {
+ if (res == -ENOMEM) {
+ rmnet_log(rmnet_mhi_ptr, MSG_INFO,
+ "out of mem, queuing bg worker\n");
+ rmnet_mhi_ptr->alloc_fail++;
+ schedule_work(&rmnet_mhi_ptr->alloc_work);
+ }
+
+ napi_complete(napi);
- /* We got a NULL descriptor back */
- if (should_reschedule == false) {
- if (atomic_read(&rmnet_mhi_ptr->irq_masked_cntr)) {
- atomic_dec(&rmnet_mhi_ptr->irq_masked_cntr);
- mhi_unmask_irq(rmnet_mhi_ptr->rx_client_handle);
+ /* We got a NULL descriptor back */
+ if (!should_reschedule) {
+ if (test_and_clear_bit(IRQ_MASKED_BIT,
+ &rmnet_mhi_ptr->flags))
+ mhi_unmask_irq(rmnet_mhi_ptr->rx_client_handle);
mhi_set_lpm(rmnet_mhi_ptr->rx_client_handle, true);
+ rmnet_mhi_ptr->wake_count--;
+ } else {
+ if (received_packets == budget)
+ rmnet_mhi_ptr->debug.rx_napi_budget_overflow++;
+ napi_reschedule(napi);
}
- } else {
- if (received_packets == budget)
- rmnet_mhi_ptr->debug.rx_napi_budget_overflow++;
- napi_reschedule(napi);
- }
- rmnet_mhi_ptr->debug.rx_napi_skb_burst_min =
- min((u64)received_packets,
- rmnet_mhi_ptr->debug.rx_napi_skb_burst_min);
+ rmnet_mhi_ptr->debug.rx_napi_skb_burst_min =
+ min((u64)received_packets,
+ rmnet_mhi_ptr->debug.rx_napi_skb_burst_min);
- rmnet_mhi_ptr->debug.rx_napi_skb_burst_max =
- max((u64)received_packets,
- rmnet_mhi_ptr->debug.rx_napi_skb_burst_max);
+ rmnet_mhi_ptr->debug.rx_napi_skb_burst_max =
+ max((u64)received_packets,
+ rmnet_mhi_ptr->debug.rx_napi_skb_burst_max);
+ }
+ read_unlock_bh(&rmnet_mhi_ptr->pm_lock);
rmnet_log(rmnet_mhi_ptr, MSG_VERBOSE,
"Exited, polled %d pkts\n", received_packets);
return received_packets;
}
-void rmnet_mhi_clean_buffers(struct net_device *dev)
-{
- struct rmnet_mhi_private *rmnet_mhi_ptr =
- *(struct rmnet_mhi_private **)netdev_priv(dev);
-
- rmnet_log(rmnet_mhi_ptr, MSG_INFO, "Entered\n");
- /* Clean TX buffers */
- rmnet_mhi_internal_clean_unmap_buffers(dev,
- &rmnet_mhi_ptr->tx_buffers,
- DMA_TO_DEVICE);
-
- /* Clean RX buffers */
- rmnet_mhi_internal_clean_unmap_buffers(dev,
- &rmnet_mhi_ptr->rx_buffers,
- DMA_FROM_DEVICE);
- rmnet_log(rmnet_mhi_ptr, MSG_INFO, "Exited\n");
-}
-
-static int rmnet_mhi_disable_channels(struct rmnet_mhi_private *rmnet_mhi_ptr)
-{
- rmnet_log(rmnet_mhi_ptr, MSG_INFO, "Closing MHI TX channel\n");
- mhi_close_channel(rmnet_mhi_ptr->tx_client_handle);
- rmnet_log(rmnet_mhi_ptr, MSG_INFO, "Closing MHI RX channel\n");
- mhi_close_channel(rmnet_mhi_ptr->rx_client_handle);
- rmnet_log(rmnet_mhi_ptr, MSG_INFO, "Clearing Pending TX buffers.\n");
- rmnet_mhi_clean_buffers(rmnet_mhi_ptr->dev);
- rmnet_mhi_ptr->tx_client_handle = NULL;
- rmnet_mhi_ptr->rx_client_handle = NULL;
-
- return 0;
-}
-
static int rmnet_mhi_init_inbound(struct rmnet_mhi_private *rmnet_mhi_ptr)
{
int res;
@@ -431,7 +432,7 @@ static void rmnet_mhi_tx_cb(struct mhi_result *result)
struct net_device *dev;
struct rmnet_mhi_private *rmnet_mhi_ptr;
unsigned long burst_counter = 0;
- unsigned long flags;
+ unsigned long flags, pm_flags;
rmnet_mhi_ptr = result->user_data;
dev = rmnet_mhi_ptr->dev;
@@ -451,10 +452,10 @@ static void rmnet_mhi_tx_cb(struct mhi_result *result)
break;
} else {
if (skb->data == result->buf_addr) {
- kfree_skb(skb);
+ dev_kfree_skb_any(skb);
break;
}
- kfree_skb(skb);
+ dev_kfree_skb_any(skb);
burst_counter++;
/* Update statistics */
@@ -477,10 +478,15 @@ static void rmnet_mhi_tx_cb(struct mhi_result *result)
rmnet_mhi_ptr->debug.tx_cb_skb_free_burst_max);
/* In case we couldn't write again, now we can! */
- spin_lock_irqsave(&rmnet_mhi_ptr->out_chan_full_lock, flags);
- rmnet_log(rmnet_mhi_ptr, MSG_VERBOSE, "Waking up queue\n");
- netif_wake_queue(dev);
- spin_unlock_irqrestore(&rmnet_mhi_ptr->out_chan_full_lock, flags);
+ read_lock_irqsave(&rmnet_mhi_ptr->pm_lock, pm_flags);
+ if (likely(rmnet_mhi_ptr->mhi_enabled)) {
+ spin_lock_irqsave(&rmnet_mhi_ptr->out_chan_full_lock, flags);
+ rmnet_log(rmnet_mhi_ptr, MSG_VERBOSE, "Waking up queue\n");
+ netif_wake_queue(dev);
+ spin_unlock_irqrestore(&rmnet_mhi_ptr->out_chan_full_lock,
+ flags);
+ }
+ read_unlock_irqrestore(&rmnet_mhi_ptr->pm_lock, pm_flags);
rmnet_log(rmnet_mhi_ptr, MSG_VERBOSE, "Exited\n");
}
@@ -488,20 +494,27 @@ static void rmnet_mhi_rx_cb(struct mhi_result *result)
{
struct net_device *dev;
struct rmnet_mhi_private *rmnet_mhi_ptr;
+ unsigned long flags;
+
rmnet_mhi_ptr = result->user_data;
dev = rmnet_mhi_ptr->dev;
rmnet_log(rmnet_mhi_ptr, MSG_VERBOSE, "Entered\n");
rmnet_mhi_ptr->debug.rx_interrupts_count++;
-
- if (napi_schedule_prep(&(rmnet_mhi_ptr->napi))) {
- mhi_mask_irq(rmnet_mhi_ptr->rx_client_handle);
- atomic_inc(&rmnet_mhi_ptr->irq_masked_cntr);
- mhi_set_lpm(rmnet_mhi_ptr->rx_client_handle, false);
- __napi_schedule(&(rmnet_mhi_ptr->napi));
- } else {
- rmnet_mhi_ptr->debug.rx_interrupts_in_masked_irq++;
+ read_lock_irqsave(&rmnet_mhi_ptr->pm_lock, flags);
+ if (likely(rmnet_mhi_ptr->mhi_enabled)) {
+ if (napi_schedule_prep(&rmnet_mhi_ptr->napi)) {
+ if (!test_and_set_bit(IRQ_MASKED_BIT,
+ &rmnet_mhi_ptr->flags))
+ mhi_mask_irq(rmnet_mhi_ptr->rx_client_handle);
+ mhi_set_lpm(rmnet_mhi_ptr->rx_client_handle, false);
+ rmnet_mhi_ptr->wake_count++;
+ __napi_schedule(&rmnet_mhi_ptr->napi);
+ } else {
+ rmnet_mhi_ptr->debug.rx_interrupts_in_masked_irq++;
+ }
}
+ read_unlock_irqrestore(&rmnet_mhi_ptr->pm_lock, flags);
rmnet_log(rmnet_mhi_ptr, MSG_VERBOSE, "Exited\n");
}
@@ -510,8 +523,7 @@ static int rmnet_mhi_open(struct net_device *dev)
struct rmnet_mhi_private *rmnet_mhi_ptr =
*(struct rmnet_mhi_private **)netdev_priv(dev);
- rmnet_log(rmnet_mhi_ptr,
- MSG_INFO,
+ rmnet_log(rmnet_mhi_ptr, MSG_INFO,
"Opened net dev interface for MHI chans %d and %d\n",
rmnet_mhi_ptr->tx_channel,
rmnet_mhi_ptr->rx_channel);
@@ -527,43 +539,35 @@ static int rmnet_mhi_open(struct net_device *dev)
/* Poll to check if any buffers are accumulated in the
* transport buffers
*/
- if (napi_schedule_prep(&(rmnet_mhi_ptr->napi))) {
- mhi_mask_irq(rmnet_mhi_ptr->rx_client_handle);
- atomic_inc(&rmnet_mhi_ptr->irq_masked_cntr);
- mhi_set_lpm(rmnet_mhi_ptr->rx_client_handle, false);
- __napi_schedule(&(rmnet_mhi_ptr->napi));
- } else {
- rmnet_mhi_ptr->debug.rx_interrupts_in_masked_irq++;
+ read_lock_bh(&rmnet_mhi_ptr->pm_lock);
+ if (likely(rmnet_mhi_ptr->mhi_enabled)) {
+ if (napi_schedule_prep(&rmnet_mhi_ptr->napi)) {
+ if (!test_and_set_bit(IRQ_MASKED_BIT,
+ &rmnet_mhi_ptr->flags)) {
+ mhi_mask_irq(rmnet_mhi_ptr->rx_client_handle);
+ }
+ mhi_set_lpm(rmnet_mhi_ptr->rx_client_handle, false);
+ rmnet_mhi_ptr->wake_count++;
+ __napi_schedule(&rmnet_mhi_ptr->napi);
+ } else {
+ rmnet_mhi_ptr->debug.rx_interrupts_in_masked_irq++;
+ }
}
+ read_unlock_bh(&rmnet_mhi_ptr->pm_lock);
return 0;
}
-static int rmnet_mhi_disable_iface(struct rmnet_mhi_private *rmnet_mhi_ptr)
-{
- rmnet_mhi_ptr->rx_enabled = 0;
- rmnet_mhi_ptr->tx_enabled = 0;
- rmnet_mhi_ptr->mhi_enabled = 0;
- if (rmnet_mhi_ptr->dev != 0) {
- netif_stop_queue(rmnet_mhi_ptr->dev);
- netif_napi_del(&(rmnet_mhi_ptr->napi));
- rmnet_mhi_disable_channels(rmnet_mhi_ptr);
- unregister_netdev(rmnet_mhi_ptr->dev);
- free_netdev(rmnet_mhi_ptr->dev);
- rmnet_mhi_ptr->dev = 0;
- }
- return 0;
-}
-
static int rmnet_mhi_disable(struct rmnet_mhi_private *rmnet_mhi_ptr)
{
- rmnet_mhi_ptr->mhi_enabled = 0;
- rmnet_mhi_disable_iface(rmnet_mhi_ptr);
napi_disable(&(rmnet_mhi_ptr->napi));
- if (atomic_read(&rmnet_mhi_ptr->irq_masked_cntr)) {
+ rmnet_mhi_ptr->rx_enabled = 0;
+ rmnet_mhi_internal_clean_unmap_buffers(rmnet_mhi_ptr->dev,
+ &rmnet_mhi_ptr->rx_buffers,
+ DMA_FROM_DEVICE);
+ if (test_and_clear_bit(IRQ_MASKED_BIT, &rmnet_mhi_ptr->flags))
mhi_unmask_irq(rmnet_mhi_ptr->rx_client_handle);
- atomic_dec(&rmnet_mhi_ptr->irq_masked_cntr);
- }
+
return 0;
}
@@ -574,11 +578,9 @@ static int rmnet_mhi_stop(struct net_device *dev)
netif_stop_queue(dev);
rmnet_log(rmnet_mhi_ptr, MSG_VERBOSE, "Entered\n");
- if (atomic_read(&rmnet_mhi_ptr->irq_masked_cntr)) {
+ if (test_and_clear_bit(IRQ_MASKED_BIT, &rmnet_mhi_ptr->flags)) {
mhi_unmask_irq(rmnet_mhi_ptr->rx_client_handle);
- atomic_dec(&rmnet_mhi_ptr->irq_masked_cntr);
- rmnet_log(rmnet_mhi_ptr,
- MSG_ERROR,
+ rmnet_log(rmnet_mhi_ptr, MSG_ERROR,
"IRQ was masked, unmasking...\n");
}
rmnet_log(rmnet_mhi_ptr, MSG_VERBOSE, "Exited\n");
@@ -605,14 +607,23 @@ static int rmnet_mhi_xmit(struct sk_buff *skb, struct net_device *dev)
unsigned long flags;
struct mhi_skb_priv *tx_priv;
- rmnet_log(rmnet_mhi_ptr,
- MSG_VERBOSE,
- "Entered chan %d\n",
- rmnet_mhi_ptr->tx_channel);
+ rmnet_log(rmnet_mhi_ptr, MSG_VERBOSE,
+ "Entered chan %d\n", rmnet_mhi_ptr->tx_channel);
tx_priv = (struct mhi_skb_priv *)(skb->cb);
tx_priv->dma_size = skb->len;
tx_priv->dma_addr = 0;
+ read_lock_bh(&rmnet_mhi_ptr->pm_lock);
+ if (unlikely(!rmnet_mhi_ptr->mhi_enabled)) {
+ /* Only reason interface could be disabled and we get data
+ * is due to an SSR. We do not want to stop the queue and
+ * return error. instead we will flush all the uplink packets
+ * and return successful
+ */
+ res = NETDEV_TX_OK;
+ dev_kfree_skb_any(skb);
+ goto mhi_xmit_exit;
+ }
if (mhi_get_free_desc(rmnet_mhi_ptr->tx_client_handle) <= 0) {
rmnet_log(rmnet_mhi_ptr,
@@ -624,7 +635,8 @@ static int rmnet_mhi_xmit(struct sk_buff *skb, struct net_device *dev)
netif_stop_queue(dev);
spin_unlock_irqrestore(&rmnet_mhi_ptr->out_chan_full_lock,
flags);
- return NETDEV_TX_BUSY;
+ res = NETDEV_TX_BUSY;
+ goto mhi_xmit_exit;
}
res = mhi_queue_xfer(rmnet_mhi_ptr->tx_client_handle,
skb->data,
@@ -641,15 +653,17 @@ static int rmnet_mhi_xmit(struct sk_buff *skb, struct net_device *dev)
netif_stop_queue(dev);
spin_unlock_irqrestore(&rmnet_mhi_ptr->out_chan_full_lock,
flags);
- return NETDEV_TX_BUSY;
+ res = NETDEV_TX_BUSY;
+ goto mhi_xmit_exit;
}
-
+ res = NETDEV_TX_OK;
skb_queue_tail(&(rmnet_mhi_ptr->tx_buffers), skb);
dev->trans_start = jiffies;
rmnet_mhi_ptr->debug.tx_queued_packets_count++;
-
+mhi_xmit_exit:
+ read_unlock_bh(&rmnet_mhi_ptr->pm_lock);
rmnet_log(rmnet_mhi_ptr, MSG_VERBOSE, "Exited\n");
- return NETDEV_TX_OK;
+ return res;
}
static int rmnet_mhi_ioctl_extended(struct net_device *dev, struct ifreq *ifr)
@@ -698,16 +712,19 @@ static int rmnet_mhi_ioctl_extended(struct net_device *dev, struct ifreq *ifr)
sizeof(ext_cmd.u.if_name));
break;
case RMNET_IOCTL_SET_SLEEP_STATE:
+ read_lock_bh(&rmnet_mhi_ptr->pm_lock);
if (rmnet_mhi_ptr->mhi_enabled &&
rmnet_mhi_ptr->tx_client_handle != NULL) {
+ rmnet_mhi_ptr->wake_count += (ext_cmd.u.data) ? -1 : 1;
mhi_set_lpm(rmnet_mhi_ptr->tx_client_handle,
ext_cmd.u.data);
} else {
- rmnet_log(rmnet_mhi_ptr,
- MSG_ERROR,
+ rmnet_log(rmnet_mhi_ptr, MSG_ERROR,
"Cannot set LPM value, MHI is not up.\n");
+ read_unlock_bh(&rmnet_mhi_ptr->pm_lock);
return -ENODEV;
}
+ read_unlock_bh(&rmnet_mhi_ptr->pm_lock);
break;
default:
rc = -EINVAL;
@@ -832,9 +849,8 @@ static int rmnet_mhi_enable_iface(struct rmnet_mhi_private *rmnet_mhi_ptr)
"Failed to start TX chan ret %d\n",
r);
goto mhi_tx_chan_start_fail;
- } else {
- rmnet_mhi_ptr->tx_enabled = 1;
}
+
client_handle = rmnet_mhi_ptr->tx_client_handle;
}
if (rmnet_mhi_ptr->rx_client_handle != NULL) {
@@ -848,8 +864,6 @@ static int rmnet_mhi_enable_iface(struct rmnet_mhi_private *rmnet_mhi_ptr)
"Failed to start RX chan ret %d\n",
r);
goto mhi_rx_chan_start_fail;
- } else {
- rmnet_mhi_ptr->rx_enabled = 1;
}
/* Both tx & rx client handle contain same device info */
client_handle = rmnet_mhi_ptr->rx_client_handle;
@@ -860,62 +874,64 @@ static int rmnet_mhi_enable_iface(struct rmnet_mhi_private *rmnet_mhi_ptr)
goto net_dev_alloc_fail;
}
- snprintf(ifalias,
- sizeof(ifalias),
- "%s_%04x_%02u.%02u.%02u_%u",
- rmnet_mhi_ptr->interface_name,
- client_handle->dev_id,
- client_handle->domain,
- client_handle->bus,
- client_handle->slot,
- rmnet_mhi_ptr->dev_id);
-
- snprintf(ifname, sizeof(ifname), "%s%%d",
- rmnet_mhi_ptr->interface_name);
- rtnl_lock();
- rmnet_mhi_ptr->dev =
- alloc_netdev(sizeof(struct rmnet_mhi_private *),
- ifname, NET_NAME_PREDICTABLE, rmnet_mhi_setup);
if (!rmnet_mhi_ptr->dev) {
- rmnet_log(rmnet_mhi_ptr,
- MSG_CRITICAL,
- "Network device allocation failed\n");
- ret = -ENOMEM;
- goto net_dev_alloc_fail;
+ snprintf(ifalias, sizeof(ifalias),
+ "%s_%04x_%02u.%02u.%02u_%u",
+ rmnet_mhi_ptr->interface_name,
+ client_handle->dev_id,
+ client_handle->domain,
+ client_handle->bus,
+ client_handle->slot,
+ rmnet_mhi_ptr->dev_id);
+
+ snprintf(ifname, sizeof(ifname), "%s%%d",
+ rmnet_mhi_ptr->interface_name);
+
+ rtnl_lock();
+ rmnet_mhi_ptr->dev = alloc_netdev(
+ sizeof(struct rmnet_mhi_private *),
+ ifname, NET_NAME_PREDICTABLE, rmnet_mhi_setup);
+
+ if (!rmnet_mhi_ptr->dev) {
+ rmnet_log(rmnet_mhi_ptr, MSG_CRITICAL,
+ "Network device allocation failed\n");
+ ret = -ENOMEM;
+ goto net_dev_alloc_fail;
+ }
+ SET_NETDEV_DEV(rmnet_mhi_ptr->dev, &rmnet_mhi_ptr->pdev->dev);
+ dev_set_alias(rmnet_mhi_ptr->dev, ifalias, strlen(ifalias));
+ rmnet_mhi_ctxt = netdev_priv(rmnet_mhi_ptr->dev);
+ rtnl_unlock();
+ *rmnet_mhi_ctxt = rmnet_mhi_ptr;
+
+ ret = dma_set_mask(&rmnet_mhi_ptr->dev->dev, MHI_DMA_MASK);
+ if (ret)
+ rmnet_mhi_ptr->allocation_flags = GFP_KERNEL;
+ else
+ rmnet_mhi_ptr->allocation_flags = GFP_DMA;
+
+ netif_napi_add(rmnet_mhi_ptr->dev, &rmnet_mhi_ptr->napi,
+ rmnet_mhi_poll, MHI_NAPI_WEIGHT_VALUE);
+
+ ret = register_netdev(rmnet_mhi_ptr->dev);
+ if (ret) {
+ rmnet_log(rmnet_mhi_ptr, MSG_CRITICAL,
+ "Network device registration failed\n");
+ goto net_dev_reg_fail;
+ }
}
- SET_NETDEV_DEV(rmnet_mhi_ptr->dev, &rmnet_mhi_ptr->pdev->dev);
- dev_set_alias(rmnet_mhi_ptr->dev, ifalias, strlen(ifalias));
- rmnet_mhi_ctxt = netdev_priv(rmnet_mhi_ptr->dev);
- rtnl_unlock();
- *rmnet_mhi_ctxt = rmnet_mhi_ptr;
-
- ret = dma_set_mask(&(rmnet_mhi_ptr->dev->dev),
- MHI_DMA_MASK);
- if (ret)
- rmnet_mhi_ptr->allocation_flags = GFP_KERNEL;
- else
- rmnet_mhi_ptr->allocation_flags = GFP_DMA;
+
+ write_lock_irq(&rmnet_mhi_ptr->pm_lock);
+ rmnet_mhi_ptr->mhi_enabled = 1;
+ write_unlock_irq(&rmnet_mhi_ptr->pm_lock);
r = rmnet_mhi_init_inbound(rmnet_mhi_ptr);
if (r) {
- rmnet_log(rmnet_mhi_ptr,
- MSG_CRITICAL,
- "Failed to init inbound ret %d\n",
- r);
+ rmnet_log(rmnet_mhi_ptr, MSG_INFO,
+ "Failed to init inbound ret %d\n", r);
}
- netif_napi_add(rmnet_mhi_ptr->dev, &(rmnet_mhi_ptr->napi),
- rmnet_mhi_poll, MHI_NAPI_WEIGHT_VALUE);
-
- rmnet_mhi_ptr->mhi_enabled = 1;
- ret = register_netdev(rmnet_mhi_ptr->dev);
- if (ret) {
- rmnet_log(rmnet_mhi_ptr,
- MSG_CRITICAL,
- "Network device registration failed\n");
- goto net_dev_reg_fail;
- }
napi_enable(&(rmnet_mhi_ptr->napi));
rmnet_log(rmnet_mhi_ptr, MSG_INFO, "Exited.\n");
@@ -951,25 +967,47 @@ static void rmnet_mhi_cb(struct mhi_cb_info *cb_info)
switch (cb_info->cb_reason) {
case MHI_CB_MHI_DISABLED:
- rmnet_log(rmnet_mhi_ptr,
- MSG_CRITICAL,
- "Got MHI_DISABLED notification. Stopping stack\n");
- if (rmnet_mhi_ptr->mhi_enabled) {
- rmnet_mhi_ptr->mhi_enabled = 0;
- /* Ensure MHI is disabled before other mem ops */
- wmb();
- while (atomic_read(&rmnet_mhi_ptr->pending_data)) {
- rmnet_log(rmnet_mhi_ptr,
- MSG_CRITICAL,
- "Waiting for channels to stop.\n");
- msleep(25);
- }
+ case MHI_CB_MHI_SHUTDOWN:
+ case MHI_CB_SYS_ERROR:
+ rmnet_log(rmnet_mhi_ptr, MSG_INFO,
+ "Got MHI_SYS_ERROR notification. Stopping stack\n");
+
+ /* Disable interface on first notification. Long
+ * as we set mhi_enabled = 0, we gurantee rest of
+ * driver will not touch any critical data.
+ */
+ write_lock_irq(&rmnet_mhi_ptr->pm_lock);
+ rmnet_mhi_ptr->mhi_enabled = 0;
+ write_unlock_irq(&rmnet_mhi_ptr->pm_lock);
+
+ if (cb_info->chan == rmnet_mhi_ptr->rx_channel) {
+ rmnet_log(rmnet_mhi_ptr, MSG_INFO,
+ "Receive MHI_DISABLE notification for rx path\n");
rmnet_mhi_disable(rmnet_mhi_ptr);
+ } else {
+ rmnet_log(rmnet_mhi_ptr, MSG_INFO,
+ "Receive MHI_DISABLE notification for tx path\n");
+ rmnet_mhi_ptr->tx_enabled = 0;
+ rmnet_mhi_internal_clean_unmap_buffers
+ (rmnet_mhi_ptr->dev, &rmnet_mhi_ptr->tx_buffers,
+ DMA_TO_DEVICE);
+ }
+
+ /* Remove all votes disabling low power mode */
+ if (!rmnet_mhi_ptr->tx_enabled && !rmnet_mhi_ptr->rx_enabled) {
+ struct mhi_client_handle *handle =
+ rmnet_mhi_ptr->rx_client_handle;
+
+ if (!handle)
+ handle = rmnet_mhi_ptr->tx_client_handle;
+ while (rmnet_mhi_ptr->wake_count) {
+ mhi_set_lpm(handle, true);
+ rmnet_mhi_ptr->wake_count--;
+ }
}
break;
case MHI_CB_MHI_ENABLED:
- rmnet_log(rmnet_mhi_ptr,
- MSG_CRITICAL,
+ rmnet_log(rmnet_mhi_ptr, MSG_INFO,
"Got MHI_ENABLED notification. Starting stack\n");
if (cb_info->chan == rmnet_mhi_ptr->rx_channel)
rmnet_mhi_ptr->rx_enabled = 1;
@@ -998,16 +1036,10 @@ static void rmnet_mhi_cb(struct mhi_cb_info *cb_info)
}
break;
case MHI_CB_XFER:
- atomic_inc(&rmnet_mhi_ptr->pending_data);
- /* Flush pending data is set before any other mem operations */
- wmb();
- if (rmnet_mhi_ptr->mhi_enabled) {
- if (cb_info->chan == rmnet_mhi_ptr->rx_channel)
- rmnet_mhi_rx_cb(cb_info->result);
- else
- rmnet_mhi_tx_cb(cb_info->result);
- }
- atomic_dec(&rmnet_mhi_ptr->pending_data);
+ if (cb_info->chan == rmnet_mhi_ptr->rx_channel)
+ rmnet_mhi_rx_cb(cb_info->result);
+ else
+ rmnet_mhi_tx_cb(cb_info->result);
break;
default:
break;
@@ -1172,6 +1204,7 @@ static int rmnet_mhi_probe(struct platform_device *pdev)
return -ENOMEM;
rmnet_mhi_ptr->pdev = pdev;
spin_lock_init(&rmnet_mhi_ptr->out_chan_full_lock);
+ rwlock_init(&rmnet_mhi_ptr->pm_lock);
rc = of_property_read_u32(pdev->dev.of_node,
"qcom,mhi-mru",
diff --git a/drivers/net/wireless/ath/wil6210/pm.c b/drivers/net/wireless/ath/wil6210/pm.c
index 7260bef314a4..2ae4fe85cc8c 100644
--- a/drivers/net/wireless/ath/wil6210/pm.c
+++ b/drivers/net/wireless/ath/wil6210/pm.c
@@ -71,6 +71,11 @@ int wil_suspend(struct wil6210_priv *wil, bool is_runtime)
wil_dbg_pm(wil, "suspend: %s\n", is_runtime ? "runtime" : "system");
+ if (test_bit(wil_status_suspended, wil->status)) {
+ wil_dbg_pm(wil, "trying to suspend while suspended\n");
+ return 0;
+ }
+
/* if netif up, hardware is alive, shut it down */
if (ndev->flags & IFF_UP) {
rc = wil_down(wil);
@@ -86,10 +91,14 @@ int wil_suspend(struct wil6210_priv *wil, bool is_runtime)
if (wil->platform_ops.suspend) {
rc = wil->platform_ops.suspend(wil->platform_handle);
- if (rc)
+ if (rc) {
wil_enable_irq(wil);
+ goto out;
+ }
}
+ set_bit(wil_status_suspended, wil->status);
+
out:
wil_dbg_pm(wil, "suspend: %s => %d\n",
is_runtime ? "runtime" : "system", rc);
@@ -117,10 +126,13 @@ int wil_resume(struct wil6210_priv *wil, bool is_runtime)
/* if netif up, bring hardware up
* During open(), IFF_UP set after actual device method
- * invocation. This prevent recursive call to wil_up()
+ * invocation. This prevent recursive call to wil_up().
+ * wil_status_suspended will be cleared in wil_reset
*/
if (ndev->flags & IFF_UP)
rc = wil_up(wil);
+ else
+ clear_bit(wil_status_suspended, wil->status);
out:
wil_dbg_pm(wil, "resume: %s => %d\n",
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h
index 6111ef6408ea..83c0724a21d7 100644
--- a/drivers/net/wireless/ath/wil6210/wil6210.h
+++ b/drivers/net/wireless/ath/wil6210/wil6210.h
@@ -417,6 +417,7 @@ enum { /* for wil6210_priv.status */
wil_status_irqen, /* FIXME: interrupts enabled - for debug */
wil_status_napi_en, /* NAPI enabled protected by wil->mutex */
wil_status_resetting, /* reset in progress */
+ wil_status_suspended, /* suspend completed, device is suspended */
wil_status_last /* keep last */
};
diff --git a/drivers/pci/host/pci-msm.c b/drivers/pci/host/pci-msm.c
index 72695d3b9224..121c994e6033 100644
--- a/drivers/pci/host/pci-msm.c
+++ b/drivers/pci/host/pci-msm.c
@@ -481,6 +481,11 @@ enum msm_pcie_link_status {
MSM_PCIE_LINK_DISABLED
};
+enum msm_pcie_boot_option {
+ MSM_PCIE_NO_PROBE_ENUMERATION = BIT(0),
+ MSM_PCIE_NO_WAKE_ENUMERATION = BIT(1)
+};
+
/* gpio info structure */
struct msm_pcie_gpio_info_t {
char *name;
@@ -629,7 +634,7 @@ struct msm_pcie_dev_t {
uint32_t perst_delay_us_max;
uint32_t tlp_rd_size;
bool linkdown_panic;
- bool ep_wakeirq;
+ uint32_t boot_option;
uint32_t rc_idx;
uint32_t phy_ver;
@@ -1947,8 +1952,8 @@ static void msm_pcie_show_status(struct msm_pcie_dev_t *dev)
dev->aer_enable ? "" : "not");
PCIE_DBG_FS(dev, "ext_ref_clk is %d\n",
dev->ext_ref_clk);
- PCIE_DBG_FS(dev, "ep_wakeirq is %d\n",
- dev->ep_wakeirq);
+ PCIE_DBG_FS(dev, "boot_option is 0x%x\n",
+ dev->boot_option);
PCIE_DBG_FS(dev, "phy_ver is %d\n",
dev->phy_ver);
PCIE_DBG_FS(dev, "drv_ready is %d\n",
@@ -2563,7 +2568,7 @@ static struct dentry *dfile_linkdown_panic;
static struct dentry *dfile_wr_offset;
static struct dentry *dfile_wr_mask;
static struct dentry *dfile_wr_value;
-static struct dentry *dfile_ep_wakeirq;
+static struct dentry *dfile_boot_option;
static struct dentry *dfile_aer_enable;
static struct dentry *dfile_corr_counter_limit;
@@ -2832,13 +2837,13 @@ const struct file_operations msm_pcie_wr_value_ops = {
.write = msm_pcie_set_wr_value,
};
-static ssize_t msm_pcie_set_ep_wakeirq(struct file *file,
+static ssize_t msm_pcie_set_boot_option(struct file *file,
const char __user *buf,
size_t count, loff_t *ppos)
{
unsigned long ret;
char str[MAX_MSG_LEN];
- u32 new_ep_wakeirq = 0;
+ u32 new_boot_option = 0;
int i;
memset(str, 0, sizeof(str));
@@ -2847,33 +2852,33 @@ static ssize_t msm_pcie_set_ep_wakeirq(struct file *file,
return -EFAULT;
for (i = 0; i < sizeof(str) && (str[i] >= '0') && (str[i] <= '9'); ++i)
- new_ep_wakeirq = (new_ep_wakeirq * 10) + (str[i] - '0');
+ new_boot_option = (new_boot_option * 10) + (str[i] - '0');
- if (new_ep_wakeirq <= 1) {
+ if (new_boot_option <= 1) {
for (i = 0; i < MAX_RC_NUM; i++) {
if (!rc_sel) {
- msm_pcie_dev[0].ep_wakeirq = new_ep_wakeirq;
+ msm_pcie_dev[0].boot_option = new_boot_option;
PCIE_DBG_FS(&msm_pcie_dev[0],
- "PCIe: RC0: ep_wakeirq is now %d\n",
- msm_pcie_dev[0].ep_wakeirq);
+ "PCIe: RC0: boot_option is now 0x%x\n",
+ msm_pcie_dev[0].boot_option);
break;
} else if (rc_sel & (1 << i)) {
- msm_pcie_dev[i].ep_wakeirq = new_ep_wakeirq;
+ msm_pcie_dev[i].boot_option = new_boot_option;
PCIE_DBG_FS(&msm_pcie_dev[i],
- "PCIe: RC%d: ep_wakeirq is now %d\n",
- i, msm_pcie_dev[i].ep_wakeirq);
+ "PCIe: RC%d: boot_option is now 0x%x\n",
+ i, msm_pcie_dev[i].boot_option);
}
}
} else {
- pr_err("PCIe: Invalid input for ep_wakeirq: %d. Please enter 0 or 1.\n",
- new_ep_wakeirq);
+ pr_err("PCIe: Invalid input for boot_option: 0x%x.\n",
+ new_boot_option);
}
return count;
}
-const struct file_operations msm_pcie_ep_wakeirq_ops = {
- .write = msm_pcie_set_ep_wakeirq,
+const struct file_operations msm_pcie_boot_option_ops = {
+ .write = msm_pcie_set_boot_option,
};
static ssize_t msm_pcie_set_aer_enable(struct file *file,
@@ -3026,12 +3031,12 @@ static void msm_pcie_debugfs_init(void)
goto wr_value_error;
}
- dfile_ep_wakeirq = debugfs_create_file("ep_wakeirq", 0664,
+ dfile_boot_option = debugfs_create_file("boot_option", 0664,
dent_msm_pcie, 0,
- &msm_pcie_ep_wakeirq_ops);
- if (!dfile_ep_wakeirq || IS_ERR(dfile_ep_wakeirq)) {
- pr_err("PCIe: fail to create the file for debug_fs ep_wakeirq.\n");
- goto ep_wakeirq_error;
+ &msm_pcie_boot_option_ops);
+ if (!dfile_boot_option || IS_ERR(dfile_boot_option)) {
+ pr_err("PCIe: fail to create the file for debug_fs boot_option.\n");
+ goto boot_option_error;
}
dfile_aer_enable = debugfs_create_file("aer_enable", 0664,
@@ -3054,8 +3059,8 @@ static void msm_pcie_debugfs_init(void)
corr_counter_limit_error:
debugfs_remove(dfile_aer_enable);
aer_enable_error:
- debugfs_remove(dfile_ep_wakeirq);
-ep_wakeirq_error:
+ debugfs_remove(dfile_boot_option);
+boot_option_error:
debugfs_remove(dfile_wr_value);
wr_value_error:
debugfs_remove(dfile_wr_mask);
@@ -3082,7 +3087,7 @@ static void msm_pcie_debugfs_exit(void)
debugfs_remove(dfile_wr_offset);
debugfs_remove(dfile_wr_mask);
debugfs_remove(dfile_wr_value);
- debugfs_remove(dfile_ep_wakeirq);
+ debugfs_remove(dfile_boot_option);
debugfs_remove(dfile_aer_enable);
debugfs_remove(dfile_corr_counter_limit);
}
@@ -3313,7 +3318,7 @@ static inline int msm_pcie_oper_conf(struct pci_bus *bus, u32 devfn, int oper,
word_offset = where & ~0x3;
byte_offset = where & 0x3;
- mask = (~0 >> (8 * (4 - size))) << (8 * byte_offset);
+ mask = ((u32)~0 >> (8 * (4 - size))) << (8 * byte_offset);
if (rc || !dev->enumerated) {
config_base = rc ? dev->dm_core : dev->conf;
@@ -3348,12 +3353,17 @@ static inline int msm_pcie_oper_conf(struct pci_bus *bus, u32 devfn, int oper,
writel_relaxed(wr_val, config_base + word_offset);
wmb(); /* ensure config data is written to hardware register */
- if (rd_val == PCIE_LINK_DOWN)
- PCIE_ERR(dev,
- "Read of RC%d %d:0x%02x + 0x%04x[%d] is all FFs\n",
- rc_idx, bus->number, devfn, where, size);
- else if (dev->shadow_en)
- msm_pcie_save_shadow(dev, word_offset, wr_val, bdf, rc);
+ if (dev->shadow_en) {
+ if (rd_val == PCIE_LINK_DOWN &&
+ (readl_relaxed(config_base) == PCIE_LINK_DOWN))
+ PCIE_ERR(dev,
+ "Read of RC%d %d:0x%02x + 0x%04x[%d] is all FFs\n",
+ rc_idx, bus->number, devfn,
+ where, size);
+ else
+ msm_pcie_save_shadow(dev, word_offset, wr_val,
+ bdf, rc);
+ }
PCIE_DBG3(dev,
"RC%d %d:0x%02x + 0x%04x[%d] <- 0x%08x; rd 0x%08x val 0x%08x\n",
@@ -5411,14 +5421,10 @@ static irqreturn_t handle_wake_irq(int irq, void *data)
PCIE_DBG2(dev, "PCIe WAKE is asserted by Endpoint of RC%d\n",
dev->rc_idx);
- if (!dev->enumerated) {
- PCIE_DBG(dev, "Start enumeating RC%d\n", dev->rc_idx);
- if (dev->ep_wakeirq)
- schedule_work(&dev->handle_wake_work);
- else
- PCIE_DBG(dev,
- "wake irq is received but ep_wakeirq is not supported for RC%d.\n",
- dev->rc_idx);
+ if (!dev->enumerated && !(dev->boot_option &
+ MSM_PCIE_NO_WAKE_ENUMERATION)) {
+ PCIE_DBG(dev, "Start enumerating RC%d\n", dev->rc_idx);
+ schedule_work(&dev->handle_wake_work);
} else {
PCIE_DBG2(dev, "Wake up RC%d\n", dev->rc_idx);
__pm_stay_awake(&dev->ws);
@@ -6200,12 +6206,12 @@ static int msm_pcie_probe(struct platform_device *pdev)
msm_pcie_dev[rc_idx].rc_idx,
msm_pcie_dev[rc_idx].smmu_sid_base);
- msm_pcie_dev[rc_idx].ep_wakeirq =
- of_property_read_bool((&pdev->dev)->of_node,
- "qcom,ep-wakeirq");
+ msm_pcie_dev[rc_idx].boot_option = 0;
+ ret = of_property_read_u32((&pdev->dev)->of_node, "qcom,boot-option",
+ &msm_pcie_dev[rc_idx].boot_option);
PCIE_DBG(&msm_pcie_dev[rc_idx],
- "PCIe: EP of RC%d does %s assert wake when it is up.\n",
- rc_idx, msm_pcie_dev[rc_idx].ep_wakeirq ? "" : "not");
+ "PCIe: RC%d boot option is 0x%x.\n",
+ rc_idx, msm_pcie_dev[rc_idx].boot_option);
msm_pcie_dev[rc_idx].phy_ver = 1;
ret = of_property_read_u32((&pdev->dev)->of_node,
@@ -6484,9 +6490,10 @@ static int msm_pcie_probe(struct platform_device *pdev)
msm_pcie_dev[rc_idx].drv_ready = true;
- if (msm_pcie_dev[rc_idx].ep_wakeirq) {
+ if (msm_pcie_dev[rc_idx].boot_option &
+ MSM_PCIE_NO_PROBE_ENUMERATION) {
PCIE_DBG(&msm_pcie_dev[rc_idx],
- "PCIe: RC%d will be enumerated upon WAKE signal from Endpoint.\n",
+ "PCIe: RC%d will be enumerated by client or endpoint.\n",
rc_idx);
mutex_unlock(&pcie_drv.drv_lock);
return 0;
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa.c b/drivers/platform/msm/ipa/ipa_v2/ipa.c
index 553480660722..100bbd582a5e 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa.c
@@ -3848,11 +3848,8 @@ static int ipa_init(const struct ipa_plat_drv_res *resource_p,
}
ipa_ctx->logbuf = ipc_log_context_create(IPA_IPC_LOG_PAGES, "ipa", 0);
- if (ipa_ctx->logbuf == NULL) {
- IPAERR("failed to get logbuf\n");
- result = -ENOMEM;
- goto fail_logbuf;
- }
+ if (ipa_ctx->logbuf == NULL)
+ IPAERR("failed to create IPC log, continue...\n");
ipa_ctx->pdev = ipa_dev;
ipa_ctx->uc_pdev = ipa_dev;
@@ -4390,8 +4387,8 @@ fail_bus_reg:
fail_bind:
kfree(ipa_ctx->ctrl);
fail_mem_ctrl:
- ipc_log_context_destroy(ipa_ctx->logbuf);
-fail_logbuf:
+ if (ipa_ctx->logbuf)
+ ipc_log_context_destroy(ipa_ctx->logbuf);
kfree(ipa_ctx);
ipa_ctx = NULL;
fail_mem_ctx:
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c
index 5b706b6f493b..ddff50834f03 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c
@@ -4264,11 +4264,8 @@ static int ipa3_pre_init(const struct ipa3_plat_drv_res *resource_p,
}
ipa3_ctx->logbuf = ipc_log_context_create(IPA_IPC_LOG_PAGES, "ipa", 0);
- if (ipa3_ctx->logbuf == NULL) {
- IPAERR("failed to get logbuf\n");
- result = -ENOMEM;
- goto fail_logbuf;
- }
+ if (ipa3_ctx->logbuf == NULL)
+ IPAERR("failed to create IPC log, continue...\n");
ipa3_ctx->pdev = ipa_dev;
ipa3_ctx->uc_pdev = ipa_dev;
@@ -4769,8 +4766,8 @@ fail_bind:
fail_mem_ctrl:
kfree(ipa3_ctx->ipa_tz_unlock_reg);
fail_tz_unlock_reg:
- ipc_log_context_destroy(ipa3_ctx->logbuf);
-fail_logbuf:
+ if (ipa3_ctx->logbuf)
+ ipc_log_context_destroy(ipa3_ctx->logbuf);
kfree(ipa3_ctx);
ipa3_ctx = NULL;
fail_mem_ctx:
diff --git a/drivers/platform/msm/mhi_uci/mhi_uci.c b/drivers/platform/msm/mhi_uci/mhi_uci.c
index ab3c3503c2fc..3191ec065a95 100644
--- a/drivers/platform/msm/mhi_uci/mhi_uci.c
+++ b/drivers/platform/msm/mhi_uci/mhi_uci.c
@@ -1185,9 +1185,43 @@ static void uci_xfer_cb(struct mhi_cb_info *cb_info)
mutex_unlock(&chan_attr->chan_lock);
wake_up(&chan_attr->wq);
break;
+ case MHI_CB_SYS_ERROR:
+ case MHI_CB_MHI_SHUTDOWN:
case MHI_CB_MHI_DISABLED:
uci_log(uci_handle->uci_ipc_log, UCI_DBG_INFO,
- "MHI disabled CB received\n");
+ "MHI disabled CB received 0x%x for chan:%d\n",
+ cb_info->cb_reason, cb_info->chan);
+
+ chan_attr = (cb_info->chan % 2) ? &uci_handle->in_attr :
+ &uci_handle->out_attr;
+ mutex_lock(&chan_attr->chan_lock);
+ chan_attr->enabled = false;
+ /* we disable entire handler by grabbing only one lock */
+ uci_handle->enabled = false;
+ mutex_unlock(&chan_attr->chan_lock);
+ wake_up(&chan_attr->wq);
+
+ /*
+ * if it's ctrl channel clear the resource now
+ * otherwise during file close we will release the
+ * resources
+ */
+ if (uci_handle == uci_handle->uci_ctxt->ctrl_client &&
+ chan_attr == &uci_handle->out_attr) {
+ struct uci_buf *itr, *tmp;
+
+ mutex_lock(&chan_attr->chan_lock);
+ atomic_set(&uci_handle->out_attr.avail_pkts, 0);
+ atomic_set(&uci_handle->out_pkt_pend_ack, 0);
+ list_for_each_entry_safe(itr, tmp, &chan_attr->buf_head,
+ node) {
+ list_del(&itr->node);
+ kfree(itr->data);
+ }
+ atomic_set(&uci_handle->completion_ack, 0);
+ INIT_LIST_HEAD(&uci_handle->out_attr.buf_head);
+ mutex_unlock(&chan_attr->chan_lock);
+ }
break;
case MHI_CB_XFER:
if (!cb_info->result) {
diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c
index 438da2c51dd6..723b9eaf658a 100644
--- a/drivers/power/power_supply_sysfs.c
+++ b/drivers/power/power_supply_sysfs.c
@@ -293,6 +293,7 @@ static struct device_attribute power_supply_attrs[] = {
POWER_SUPPLY_ATTR(die_health),
POWER_SUPPLY_ATTR(connector_health),
POWER_SUPPLY_ATTR(ctm_current_max),
+ POWER_SUPPLY_ATTR(hw_current_max),
/* Local extensions of type int64_t */
POWER_SUPPLY_ATTR(charge_counter_ext),
/* Properties of type `const char *' */
diff --git a/drivers/power/qcom/msm-core.c b/drivers/power/qcom/msm-core.c
index 3ac4611da9bd..43ad33ea234b 100644
--- a/drivers/power/qcom/msm-core.c
+++ b/drivers/power/qcom/msm-core.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -1069,6 +1069,7 @@ static int msm_core_dev_probe(struct platform_device *pdev)
if (ret)
goto failed;
+ INIT_DEFERRABLE_WORK(&sampling_work, samplequeue_handle);
ret = msm_core_task_init(&pdev->dev);
if (ret)
goto failed;
@@ -1076,7 +1077,6 @@ static int msm_core_dev_probe(struct platform_device *pdev)
for_each_possible_cpu(cpu)
set_threshold(&activity[cpu]);
- INIT_DEFERRABLE_WORK(&sampling_work, samplequeue_handle);
schedule_delayed_work(&sampling_work, msecs_to_jiffies(0));
cpufreq_register_notifier(&cpu_policy, CPUFREQ_POLICY_NOTIFIER);
pm_notifier(system_suspend_handler, 0);
diff --git a/drivers/power/supply/qcom/battery.c b/drivers/power/supply/qcom/battery.c
index 0c80c8be7909..914a6e4eae64 100644
--- a/drivers/power/supply/qcom/battery.c
+++ b/drivers/power/supply/qcom/battery.c
@@ -13,6 +13,7 @@
#define pr_fmt(fmt) "QCOM-BATT: %s: " fmt, __func__
#include <linux/device.h>
+#include <linux/delay.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
@@ -36,6 +37,7 @@
#define PL_HW_ABSENT_VOTER "PL_HW_ABSENT_VOTER"
#define PL_VOTER "PL_VOTER"
#define RESTRICT_CHG_VOTER "RESTRICT_CHG_VOTER"
+#define ICL_CHANGE_VOTER "ICL_CHANGE_VOTER"
struct pl_data {
int pl_mode;
@@ -49,14 +51,16 @@ struct pl_data {
struct votable *pl_disable_votable;
struct votable *pl_awake_votable;
struct votable *hvdcp_hw_inov_dis_votable;
+ struct votable *usb_icl_votable;
struct work_struct status_change_work;
struct work_struct pl_disable_forever_work;
struct delayed_work pl_taper_work;
struct power_supply *main_psy;
struct power_supply *pl_psy;
struct power_supply *batt_psy;
+ struct power_supply *usb_psy;
int charge_type;
- int main_settled_ua;
+ int total_settled_ua;
int pl_settled_ua;
struct class qcom_batt_class;
struct wakeup_source *pl_ws;
@@ -92,15 +96,10 @@ enum {
********/
static void split_settled(struct pl_data *chip)
{
- int slave_icl_pct;
+ int slave_icl_pct, total_current_ua;
int slave_ua = 0, main_settled_ua = 0;
union power_supply_propval pval = {0, };
- int rc;
-
- /* TODO some parallel chargers do not have a fine ICL resolution. For
- * them implement a psy interface which returns the closest lower ICL
- * for desired split
- */
+ int rc, total_settled_ua = 0;
if ((chip->pl_mode != POWER_SUPPLY_PL_USBIN_USBIN)
&& (chip->pl_mode != POWER_SUPPLY_PL_USBIN_USBIN_EXT))
@@ -122,12 +121,31 @@ static void split_settled(struct pl_data *chip)
slave_icl_pct = max(0, chip->slave_pct - 10);
slave_ua = ((main_settled_ua + chip->pl_settled_ua)
* slave_icl_pct) / 100;
+ total_settled_ua = main_settled_ua + chip->pl_settled_ua;
}
- /* ICL_REDUCTION on main could be 0mA when pl is disabled */
- pval.intval = slave_ua;
+ total_current_ua = get_effective_result_locked(chip->usb_icl_votable);
+ if (total_current_ua < 0) {
+ if (!chip->usb_psy)
+ chip->usb_psy = power_supply_get_by_name("usb");
+ if (!chip->usb_psy) {
+ pr_err("Couldn't get usbpsy while splitting settled\n");
+ return;
+ }
+ /* no client is voting, so get the total current from charger */
+ rc = power_supply_get_property(chip->usb_psy,
+ POWER_SUPPLY_PROP_HW_CURRENT_MAX, &pval);
+ if (rc < 0) {
+ pr_err("Couldn't get max current rc=%d\n", rc);
+ return;
+ }
+ total_current_ua = pval.intval;
+ }
+
+ pval.intval = total_current_ua - slave_ua;
+ /* Set ICL on main charger */
rc = power_supply_set_property(chip->main_psy,
- POWER_SUPPLY_PROP_ICL_REDUCTION, &pval);
+ POWER_SUPPLY_PROP_CURRENT_MAX, &pval);
if (rc < 0) {
pr_err("Couldn't change slave suspend state rc=%d\n", rc);
return;
@@ -142,10 +160,12 @@ static void split_settled(struct pl_data *chip)
return;
}
- /* main_settled_ua represents the total capability of adapter */
- if (!chip->main_settled_ua)
- chip->main_settled_ua = main_settled_ua;
+ chip->total_settled_ua = total_settled_ua;
chip->pl_settled_ua = slave_ua;
+
+ pl_dbg(chip, PR_PARALLEL,
+ "Split total_current_ua=%d main_settled_ua=%d slave_ua=%d\n",
+ total_current_ua, main_settled_ua, slave_ua);
}
static ssize_t version_show(struct class *c, struct class_attribute *attr,
@@ -213,6 +233,10 @@ static ssize_t restrict_chg_store(struct class *c, struct class_attribute *attr,
chip->restricted_charging_enabled = !!val;
+ /* disable parallel charger in case of restricted charging */
+ vote(chip->pl_disable_votable, RESTRICT_CHG_VOTER,
+ chip->restricted_charging_enabled, 0);
+
vote(chip->fcc_votable, RESTRICT_CHG_VOTER,
chip->restricted_charging_enabled,
chip->restricted_current);
@@ -487,6 +511,59 @@ static int pl_fv_vote_callback(struct votable *votable, void *data,
return 0;
}
+#define ICL_STEP_UV 25000
+static int usb_icl_vote_callback(struct votable *votable, void *data,
+ int icl_ua, const char *client)
+{
+ int rc;
+ struct pl_data *chip = data;
+ union power_supply_propval pval = {0, };
+
+ if (!chip->main_psy)
+ return 0;
+
+ if (client == NULL)
+ icl_ua = INT_MAX;
+
+ /*
+ * Disable parallel for new ICL vote - the call to split_settled will
+ * ensure that all the input current limit gets assigned to the main
+ * charger.
+ */
+ vote(chip->pl_disable_votable, ICL_CHANGE_VOTER, true, 0);
+
+ /* rerun AICL */
+ /* get the settled current */
+ rc = power_supply_get_property(chip->main_psy,
+ POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED,
+ &pval);
+ if (rc < 0) {
+ pr_err("Couldn't get aicl settled value rc=%d\n", rc);
+ return rc;
+ }
+
+ /* rerun AICL if new ICL is above settled ICL */
+ if (icl_ua > pval.intval) {
+ /* set a lower ICL */
+ pval.intval = max(pval.intval - ICL_STEP_UV, ICL_STEP_UV);
+ power_supply_set_property(chip->main_psy,
+ POWER_SUPPLY_PROP_CURRENT_MAX,
+ &pval);
+ /* wait for ICL change */
+ msleep(100);
+
+ pval.intval = icl_ua;
+ power_supply_set_property(chip->main_psy,
+ POWER_SUPPLY_PROP_CURRENT_MAX,
+ &pval);
+ /* wait for ICL change */
+ msleep(100);
+ }
+ vote(chip->pl_disable_votable, ICL_CHANGE_VOTER, false, 0);
+
+ return 0;
+}
+
static void pl_disable_forever_work(struct work_struct *work)
{
struct pl_data *chip = container_of(work,
@@ -508,7 +585,7 @@ static int pl_disable_vote_callback(struct votable *votable,
int rc;
chip->taper_pct = 100;
- chip->main_settled_ua = 0;
+ chip->total_settled_ua = 0;
chip->pl_settled_ua = 0;
if (!pl_disable) { /* enable */
@@ -596,13 +673,15 @@ static int pl_awake_vote_callback(struct votable *votable,
static bool is_main_available(struct pl_data *chip)
{
- if (!chip->main_psy)
- chip->main_psy = power_supply_get_by_name("main");
+ if (chip->main_psy)
+ return true;
- if (!chip->main_psy)
- return false;
+ chip->main_psy = power_supply_get_by_name("main");
- return true;
+ if (chip->main_psy)
+ rerun_election(chip->usb_icl_votable);
+
+ return !!chip->main_psy;
}
static bool is_batt_available(struct pl_data *chip)
@@ -711,6 +790,7 @@ static void handle_main_charge_type(struct pl_data *chip)
static void handle_settled_icl_change(struct pl_data *chip)
{
union power_supply_propval pval = {0, };
+ int new_total_settled_ua;
int rc;
if (get_effective_result(chip->pl_disable_votable))
@@ -730,9 +810,15 @@ static void handle_settled_icl_change(struct pl_data *chip)
return;
}
+ new_total_settled_ua = pval.intval + chip->pl_settled_ua;
+ pl_dbg(chip, PR_PARALLEL,
+ "total_settled_ua=%d settled_ua=%d new_total_settled_ua=%d\n",
+ chip->total_settled_ua, pval.intval,
+ new_total_settled_ua);
+
/* If ICL change is small skip splitting */
- if (abs((chip->main_settled_ua - chip->pl_settled_ua)
- - pval.intval) > MIN_ICL_CHANGE_DELTA_UA)
+ if (abs(new_total_settled_ua - chip->total_settled_ua)
+ > MIN_ICL_CHANGE_DELTA_UA)
split_settled(chip);
} else {
rerun_election(chip->fcc_votable);
@@ -855,6 +941,14 @@ static int pl_init(void)
goto destroy_votable;
}
+ chip->usb_icl_votable = create_votable("USB_ICL", VOTE_MIN,
+ usb_icl_vote_callback,
+ chip);
+ if (IS_ERR(chip->usb_icl_votable)) {
+ rc = PTR_ERR(chip->usb_icl_votable);
+ goto destroy_votable;
+ }
+
chip->pl_disable_votable = create_votable("PL_DISABLE", VOTE_SET_ANY,
pl_disable_vote_callback,
chip);
@@ -909,6 +1003,7 @@ destroy_votable:
destroy_votable(chip->pl_disable_votable);
destroy_votable(chip->fv_votable);
destroy_votable(chip->fcc_votable);
+ destroy_votable(chip->usb_icl_votable);
release_wakeup_source:
wakeup_source_unregister(chip->pl_ws);
cleanup:
diff --git a/drivers/power/supply/qcom/qpnp-smb2.c b/drivers/power/supply/qcom/qpnp-smb2.c
index b4fb80a2d4f3..4dfa43012b54 100644
--- a/drivers/power/supply/qcom/qpnp-smb2.c
+++ b/drivers/power/supply/qcom/qpnp-smb2.c
@@ -414,6 +414,7 @@ static enum power_supply_property smb2_usb_props[] = {
POWER_SUPPLY_PROP_BOOST_CURRENT,
POWER_SUPPLY_PROP_PE_START,
POWER_SUPPLY_PROP_CTM_CURRENT_MAX,
+ POWER_SUPPLY_PROP_HW_CURRENT_MAX,
};
static int smb2_usb_get_prop(struct power_supply *psy,
@@ -502,6 +503,9 @@ static int smb2_usb_get_prop(struct power_supply *psy,
case POWER_SUPPLY_PROP_CTM_CURRENT_MAX:
val->intval = get_client_vote(chg->usb_icl_votable, CTM_VOTER);
break;
+ case POWER_SUPPLY_PROP_HW_CURRENT_MAX:
+ rc = smblib_get_charge_current(chg, &val->intval);
+ break;
default:
pr_err("get prop %d is not supported in usb\n", psp);
rc = -EINVAL;
@@ -610,12 +614,12 @@ static int smb2_init_usb_psy(struct smb2 *chip)
static enum power_supply_property smb2_usb_main_props[] = {
POWER_SUPPLY_PROP_VOLTAGE_MAX,
- POWER_SUPPLY_PROP_ICL_REDUCTION,
POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
POWER_SUPPLY_PROP_TYPE,
POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED,
POWER_SUPPLY_PROP_INPUT_VOLTAGE_SETTLED,
POWER_SUPPLY_PROP_FCC_DELTA,
+ POWER_SUPPLY_PROP_CURRENT_MAX,
/*
* TODO move the TEMP and TEMP_MAX properties here,
* and update the thermal balancer to look here
@@ -634,9 +638,6 @@ static int smb2_usb_main_get_prop(struct power_supply *psy,
case POWER_SUPPLY_PROP_VOLTAGE_MAX:
rc = smblib_get_charge_param(chg, &chg->param.fv, &val->intval);
break;
- case POWER_SUPPLY_PROP_ICL_REDUCTION:
- val->intval = chg->icl_reduction_ua;
- break;
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
rc = smblib_get_charge_param(chg, &chg->param.fcc,
&val->intval);
@@ -653,6 +654,9 @@ static int smb2_usb_main_get_prop(struct power_supply *psy,
case POWER_SUPPLY_PROP_FCC_DELTA:
rc = smblib_get_prop_fcc_delta(chg, val);
break;
+ case POWER_SUPPLY_PROP_CURRENT_MAX:
+ val->intval = get_effective_result(chg->usb_icl_votable);
+ break;
default:
pr_debug("get prop %d is not supported in usb-main\n", psp);
rc = -EINVAL;
@@ -677,12 +681,12 @@ static int smb2_usb_main_set_prop(struct power_supply *psy,
case POWER_SUPPLY_PROP_VOLTAGE_MAX:
rc = smblib_set_charge_param(chg, &chg->param.fv, val->intval);
break;
- case POWER_SUPPLY_PROP_ICL_REDUCTION:
- rc = smblib_set_icl_reduction(chg, val->intval);
- break;
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
rc = smblib_set_charge_param(chg, &chg->param.fcc, val->intval);
break;
+ case POWER_SUPPLY_PROP_CURRENT_MAX:
+ rc = smblib_set_icl_current(chg, val->intval);
+ break;
default:
pr_err("set prop %d is not supported\n", psp);
rc = -EINVAL;
@@ -1572,6 +1576,16 @@ static int smb2_init_hw(struct smb2 *chip)
return rc;
}
+ /* disable h/w autonomous parallel charging control */
+ rc = smblib_masked_write(chg, MISC_CFG_REG,
+ STAT_PARALLEL_1400MA_EN_CFG_BIT, 0);
+ if (rc < 0) {
+ dev_err(chg->dev,
+ "Couldn't disable h/w autonomous parallel control rc=%d\n",
+ rc);
+ return rc;
+ }
+
/* configure float charger options */
switch (chip->dt.float_option) {
case 1:
@@ -2230,6 +2244,8 @@ static int smb2_probe(struct platform_device *pdev)
}
batt_charge_type = val.intval;
+ device_init_wakeup(chg->dev, true);
+
pr_info("QPNP SMB2 probed successfully usb:present=%d type=%d batt:present = %d health = %d charge = %d\n",
usb_present, chg->usb_psy_desc.type,
batt_present, batt_health, batt_charge_type);
diff --git a/drivers/power/supply/qcom/smb-lib.c b/drivers/power/supply/qcom/smb-lib.c
index d631f49db63a..bd96703579f6 100644
--- a/drivers/power/supply/qcom/smb-lib.c
+++ b/drivers/power/supply/qcom/smb-lib.c
@@ -654,10 +654,13 @@ static void smblib_uusb_removal(struct smb_charger *chg)
{
int rc;
+ cancel_delayed_work_sync(&chg->pl_enable_work);
+ vote(chg->pl_disable_votable, PL_DELAY_VOTER, true, 0);
+ vote(chg->awake_votable, PL_DELAY_VOTER, false, 0);
+
/* reset both usbin current and voltage votes */
vote(chg->pl_enable_votable_indirect, USBIN_I_VOTER, false, 0);
vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, false, 0);
- vote(chg->pl_disable_votable, PL_DELAY_HVDCP_VOTER, true, 0);
cancel_delayed_work_sync(&chg->hvdcp_detect_work);
@@ -693,13 +696,6 @@ static void smblib_uusb_removal(struct smb_charger *chg)
if (rc < 0)
smblib_err(chg,
"Couldn't un-vote DCP from USB ICL rc=%d\n", rc);
-
- /* clear USB ICL vote for PL_USBIN_USBIN_VOTER */
- rc = vote(chg->usb_icl_votable, PL_USBIN_USBIN_VOTER, false, 0);
- if (rc < 0)
- smblib_err(chg,
- "Couldn't un-vote PL_USBIN_USBIN from USB ICL rc=%d\n",
- rc);
}
void smblib_suspend_on_debug_battery(struct smb_charger *chg)
@@ -795,29 +791,12 @@ static int smblib_get_pulse_cnt(struct smb_charger *chg, int *count)
return 0;
}
-/*********************
- * VOTABLE CALLBACKS *
- *********************/
-
-static int smblib_dc_suspend_vote_callback(struct votable *votable, void *data,
- int suspend, const char *client)
-{
- struct smb_charger *chg = data;
-
- /* resume input if suspend is invalid */
- if (suspend < 0)
- suspend = 0;
-
- return smblib_set_dc_suspend(chg, (bool)suspend);
-}
-
#define USBIN_25MA 25000
#define USBIN_100MA 100000
#define USBIN_150MA 150000
#define USBIN_500MA 500000
#define USBIN_900MA 900000
-
static int set_sdp_current(struct smb_charger *chg, int icl_ua)
{
int rc;
@@ -856,20 +835,18 @@ static int set_sdp_current(struct smb_charger *chg, int icl_ua)
return rc;
}
-static int smblib_usb_icl_vote_callback(struct votable *votable, void *data,
- int icl_ua, const char *client)
+int smblib_set_icl_current(struct smb_charger *chg, int icl_ua)
{
- struct smb_charger *chg = data;
int rc = 0;
bool override;
union power_supply_propval pval;
/* suspend and return if 25mA or less is requested */
- if (client && (icl_ua < USBIN_25MA))
+ if (icl_ua < USBIN_25MA)
return smblib_set_usb_suspend(chg, true);
disable_irq_nosync(chg->irq_info[USBIN_ICL_CHANGE_IRQ].irq);
- if (!client)
+ if (icl_ua == INT_MAX)
goto override_suspend_config;
rc = smblib_get_prop_typec_mode(chg, &pval);
@@ -887,8 +864,7 @@ static int smblib_usb_icl_vote_callback(struct votable *votable, void *data,
goto enable_icl_changed_interrupt;
}
} else {
- rc = smblib_set_charge_param(chg, &chg->param.usb_icl,
- icl_ua - chg->icl_reduction_ua);
+ rc = smblib_set_charge_param(chg, &chg->param.usb_icl, icl_ua);
if (rc < 0) {
smblib_err(chg, "Couldn't set HC ICL rc=%d\n", rc);
goto enable_icl_changed_interrupt;
@@ -898,7 +874,7 @@ static int smblib_usb_icl_vote_callback(struct votable *votable, void *data,
override_suspend_config:
/* determine if override needs to be enforced */
override = true;
- if (client == NULL) {
+ if (icl_ua == INT_MAX) {
/* remove override if no voters - hw defaults is desired */
override = false;
} else if (pval.intval == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT) {
@@ -906,7 +882,7 @@ override_suspend_config:
/* For std cable with type = SDP never override */
override = false;
else if (chg->usb_psy_desc.type == POWER_SUPPLY_TYPE_USB_CDP
- && icl_ua - chg->icl_reduction_ua == 1500000)
+ && icl_ua == 1500000)
/*
* For std cable with type = CDP override only if
* current is not 1500mA
@@ -936,6 +912,22 @@ enable_icl_changed_interrupt:
return rc;
}
+/*********************
+ * VOTABLE CALLBACKS *
+ *********************/
+
+static int smblib_dc_suspend_vote_callback(struct votable *votable, void *data,
+ int suspend, const char *client)
+{
+ struct smb_charger *chg = data;
+
+ /* resume input if suspend is invalid */
+ if (suspend < 0)
+ suspend = 0;
+
+ return smblib_set_dc_suspend(chg, (bool)suspend);
+}
+
static int smblib_dc_icl_vote_callback(struct votable *votable, void *data,
int icl_ua, const char *client)
{
@@ -1793,6 +1785,10 @@ int smblib_set_prop_system_temp_level(struct smb_charger *chg,
return -EINVAL;
chg->system_temp_level = val->intval;
+ /* disable parallel charge in case of system temp level */
+ vote(chg->pl_disable_votable, THERMAL_DAEMON_VOTER,
+ chg->system_temp_level ? true : false, 0);
+
if (chg->system_temp_level == chg->thermal_levels)
return vote(chg->chg_disable_votable,
THERMAL_DAEMON_VOTER, true, 0);
@@ -2027,7 +2023,7 @@ int smblib_get_prop_usb_online(struct smb_charger *chg,
int rc = 0;
u8 stat;
- if (get_client_vote(chg->usb_icl_votable, USER_VOTER) == 0) {
+ if (get_client_vote_locked(chg->usb_icl_votable, USER_VOTER) == 0) {
val->intval = false;
return rc;
}
@@ -2605,29 +2601,12 @@ int smblib_set_prop_pd_active(struct smb_charger *chg,
"Couldn't un-vote DCP from USB ICL rc=%d\n",
rc);
- /* clear USB ICL vote for PL_USBIN_USBIN_VOTER */
- rc = vote(chg->usb_icl_votable, PL_USBIN_USBIN_VOTER, false, 0);
- if (rc < 0)
- smblib_err(chg,
- "Couldn't un-vote PL_USBIN_USBIN from USB ICL rc=%d\n",
- rc);
-
/* remove USB_PSY_VOTER */
rc = vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0);
if (rc < 0) {
smblib_err(chg, "Couldn't unvote USB_PSY rc=%d\n", rc);
return rc;
}
-
- /* pd active set, parallel charger can be enabled now */
- rc = vote(chg->pl_disable_votable, PL_DELAY_HVDCP_VOTER,
- false, 0);
- if (rc < 0) {
- smblib_err(chg,
- "Couldn't unvote PL_DELAY_HVDCP_VOTER rc=%d\n",
- rc);
- return rc;
- }
}
/* CC pin selection s/w override in PD session; h/w otherwise. */
@@ -2876,15 +2855,21 @@ int smblib_get_prop_fcc_delta(struct smb_charger *chg,
#define TYPEC_DEFAULT_CURRENT_MA 900000
#define TYPEC_MEDIUM_CURRENT_MA 1500000
#define TYPEC_HIGH_CURRENT_MA 3000000
-static int smblib_get_charge_current(struct smb_charger *chg,
+int smblib_get_charge_current(struct smb_charger *chg,
int *total_current_ua)
{
const struct apsd_result *apsd_result = smblib_update_usb_type(chg);
union power_supply_propval val = {0, };
- int rc, typec_source_rd, current_ua;
+ int rc = 0, typec_source_rd, current_ua;
bool non_compliant;
u8 stat5;
+ if (chg->pd_active) {
+ *total_current_ua =
+ get_client_vote_locked(chg->usb_icl_votable, PD_VOTER);
+ return rc;
+ }
+
rc = smblib_read(chg, TYPE_C_STATUS_5_REG, &stat5);
if (rc < 0) {
smblib_err(chg, "Couldn't read TYPE_C_STATUS_5 rc=%d\n", rc);
@@ -2959,39 +2944,12 @@ static int smblib_get_charge_current(struct smb_charger *chg,
return 0;
}
-int smblib_set_icl_reduction(struct smb_charger *chg, int reduction_ua)
-{
- int current_ua, rc;
-
- if (reduction_ua == 0) {
- vote(chg->usb_icl_votable, PL_USBIN_USBIN_VOTER, false, 0);
- } else {
- /*
- * No usb_icl voter means we are defaulting to hw chosen
- * max limit. We need a vote from s/w to enforce the reduction.
- */
- if (get_effective_result(chg->usb_icl_votable) == -EINVAL) {
- rc = smblib_get_charge_current(chg, &current_ua);
- if (rc < 0) {
- pr_err("Failed to get ICL rc=%d\n", rc);
- return rc;
- }
- vote(chg->usb_icl_votable, PL_USBIN_USBIN_VOTER, true,
- current_ua);
- }
- }
-
- chg->icl_reduction_ua = reduction_ua;
-
- return rerun_election(chg->usb_icl_votable);
-}
-
/************************
* PARALLEL PSY GETTERS *
************************/
int smblib_get_prop_slave_current_now(struct smb_charger *chg,
- union power_supply_propval *pval)
+ union power_supply_propval *pval)
{
if (IS_ERR_OR_NULL(chg->iio.batt_i_chan))
chg->iio.batt_i_chan = iio_channel_get(chg->dev, "batt_i");
@@ -3054,7 +3012,7 @@ irqreturn_t smblib_handle_chg_state_change(int irq, void *data)
rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat);
if (rc < 0) {
smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
- rc);
+ rc);
return IRQ_HANDLED;
}
@@ -3159,6 +3117,7 @@ irqreturn_t smblib_handle_usbin_uv(int irq, void *data)
return IRQ_HANDLED;
}
+#define PL_DELAY_MS 30000
irqreturn_t smblib_handle_usb_plugin(int irq, void *data)
{
struct smb_irq_data *irq_data = data;
@@ -3197,6 +3156,11 @@ irqreturn_t smblib_handle_usb_plugin(int irq, void *data)
smblib_err(chg, "Couldn't enable dpdm regulator rc=%d\n",
rc);
}
+
+ /* Schedule work to enable parallel charger */
+ vote(chg->awake_votable, PL_DELAY_VOTER, true, 0);
+ schedule_delayed_work(&chg->pl_enable_work,
+ msecs_to_jiffies(PL_DELAY_MS));
} else {
if (chg->wa_flags & BOOST_BACK_WA)
vote(chg->usb_icl_votable, BOOST_BACK_VOTER, false, 0);
@@ -3374,9 +3338,6 @@ static void smblib_handle_hvdcp_3p0_auth_done(struct smb_charger *chg,
}
}
- /* QC authentication done, parallel charger can be enabled now */
- vote(chg->pl_disable_votable, PL_DELAY_HVDCP_VOTER, false, 0);
-
smblib_dbg(chg, PR_INTERRUPT, "IRQ: hvdcp-3p0-auth-done rising; %s detected\n",
apsd_result->name);
}
@@ -3406,15 +3367,6 @@ 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 adapter is not QC2.0/QC3.0 remove vote for parallel
- * disable.
- * Otherwise if adapter is QC2.0/QC3.0 wait for authentication
- * to complete.
- */
- if (!qc_charger)
- vote(chg->pl_disable_votable, PL_DELAY_HVDCP_VOTER,
- false, 0);
}
smblib_dbg(chg, PR_INTERRUPT, "IRQ: smblib_handle_hvdcp_check_timeout %s\n",
@@ -3486,13 +3438,9 @@ static void smblib_handle_apsd_done(struct smb_charger *chg, bool rising)
true);
case OCP_CHARGER_BIT:
case FLOAT_CHARGER_BIT:
- /*
- * if not DCP then no hvdcp timeout happens. Enable
- * pd/parallel here.
- */
+ /* if not DCP then no hvdcp timeout happens, Enable pd here. */
vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
false, 0);
- vote(chg->pl_disable_votable, PL_DELAY_HVDCP_VOTER, false, 0);
break;
case DCP_CHARGER_BIT:
if (chg->wa_flags & QC_CHARGER_DETECTION_WA_BIT)
@@ -3604,12 +3552,6 @@ static void typec_source_removal(struct smb_charger *chg)
smblib_err(chg,
"Couldn't un-vote DCP from USB ICL rc=%d\n", rc);
- /* clear USB ICL vote for PL_USBIN_USBIN_VOTER */
- rc = vote(chg->usb_icl_votable, PL_USBIN_USBIN_VOTER, false, 0);
- if (rc < 0)
- smblib_err(chg,
- "Couldn't un-vote PL_USBIN_USBIN from USB ICL rc=%d\n",
- rc);
}
static void typec_source_insertion(struct smb_charger *chg)
@@ -3645,9 +3587,12 @@ static void smblib_handle_typec_removal(struct smb_charger *chg)
{
int rc;
+ cancel_delayed_work_sync(&chg->pl_enable_work);
+ vote(chg->pl_disable_votable, PL_DELAY_VOTER, true, 0);
+ vote(chg->awake_votable, PL_DELAY_VOTER, false, 0);
+
vote(chg->pd_disallowed_votable_indirect, CC_DETACHED_VOTER, true, 0);
vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER, true, 0);
- vote(chg->pl_disable_votable, PL_DELAY_HVDCP_VOTER, true, 0);
vote(chg->usb_irq_enable_votable, PD_VOTER, false, 0);
vote(chg->usb_irq_enable_votable, QC_VOTER, false, 0);
@@ -3703,8 +3648,6 @@ static void smblib_handle_typec_insertion(struct smb_charger *chg,
if (rp == POWER_SUPPLY_TYPEC_SOURCE_HIGH
|| rp == POWER_SUPPLY_TYPEC_NON_COMPLIANT) {
smblib_dbg(chg, PR_MISC, "VBUS & CC could be shorted; keeping HVDCP disabled\n");
- /* HVDCP is not going to be enabled; enable parallel */
- vote(chg->pl_disable_votable, PL_DELAY_HVDCP_VOTER, false, 0);
vote(chg->hvdcp_disable_votable_indirect, VBUS_CC_SHORT_VOTER,
true, 0);
} else {
@@ -4210,6 +4153,16 @@ static void smblib_icl_change_work(struct work_struct *work)
smblib_dbg(chg, PR_INTERRUPT, "icl_settled=%d\n", settled_ua);
}
+static void smblib_pl_enable_work(struct work_struct *work)
+{
+ struct smb_charger *chg = container_of(work, struct smb_charger,
+ pl_enable_work.work);
+
+ smblib_dbg(chg, PR_PARALLEL, "timer expired, enabling parallel\n");
+ vote(chg->pl_disable_votable, PL_DELAY_VOTER, false, 0);
+ vote(chg->awake_votable, PL_DELAY_VOTER, false, 0);
+}
+
static int smblib_create_votables(struct smb_charger *chg)
{
int rc = 0;
@@ -4226,13 +4179,19 @@ static int smblib_create_votables(struct smb_charger *chg)
return rc;
}
+ chg->usb_icl_votable = find_votable("USB_ICL");
+ if (!chg->usb_icl_votable) {
+ rc = -EPROBE_DEFER;
+ return rc;
+ }
+
chg->pl_disable_votable = find_votable("PL_DISABLE");
if (!chg->pl_disable_votable) {
rc = -EPROBE_DEFER;
return rc;
}
vote(chg->pl_disable_votable, PL_INDIRECT_VOTER, true, 0);
- vote(chg->pl_disable_votable, PL_DELAY_HVDCP_VOTER, true, 0);
+ vote(chg->pl_disable_votable, PL_DELAY_VOTER, true, 0);
chg->dc_suspend_votable = create_votable("DC_SUSPEND", VOTE_SET_ANY,
smblib_dc_suspend_vote_callback,
@@ -4242,14 +4201,6 @@ static int smblib_create_votables(struct smb_charger *chg)
return rc;
}
- chg->usb_icl_votable = create_votable("USB_ICL", VOTE_MIN,
- smblib_usb_icl_vote_callback,
- chg);
- if (IS_ERR(chg->usb_icl_votable)) {
- rc = PTR_ERR(chg->usb_icl_votable);
- return rc;
- }
-
chg->dc_icl_votable = create_votable("DC_ICL", VOTE_MIN,
smblib_dc_icl_vote_callback,
chg);
@@ -4400,6 +4351,7 @@ int smblib_init(struct smb_charger *chg)
INIT_WORK(&chg->vconn_oc_work, smblib_vconn_oc_work);
INIT_DELAYED_WORK(&chg->otg_ss_done_work, smblib_otg_ss_done_work);
INIT_DELAYED_WORK(&chg->icl_change_work, smblib_icl_change_work);
+ INIT_DELAYED_WORK(&chg->pl_enable_work, smblib_pl_enable_work);
chg->fake_capacity = -EINVAL;
switch (chg->mode) {
diff --git a/drivers/power/supply/qcom/smb-lib.h b/drivers/power/supply/qcom/smb-lib.h
index 048e7c2b4091..49b9d3da783c 100644
--- a/drivers/power/supply/qcom/smb-lib.h
+++ b/drivers/power/supply/qcom/smb-lib.h
@@ -56,7 +56,7 @@ enum print_reason {
#define MICRO_USB_VOTER "MICRO_USB_VOTER"
#define DEBUG_BOARD_VOTER "DEBUG_BOARD_VOTER"
#define PD_SUSPEND_SUPPORTED_VOTER "PD_SUSPEND_SUPPORTED_VOTER"
-#define PL_DELAY_HVDCP_VOTER "PL_DELAY_HVDCP_VOTER"
+#define PL_DELAY_VOTER "PL_DELAY_VOTER"
#define CTM_VOTER "CTM_VOTER"
#define SW_QC3_VOTER "SW_QC3_VOTER"
#define AICL_RERUN_VOTER "AICL_RERUN_VOTER"
@@ -288,6 +288,7 @@ struct smb_charger {
struct work_struct vconn_oc_work;
struct delayed_work otg_ss_done_work;
struct delayed_work icl_change_work;
+ struct delayed_work pl_enable_work;
/* cached status */
int voltage_min_uv;
@@ -321,8 +322,6 @@ struct smb_charger {
/* extcon for VBUS / ID notification to USB for uUSB */
struct extcon_dev *extcon;
- int icl_reduction_ua;
-
/* qnovo */
int qnovo_fcc_ua;
int qnovo_fv_uv;
@@ -488,9 +487,10 @@ int smblib_rerun_apsd_if_required(struct smb_charger *chg);
int smblib_get_prop_fcc_delta(struct smb_charger *chg,
union power_supply_propval *val);
int smblib_icl_override(struct smb_charger *chg, bool override);
-int smblib_set_icl_reduction(struct smb_charger *chg, int reduction_ua);
int smblib_dp_dm(struct smb_charger *chg, int val);
int smblib_rerun_aicl(struct smb_charger *chg);
+int smblib_set_icl_current(struct smb_charger *chg, int icl_ua);
+int smblib_get_charge_current(struct smb_charger *chg, int *total_current_ua);
int smblib_init(struct smb_charger *chg);
int smblib_deinit(struct smb_charger *chg);
diff --git a/drivers/power/supply/qcom/smb-reg.h b/drivers/power/supply/qcom/smb-reg.h
index b79060094cf6..167666a8c548 100644
--- a/drivers/power/supply/qcom/smb-reg.h
+++ b/drivers/power/supply/qcom/smb-reg.h
@@ -919,6 +919,7 @@ enum {
#define MISC_CFG_REG (MISC_BASE + 0x52)
#define GSM_PA_ON_ADJ_SEL_BIT BIT(0)
+#define STAT_PARALLEL_1400MA_EN_CFG_BIT BIT(3)
#define TCC_DEBOUNCE_20MS_BIT BIT(5)
#define SNARL_BARK_BITE_WD_CFG_REG (MISC_BASE + 0x53)
diff --git a/drivers/power/supply/qcom/smb1351-charger.c b/drivers/power/supply/qcom/smb1351-charger.c
index 8467d167512f..7014fd706d9e 100644
--- a/drivers/power/supply/qcom/smb1351-charger.c
+++ b/drivers/power/supply/qcom/smb1351-charger.c
@@ -1655,7 +1655,7 @@ static int smb1351_parallel_get_property(struct power_supply *psy,
switch (prop) {
case POWER_SUPPLY_PROP_CHARGING_ENABLED:
- val->intval = !chip->usb_suspended_status;
+ val->intval = !chip->parallel_charger_suspended;
break;
case POWER_SUPPLY_PROP_CURRENT_MAX:
if (!chip->parallel_charger_suspended)
diff --git a/drivers/power/supply/qcom/smb138x-charger.c b/drivers/power/supply/qcom/smb138x-charger.c
index 4916c87aced8..694591c3ec56 100644
--- a/drivers/power/supply/qcom/smb138x-charger.c
+++ b/drivers/power/supply/qcom/smb138x-charger.c
@@ -577,13 +577,15 @@ static int smb138x_parallel_get_prop(struct power_supply *psy,
rc = smblib_get_usb_suspend(chg, &val->intval);
break;
case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED:
- if (chip->dt.pl_mode == POWER_SUPPLY_PL_USBIN_USBIN)
+ if ((chip->dt.pl_mode == POWER_SUPPLY_PL_USBIN_USBIN)
+ || (chip->dt.pl_mode == POWER_SUPPLY_PL_USBIN_USBIN_EXT))
rc = smblib_get_prop_input_current_limited(chg, val);
else
val->intval = 0;
break;
case POWER_SUPPLY_PROP_CURRENT_MAX:
- if (chip->dt.pl_mode == POWER_SUPPLY_PL_USBIN_USBIN)
+ if ((chip->dt.pl_mode == POWER_SUPPLY_PL_USBIN_USBIN)
+ || (chip->dt.pl_mode == POWER_SUPPLY_PL_USBIN_USBIN_EXT))
rc = smblib_get_charge_param(chg, &chg->param.usb_icl,
&val->intval);
else
@@ -669,7 +671,8 @@ static int smb138x_parallel_set_prop(struct power_supply *psy,
rc = smb138x_set_parallel_suspend(chip, (bool)val->intval);
break;
case POWER_SUPPLY_PROP_CURRENT_MAX:
- if (chip->dt.pl_mode == POWER_SUPPLY_PL_USBIN_USBIN)
+ if ((chip->dt.pl_mode == POWER_SUPPLY_PL_USBIN_USBIN)
+ || (chip->dt.pl_mode == POWER_SUPPLY_PL_USBIN_USBIN_EXT))
rc = smblib_set_charge_param(chg, &chg->param.usb_icl,
val->intval);
break;
@@ -1484,7 +1487,8 @@ static int smb138x_slave_probe(struct smb138x *chip)
goto cleanup;
}
- if (chip->dt.pl_mode == POWER_SUPPLY_PL_USBIN_USBIN) {
+ if ((chip->dt.pl_mode == POWER_SUPPLY_PL_USBIN_USBIN)
+ || (chip->dt.pl_mode == POWER_SUPPLY_PL_USBIN_USBIN_EXT)) {
rc = smb138x_init_vbus_regulator(chip);
if (rc < 0) {
pr_err("Couldn't initialize vbus regulator rc=%d\n",
diff --git a/drivers/pps/clients/pps-gpio.c b/drivers/pps/clients/pps-gpio.c
index 333ad7d5b45b..da72b0b59c3a 100644
--- a/drivers/pps/clients/pps-gpio.c
+++ b/drivers/pps/clients/pps-gpio.c
@@ -57,7 +57,7 @@ static irqreturn_t pps_gpio_irq_handler(int irq, void *data)
int rising_edge;
/* Get the time stamp first */
- pps_get_ts(&ts);
+ get_monotonic_boottime(&ts.ts_real);
info = data;
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index d5c00951cf93..5d81bcc1dc75 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -2806,10 +2806,10 @@ static int sd_revalidate_disk(struct gendisk *disk)
if (sdkp->opt_xfer_blocks &&
sdkp->opt_xfer_blocks <= dev_max &&
sdkp->opt_xfer_blocks <= SD_DEF_XFER_BLOCKS &&
- logical_to_bytes(sdp, sdkp->opt_xfer_blocks) >= PAGE_CACHE_SIZE) {
- q->limits.io_opt = logical_to_bytes(sdp, sdkp->opt_xfer_blocks);
- rw_max = logical_to_sectors(sdp, sdkp->opt_xfer_blocks);
- } else
+ sdkp->opt_xfer_blocks * sdp->sector_size >= PAGE_CACHE_SIZE)
+ rw_max = q->limits.io_opt =
+ sdkp->opt_xfer_blocks * sdp->sector_size;
+ else
rw_max = BLK_DEF_MAX_SECTORS;
/* Combine with controller limits */
diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h
index 765a6f1ac1b7..654630bb7d0e 100644
--- a/drivers/scsi/sd.h
+++ b/drivers/scsi/sd.h
@@ -151,11 +151,6 @@ static inline sector_t logical_to_sectors(struct scsi_device *sdev, sector_t blo
return blocks << (ilog2(sdev->sector_size) - 9);
}
-static inline unsigned int logical_to_bytes(struct scsi_device *sdev, sector_t blocks)
-{
- return blocks * sdev->sector_size;
-}
-
/*
* A DIF-capable target device can be formatted with different
* protection schemes. Currently 0 through 3 are defined:
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 3e858015813f..79bb3337ba36 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -4289,15 +4289,25 @@ static int __ufshcd_uic_hibern8_enter(struct ufs_hba *hba)
* mode hence full reinit is required to move link to HS speeds.
*/
if (ret || hba->full_init_linereset) {
+ int err;
+
hba->full_init_linereset = false;
ufshcd_update_error_stats(hba, UFS_ERR_HIBERN8_ENTER);
dev_err(hba->dev, "%s: hibern8 enter failed. ret = %d",
__func__, ret);
/*
- * If link recovery fails then return error so that caller
- * don't retry the hibern8 enter again.
+ * If link recovery fails then return error code (-ENOLINK)
+ * returned ufshcd_link_recovery().
+ * If link recovery succeeds then return -EAGAIN to attempt
+ * hibern8 enter retry again.
*/
- ret = ufshcd_link_recovery(hba);
+ err = ufshcd_link_recovery(hba);
+ if (err) {
+ dev_err(hba->dev, "%s: link recovery failed", __func__);
+ ret = err;
+ } else {
+ ret = -EAGAIN;
+ }
} else {
dev_dbg(hba->dev, "%s: Hibern8 Enter at %lld us", __func__,
ktime_to_us(ktime_get()));
@@ -4314,8 +4324,8 @@ int ufshcd_uic_hibern8_enter(struct ufs_hba *hba)
ret = __ufshcd_uic_hibern8_enter(hba);
if (!ret)
goto out;
- /* Unable to recover the link, so no point proceeding */
- if (ret == -ENOLINK)
+ else if (ret != -EAGAIN)
+ /* Unable to recover the link, so no point proceeding */
BUG();
}
out:
diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c
index 0b35caa86d51..ab46eb70651c 100644
--- a/drivers/soc/qcom/icnss.c
+++ b/drivers/soc/qcom/icnss.c
@@ -2110,7 +2110,6 @@ static int icnss_driver_event_register_driver(void *data)
power_off:
icnss_hw_power_off(penv);
- penv->ops = NULL;
out:
return ret;
}
@@ -2646,7 +2645,7 @@ int icnss_register_driver(struct icnss_driver_ops *ops)
}
ret = icnss_driver_event_post(ICNSS_DRIVER_EVENT_REGISTER_DRIVER,
- ICNSS_EVENT_SYNC, ops);
+ 0, ops);
if (ret == -EINTR)
ret = 0;
diff --git a/drivers/soc/qcom/msm_glink_pkt.c b/drivers/soc/qcom/msm_glink_pkt.c
index 78f6a2aa8f66..a92e5c416678 100644
--- a/drivers/soc/qcom/msm_glink_pkt.c
+++ b/drivers/soc/qcom/msm_glink_pkt.c
@@ -625,14 +625,17 @@ ssize_t glink_pkt_read(struct file *file,
return -ENETRESET;
}
+ mutex_lock(&devp->ch_lock);
if (!glink_rx_intent_exists(devp->handle, count)) {
ret = glink_queue_rx_intent(devp->handle, devp, count);
if (ret) {
GLINK_PKT_ERR("%s: failed to queue_rx_intent ret[%d]\n",
__func__, ret);
+ mutex_unlock(&devp->ch_lock);
return ret;
}
}
+ mutex_unlock(&devp->ch_lock);
GLINK_PKT_INFO("Begin %s on glink_pkt_dev id:%d buffer_size %zu\n",
__func__, devp->i, count);
diff --git a/drivers/spi/spi_qsd.c b/drivers/spi/spi_qsd.c
index 6f75eee8f921..8efe18dcc98f 100644
--- a/drivers/spi/spi_qsd.c
+++ b/drivers/spi/spi_qsd.c
@@ -45,6 +45,8 @@
#include <linux/msm-bus-board.h>
#include "spi_qsd.h"
+#define SPI_MAX_BYTES_PER_WORD (4)
+
static int msm_spi_pm_resume_runtime(struct device *device);
static int msm_spi_pm_suspend_runtime(struct device *device);
static inline void msm_spi_dma_unmap_buffers(struct msm_spi *dd);
@@ -438,10 +440,12 @@ static void msm_spi_read_word_from_fifo(struct msm_spi *dd)
u32 data_in;
int i;
int shift;
+ int read_bytes = (dd->pack_words ?
+ SPI_MAX_BYTES_PER_WORD : dd->bytes_per_word);
data_in = readl_relaxed(dd->base + SPI_INPUT_FIFO);
if (dd->read_buf) {
- for (i = 0; (i < dd->bytes_per_word) &&
+ for (i = 0; (i < read_bytes) &&
dd->rx_bytes_remaining; i++) {
/* The data format depends on bytes_per_word:
4 bytes: 0x12345678
@@ -454,8 +458,8 @@ static void msm_spi_read_word_from_fifo(struct msm_spi *dd)
dd->rx_bytes_remaining--;
}
} else {
- if (dd->rx_bytes_remaining >= dd->bytes_per_word)
- dd->rx_bytes_remaining -= dd->bytes_per_word;
+ if (dd->rx_bytes_remaining >= read_bytes)
+ dd->rx_bytes_remaining -= read_bytes;
else
dd->rx_bytes_remaining = 0;
}
@@ -552,7 +556,7 @@ msm_spi_set_bpw_and_no_io_flags(struct msm_spi *dd, u32 *config, int n)
if (n != (*config & SPI_CFG_N))
*config = (*config & ~SPI_CFG_N) | n;
- if (dd->mode == SPI_BAM_MODE) {
+ if (dd->tx_mode == SPI_BAM_MODE) {
if (dd->read_buf == NULL)
*config |= SPI_NO_INPUT;
if (dd->write_buf == NULL)
@@ -617,25 +621,34 @@ static void msm_spi_set_spi_config(struct msm_spi *dd, int bpw)
static void msm_spi_set_mx_counts(struct msm_spi *dd, u32 n_words)
{
/*
- * n_words cannot exceed fifo_size, and only one READ COUNT
- * interrupt is generated per transaction, so for transactions
- * larger than fifo size READ COUNT must be disabled.
- * For those transactions we usually move to Data Mover mode.
+ * For FIFO mode:
+ * - Set the MX_OUTPUT_COUNT/MX_INPUT_COUNT registers to 0
+ * - Set the READ/WRITE_COUNT registers to 0 (infinite mode)
+ * or num bytes (finite mode) if less than fifo worth of data.
+ * For Block mode:
+ * - Set the MX_OUTPUT/MX_INPUT_COUNT registers to num xfer bytes.
+ * - Set the READ/WRITE_COUNT registers to 0.
*/
- if (dd->mode == SPI_FIFO_MODE) {
- if (n_words <= dd->input_fifo_size) {
- writel_relaxed(n_words,
- dd->base + SPI_MX_READ_COUNT);
- msm_spi_set_write_count(dd, n_words);
- } else {
- writel_relaxed(0, dd->base + SPI_MX_READ_COUNT);
- msm_spi_set_write_count(dd, 0);
- }
- if (dd->qup_ver == SPI_QUP_VERSION_BFAM) {
- /* must be zero for FIFO */
- writel_relaxed(0, dd->base + SPI_MX_INPUT_COUNT);
+ if (dd->tx_mode != SPI_BAM_MODE) {
+ if (dd->tx_mode == SPI_FIFO_MODE) {
+ if (n_words <= dd->input_fifo_size)
+ msm_spi_set_write_count(dd, n_words);
+ else
+ msm_spi_set_write_count(dd, 0);
writel_relaxed(0, dd->base + SPI_MX_OUTPUT_COUNT);
- }
+ } else
+ writel_relaxed(n_words, dd->base + SPI_MX_OUTPUT_COUNT);
+
+ if (dd->rx_mode == SPI_FIFO_MODE) {
+ if (n_words <= dd->input_fifo_size)
+ writel_relaxed(n_words,
+ dd->base + SPI_MX_READ_COUNT);
+ else
+ writel_relaxed(0,
+ dd->base + SPI_MX_READ_COUNT);
+ writel_relaxed(0, dd->base + SPI_MX_INPUT_COUNT);
+ } else
+ writel_relaxed(n_words, dd->base + SPI_MX_INPUT_COUNT);
} else {
/* must be zero for BAM and DMOV */
writel_relaxed(0, dd->base + SPI_MX_READ_COUNT);
@@ -882,7 +895,7 @@ xfr_err:
static int
msm_spi_bam_next_transfer(struct msm_spi *dd)
{
- if (dd->mode != SPI_BAM_MODE)
+ if (dd->tx_mode != SPI_BAM_MODE)
return 0;
if (dd->tx_bytes_remaining > 0) {
@@ -901,7 +914,7 @@ msm_spi_bam_next_transfer(struct msm_spi *dd)
static int msm_spi_dma_send_next(struct msm_spi *dd)
{
int ret = 0;
- if (dd->mode == SPI_BAM_MODE)
+ if (dd->tx_mode == SPI_BAM_MODE)
ret = msm_spi_bam_next_transfer(dd);
return ret;
}
@@ -932,32 +945,38 @@ static inline irqreturn_t msm_spi_qup_irq(int irq, void *dev_id)
}
op = readl_relaxed(dd->base + SPI_OPERATIONAL);
+ writel_relaxed(op, dd->base + SPI_OPERATIONAL);
+ /*
+ * Ensure service flag was cleared before further
+ * processing of interrupt.
+ */
+ mb();
if (op & SPI_OP_INPUT_SERVICE_FLAG) {
- writel_relaxed(SPI_OP_INPUT_SERVICE_FLAG,
- dd->base + SPI_OPERATIONAL);
- /*
- * Ensure service flag was cleared before further
- * processing of interrupt.
- */
- mb();
ret |= msm_spi_input_irq(irq, dev_id);
}
if (op & SPI_OP_OUTPUT_SERVICE_FLAG) {
- writel_relaxed(SPI_OP_OUTPUT_SERVICE_FLAG,
- dd->base + SPI_OPERATIONAL);
- /*
- * Ensure service flag was cleared before further
- * processing of interrupt.
- */
- mb();
ret |= msm_spi_output_irq(irq, dev_id);
}
- if (dd->done) {
+ if (dd->tx_mode != SPI_BAM_MODE) {
+ if (!dd->rx_done) {
+ if (dd->rx_bytes_remaining == 0)
+ dd->rx_done = true;
+ }
+ if (!dd->tx_done) {
+ if (!dd->tx_bytes_remaining &&
+ (op & SPI_OP_IP_FIFO_NOT_EMPTY)) {
+ dd->tx_done = true;
+ }
+ }
+ }
+ if (dd->tx_done && dd->rx_done) {
+ msm_spi_set_state(dd, SPI_OP_STATE_RESET);
+ dd->tx_done = false;
+ dd->rx_done = false;
complete(&dd->rx_transfer_complete);
complete(&dd->tx_transfer_complete);
- dd->done = 0;
}
return ret;
}
@@ -968,17 +987,23 @@ static irqreturn_t msm_spi_input_irq(int irq, void *dev_id)
dd->stat_rx++;
- if (dd->mode == SPI_MODE_NONE)
+ if (dd->rx_mode == SPI_MODE_NONE)
return IRQ_HANDLED;
- if (dd->mode == SPI_FIFO_MODE) {
+ if (dd->rx_mode == SPI_FIFO_MODE) {
while ((readl_relaxed(dd->base + SPI_OPERATIONAL) &
SPI_OP_IP_FIFO_NOT_EMPTY) &&
(dd->rx_bytes_remaining > 0)) {
msm_spi_read_word_from_fifo(dd);
}
- if (dd->rx_bytes_remaining == 0)
- msm_spi_complete(dd);
+ } else if (dd->rx_mode == SPI_BLOCK_MODE) {
+ int count = 0;
+
+ while (dd->rx_bytes_remaining &&
+ (count < dd->input_block_size)) {
+ msm_spi_read_word_from_fifo(dd);
+ count += SPI_MAX_BYTES_PER_WORD;
+ }
}
return IRQ_HANDLED;
@@ -989,18 +1014,20 @@ static void msm_spi_write_word_to_fifo(struct msm_spi *dd)
u32 word;
u8 byte;
int i;
+ int write_bytes =
+ (dd->pack_words ? SPI_MAX_BYTES_PER_WORD : dd->bytes_per_word);
word = 0;
if (dd->write_buf) {
- for (i = 0; (i < dd->bytes_per_word) &&
+ for (i = 0; (i < write_bytes) &&
dd->tx_bytes_remaining; i++) {
dd->tx_bytes_remaining--;
byte = *dd->write_buf++;
word |= (byte << (BITS_PER_BYTE * i));
}
} else
- if (dd->tx_bytes_remaining > dd->bytes_per_word)
- dd->tx_bytes_remaining -= dd->bytes_per_word;
+ if (dd->tx_bytes_remaining > write_bytes)
+ dd->tx_bytes_remaining -= write_bytes;
else
dd->tx_bytes_remaining = 0;
dd->write_xfr_cnt++;
@@ -1012,11 +1039,22 @@ static inline void msm_spi_write_rmn_to_fifo(struct msm_spi *dd)
{
int count = 0;
- while ((dd->tx_bytes_remaining > 0) && (count < dd->input_fifo_size) &&
- !(readl_relaxed(dd->base + SPI_OPERATIONAL) &
- SPI_OP_OUTPUT_FIFO_FULL)) {
- msm_spi_write_word_to_fifo(dd);
- count++;
+ if (dd->tx_mode == SPI_FIFO_MODE) {
+ while ((dd->tx_bytes_remaining > 0) &&
+ (count < dd->input_fifo_size) &&
+ !(readl_relaxed(dd->base + SPI_OPERATIONAL)
+ & SPI_OP_OUTPUT_FIFO_FULL)) {
+ msm_spi_write_word_to_fifo(dd);
+ count++;
+ }
+ }
+
+ if (dd->tx_mode == SPI_BLOCK_MODE) {
+ while (dd->tx_bytes_remaining &&
+ (count < dd->output_block_size)) {
+ msm_spi_write_word_to_fifo(dd);
+ count += SPI_MAX_BYTES_PER_WORD;
+ }
}
}
@@ -1026,11 +1064,11 @@ static irqreturn_t msm_spi_output_irq(int irq, void *dev_id)
dd->stat_tx++;
- if (dd->mode == SPI_MODE_NONE)
+ if (dd->tx_mode == SPI_MODE_NONE)
return IRQ_HANDLED;
/* Output FIFO is empty. Transmit any outstanding write data. */
- if (dd->mode == SPI_FIFO_MODE)
+ if ((dd->tx_mode == SPI_FIFO_MODE) || (dd->tx_mode == SPI_BLOCK_MODE))
msm_spi_write_rmn_to_fifo(dd);
return IRQ_HANDLED;
@@ -1106,7 +1144,7 @@ error:
static int msm_spi_dma_map_buffers(struct msm_spi *dd)
{
int ret = 0;
- if (dd->mode == SPI_BAM_MODE)
+ if (dd->tx_mode == SPI_BAM_MODE)
ret = msm_spi_bam_map_buffers(dd);
return ret;
}
@@ -1135,7 +1173,7 @@ static void msm_spi_bam_unmap_buffers(struct msm_spi *dd)
static inline void msm_spi_dma_unmap_buffers(struct msm_spi *dd)
{
- if (dd->mode == SPI_BAM_MODE)
+ if (dd->tx_mode == SPI_BAM_MODE)
msm_spi_bam_unmap_buffers(dd);
}
@@ -1197,9 +1235,11 @@ static void
msm_spi_set_transfer_mode(struct msm_spi *dd, u8 bpw, u32 read_count)
{
if (msm_spi_use_dma(dd, dd->cur_transfer, bpw)) {
- dd->mode = SPI_BAM_MODE;
+ dd->tx_mode = SPI_BAM_MODE;
+ dd->rx_mode = SPI_BAM_MODE;
} else {
- dd->mode = SPI_FIFO_MODE;
+ dd->rx_mode = SPI_FIFO_MODE;
+ dd->tx_mode = SPI_FIFO_MODE;
dd->read_len = dd->cur_transfer->len;
dd->write_len = dd->cur_transfer->len;
}
@@ -1215,14 +1255,23 @@ static void msm_spi_set_qup_io_modes(struct msm_spi *dd)
spi_iom = readl_relaxed(dd->base + SPI_IO_MODES);
/* Set input and output transfer mode: FIFO, DMOV, or BAM */
spi_iom &= ~(SPI_IO_M_INPUT_MODE | SPI_IO_M_OUTPUT_MODE);
- spi_iom = (spi_iom | (dd->mode << OUTPUT_MODE_SHIFT));
- spi_iom = (spi_iom | (dd->mode << INPUT_MODE_SHIFT));
- /* Turn on packing for data mover */
- if (dd->mode == SPI_BAM_MODE)
+ spi_iom = (spi_iom | (dd->tx_mode << OUTPUT_MODE_SHIFT));
+ spi_iom = (spi_iom | (dd->rx_mode << INPUT_MODE_SHIFT));
+
+ /* Always enable packing for the BAM mode and for non BAM mode only
+ * if bpw is % 8 and transfer length is % 4 Bytes.
+ */
+ if (dd->tx_mode == SPI_BAM_MODE ||
+ ((dd->cur_msg_len % SPI_MAX_BYTES_PER_WORD == 0) &&
+ (dd->cur_transfer->bits_per_word) &&
+ (dd->cur_transfer->bits_per_word <= 32) &&
+ (dd->cur_transfer->bits_per_word % 8 == 0))) {
spi_iom |= SPI_IO_M_PACK_EN | SPI_IO_M_UNPACK_EN;
- else {
+ dd->pack_words = true;
+ } else {
spi_iom &= ~(SPI_IO_M_PACK_EN | SPI_IO_M_UNPACK_EN);
spi_iom |= SPI_IO_M_OUTPUT_BIT_SHIFT_EN;
+ dd->pack_words = false;
}
/*if (dd->mode == SPI_BAM_MODE) {
@@ -1280,7 +1329,7 @@ static void msm_spi_set_qup_op_mask(struct msm_spi *dd)
{
/* mask INPUT and OUTPUT service flags in to prevent IRQs on FIFO status
* change in BAM mode */
- u32 mask = (dd->mode == SPI_BAM_MODE) ?
+ u32 mask = (dd->tx_mode == SPI_BAM_MODE) ?
QUP_OP_MASK_OUTPUT_SERVICE_FLAG | QUP_OP_MASK_INPUT_SERVICE_FLAG
: 0;
writel_relaxed(mask, dd->base + QUP_OPERATIONAL_MASK);
@@ -1321,6 +1370,8 @@ static int msm_spi_process_transfer(struct msm_spi *dd)
dd->rx_bytes_remaining = dd->cur_msg_len;
dd->read_buf = dd->cur_transfer->rx_buf;
dd->write_buf = dd->cur_transfer->tx_buf;
+ dd->tx_done = false;
+ dd->rx_done = false;
init_completion(&dd->tx_transfer_complete);
init_completion(&dd->rx_transfer_complete);
if (dd->cur_transfer->bits_per_word)
@@ -1351,10 +1402,12 @@ static int msm_spi_process_transfer(struct msm_spi *dd)
msm_spi_set_transfer_mode(dd, bpw, read_count);
msm_spi_set_mx_counts(dd, read_count);
- if (dd->mode == SPI_BAM_MODE) {
+ if (dd->tx_mode == SPI_BAM_MODE) {
ret = msm_spi_dma_map_buffers(dd);
if (ret < 0) {
pr_err("Mapping DMA buffers\n");
+ dd->tx_mode = SPI_MODE_NONE;
+ dd->rx_mode = SPI_MODE_NONE;
return ret;
}
}
@@ -1368,11 +1421,11 @@ static int msm_spi_process_transfer(struct msm_spi *dd)
the first. Restricting this to one write avoids contention
issues and race conditions between this thread and the int handler
*/
- if (dd->mode == SPI_FIFO_MODE) {
+ if (dd->tx_mode != SPI_BAM_MODE) {
if (msm_spi_prepare_for_write(dd))
goto transfer_end;
msm_spi_start_write(dd, read_count);
- } else if (dd->mode == SPI_BAM_MODE) {
+ } else {
if ((msm_spi_bam_begin_transfer(dd)) < 0) {
dev_err(dd->dev, "%s: BAM transfer setup failed\n",
__func__);
@@ -1388,11 +1441,11 @@ static int msm_spi_process_transfer(struct msm_spi *dd)
* might fire before the first word is written resulting in a
* possible race condition.
*/
- if (dd->mode != SPI_BAM_MODE)
+ if (dd->tx_mode != SPI_BAM_MODE)
if (msm_spi_set_state(dd, SPI_OP_STATE_RUN)) {
dev_warn(dd->dev,
"%s: Failed to set QUP to run-state. Mode:%d",
- __func__, dd->mode);
+ __func__, dd->tx_mode);
goto transfer_end;
}
@@ -1422,10 +1475,11 @@ static int msm_spi_process_transfer(struct msm_spi *dd)
msm_spi_udelay(dd->xfrs_delay_usec);
transfer_end:
- if ((dd->mode == SPI_BAM_MODE) && status)
+ if ((dd->tx_mode == SPI_BAM_MODE) && status)
msm_spi_bam_flush(dd);
msm_spi_dma_unmap_buffers(dd);
- dd->mode = SPI_MODE_NONE;
+ dd->tx_mode = SPI_MODE_NONE;
+ dd->rx_mode = SPI_MODE_NONE;
msm_spi_set_state(dd, SPI_OP_STATE_RESET);
if (!dd->cur_transfer->cs_change)
@@ -2349,7 +2403,8 @@ static int init_resources(struct platform_device *pdev)
pclk_enabled = 0;
dd->transfer_pending = 0;
- dd->mode = SPI_MODE_NONE;
+ dd->tx_mode = SPI_MODE_NONE;
+ dd->rx_mode = SPI_MODE_NONE;
rc = msm_spi_request_irq(dd, pdev, master);
if (rc)
diff --git a/drivers/spi/spi_qsd.h b/drivers/spi/spi_qsd.h
index 7a5cfadaa5a0..47d69965f18a 100644
--- a/drivers/spi/spi_qsd.h
+++ b/drivers/spi/spi_qsd.h
@@ -113,6 +113,8 @@
#define INPUT_MODE_SHIFT QSD_REG(10) QUP_REG(12)
/* SPI_OPERATIONAL fields */
+#define SPI_OP_IN_BLK_RD_REQ_FLAG 0x00002000
+#define SPI_OP_OUT_BLK_WR_REQ_FLAG 0x00001000
#define SPI_OP_MAX_INPUT_DONE_FLAG 0x00000800
#define SPI_OP_MAX_OUTPUT_DONE_FLAG 0x00000400
#define SPI_OP_INPUT_SERVICE_FLAG 0x00000200
@@ -321,7 +323,8 @@ struct msm_spi {
bool transfer_pending;
wait_queue_head_t continue_suspend;
/* DMA data */
- enum msm_spi_mode mode;
+ enum msm_spi_mode tx_mode;
+ enum msm_spi_mode rx_mode;
bool use_dma;
int tx_dma_chan;
int tx_dma_crci;
@@ -353,7 +356,8 @@ struct msm_spi {
#endif
struct msm_spi_platform_data *pdata; /* Platform data */
/* When set indicates multiple transfers in a single message */
- bool done;
+ bool rx_done;
+ bool tx_done;
u32 cur_msg_len;
/* Used in FIFO mode to keep track of the transfer being processed */
struct spi_transfer *cur_tx_transfer;
@@ -371,6 +375,7 @@ struct msm_spi {
struct pinctrl_state *pins_active;
struct pinctrl_state *pins_sleep;
bool is_init_complete;
+ bool pack_words;
};
/* Forward declaration */
@@ -524,7 +529,8 @@ static inline void msm_spi_set_write_count(struct msm_spi *dd, int val)
static inline void msm_spi_complete(struct msm_spi *dd)
{
- dd->done = 1;
+ dd->tx_done = true;
+ dd->rx_done = true;
}
static inline void msm_spi_enable_error_flags(struct msm_spi *dd)
diff --git a/drivers/usb/gadget/function/f_gsi.c b/drivers/usb/gadget/function/f_gsi.c
index be532503954f..7216fdd4245d 100644
--- a/drivers/usb/gadget/function/f_gsi.c
+++ b/drivers/usb/gadget/function/f_gsi.c
@@ -1550,13 +1550,6 @@ static void gsi_ctrl_notify_resp_complete(struct usb_ep *ep,
event->bNotificationType, req->status);
/* FALLTHROUGH */
case 0:
- /*
- * handle multiple pending resp available
- * notifications by queuing same until we're done,
- * rest of the notification require queuing new
- * request.
- */
- gsi_ctrl_send_notification(gsi);
break;
}
}
@@ -1651,6 +1644,14 @@ static void gsi_ctrl_reset_cmd_complete(struct usb_ep *ep,
gsi_ctrl_send_cpkt_tomodem(gsi, req->buf, 0);
}
+static void gsi_ctrl_send_response_complete(struct usb_ep *ep,
+ struct usb_request *req)
+{
+ struct f_gsi *gsi = req->context;
+
+ gsi_ctrl_send_notification(gsi);
+}
+
static int
gsi_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
{
@@ -1737,6 +1738,8 @@ gsi_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
memcpy(req->buf, cpkt->buf, value);
gsi_ctrl_pkt_free(cpkt);
+ req->complete = gsi_ctrl_send_response_complete;
+ req->context = gsi;
log_event_dbg("copied encap_resp %d bytes",
value);
break;
diff --git a/drivers/video/fbdev/msm/mdss_dp.c b/drivers/video/fbdev/msm/mdss_dp.c
index 2d499ef903d3..226198efbeec 100644
--- a/drivers/video/fbdev/msm/mdss_dp.c
+++ b/drivers/video/fbdev/msm/mdss_dp.c
@@ -1512,8 +1512,14 @@ exit_loop:
pr_debug("end\n");
- /* Send a connect notification */
- if (!mdss_dp_is_phy_test_pattern_requested(dp_drv))
+ /*
+ * Send a connect notification to clients except when processing link
+ * training and electrical compliance tests. There is no need to send
+ * a notification in these testing use cases as there is no
+ * expectation of receiving a video signal as part of the test.
+ */
+ if (!mdss_dp_is_phy_test_pattern_requested(dp_drv) &&
+ !mdss_dp_is_link_training_requested(dp_drv))
mdss_dp_notify_clients(dp_drv, NOTIFY_CONNECT_IRQ_HPD);
return ret;
@@ -1609,6 +1615,14 @@ int mdss_dp_on(struct mdss_panel_data *pdata)
panel_data);
if (dp_drv->power_on) {
+ /*
+ * Acknowledge the connection event if link training has already
+ * been done. This will unblock the external display thread and
+ * allow the driver to progress. For example, in the case of
+ * video test pattern requests, to send the test response and
+ * start transmitting the test pattern.
+ */
+ mdss_dp_ack_state(dp_drv, true);
pr_debug("Link already setup, return\n");
return 0;
}
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 3d426520bfa1..31cc6f40baa5 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -434,6 +434,8 @@ struct mmc_card {
enum mmc_pon_type pon_type;
bool cmdq_init;
struct mmc_bkops_info bkops;
+ bool err_in_sdr104;
+ bool sdr104_blocked;
};
/*
diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h
index 1068953943d8..2a1a6fec179f 100644
--- a/include/linux/mmc/core.h
+++ b/include/linux/mmc/core.h
@@ -169,6 +169,7 @@ extern int __mmc_switch_cmdq_mode(struct mmc_command *cmd, u8 set, u8 index,
extern int mmc_send_tuning(struct mmc_host *host, u32 opcode, int *cmd_error);
extern int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd);
extern int mmc_set_auto_bkops(struct mmc_card *card, bool enable);
+extern int mmc_suspend_clk_scaling(struct mmc_host *host);
#define MMC_ERASE_ARG 0x00000000
#define MMC_SECURE_ERASE_ARG 0x80000000
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 055b879dfa6b..d9e12c1b1748 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -595,6 +595,7 @@ struct mmc_host {
struct io_latency_state io_lat_s;
#endif
+ bool sdr104_wa;
unsigned long private[0] ____cacheline_aligned;
};
@@ -728,6 +729,16 @@ static inline int mmc_host_uhs(struct mmc_host *host)
MMC_CAP_UHS_DDR50);
}
+static inline void mmc_host_clear_sdr104(struct mmc_host *host)
+{
+ host->caps &= ~MMC_CAP_UHS_SDR104;
+}
+
+static inline void mmc_host_set_sdr104(struct mmc_host *host)
+{
+ host->caps |= MMC_CAP_UHS_SDR104;
+}
+
static inline int mmc_host_packed_wr(struct mmc_host *host)
{
return host->caps2 & MMC_CAP2_PACKED_WR;
diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
index 864f7f6a0d01..7488bb993d7a 100644
--- a/include/linux/power_supply.h
+++ b/include/linux/power_supply.h
@@ -246,6 +246,7 @@ enum power_supply_property {
POWER_SUPPLY_PROP_DIE_HEALTH,
POWER_SUPPLY_PROP_CONNECTOR_HEALTH,
POWER_SUPPLY_PROP_CTM_CURRENT_MAX,
+ POWER_SUPPLY_PROP_HW_CURRENT_MAX,
/* Local extensions of type int64_t */
POWER_SUPPLY_PROP_CHARGE_COUNTER_EXT,
/* Properties of type `const char *' */
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 95d758d63784..4b56a62a0a58 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -3247,6 +3247,15 @@ static inline void cond_resched_rcu(void)
#endif
}
+static inline unsigned long get_preempt_disable_ip(struct task_struct *p)
+{
+#ifdef CONFIG_DEBUG_PREEMPT
+ return p->preempt_disable_ip;
+#else
+ return 0;
+#endif
+}
+
/*
* Does a critical section need to be broken due to another
* task waiting?: (technically does not depend on CONFIG_PREEMPT,
diff --git a/kernel/cpu.c b/kernel/cpu.c
index 8b6940755e4a..0ca3599cee1f 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -530,9 +530,41 @@ out:
return ret;
}
+static int switch_to_rt_policy(void)
+{
+ struct sched_param param = { .sched_priority = MAX_RT_PRIO - 1 };
+ unsigned int policy = current->policy;
+ int err;
+
+ /* Nobody should be attempting hotplug from these policy contexts. */
+ if (policy == SCHED_BATCH || policy == SCHED_IDLE ||
+ policy == SCHED_DEADLINE)
+ return -EPERM;
+
+ if (policy == SCHED_FIFO || policy == SCHED_RR)
+ return 1;
+
+ /* Only SCHED_NORMAL left. */
+ err = sched_setscheduler_nocheck(current, SCHED_FIFO, &param);
+ return err;
+
+}
+
+static int switch_to_fair_policy(void)
+{
+ struct sched_param param = { .sched_priority = 0 };
+
+ return sched_setscheduler_nocheck(current, SCHED_NORMAL, &param);
+}
+
int cpu_up(unsigned int cpu)
{
int err = 0;
+ int switch_err = 0;
+
+ switch_err = switch_to_rt_policy();
+ if (switch_err < 0)
+ return switch_err;
if (!cpu_possible(cpu)) {
pr_err("can't online cpu %d because it is not configured as may-hotadd at boot time\n",
@@ -558,6 +590,13 @@ int cpu_up(unsigned int cpu)
out:
cpu_maps_update_done();
+
+ if (!switch_err) {
+ switch_err = switch_to_fair_policy();
+ pr_err("Hotplug policy switch err. Task %s pid=%d\n",
+ current->comm, current->pid);
+ }
+
return err;
}
EXPORT_SYMBOL_GPL(cpu_up);
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 1017a3f77391..e107c4d6b385 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -3364,6 +3364,9 @@ NOKPROBE_SYMBOL(preempt_count_sub);
*/
static noinline void __schedule_bug(struct task_struct *prev)
{
+ /* Save this before calling printk(), since that will clobber it */
+ unsigned long preempt_disable_ip = get_preempt_disable_ip(current);
+
if (oops_in_progress)
return;
@@ -3374,13 +3377,12 @@ static noinline void __schedule_bug(struct task_struct *prev)
print_modules();
if (irqs_disabled())
print_irqtrace_events(prev);
-#ifdef CONFIG_DEBUG_PREEMPT
- if (in_atomic_preempt_off()) {
+ if (IS_ENABLED(CONFIG_DEBUG_PREEMPT)
+ && in_atomic_preempt_off()) {
pr_err("Preemption disabled at:");
- print_ip_sym(current->preempt_disable_ip);
+ print_ip_sym(preempt_disable_ip);
pr_cont("\n");
}
-#endif
#ifdef CONFIG_PANIC_ON_SCHED_BUG
BUG();
#endif
@@ -8513,6 +8515,7 @@ EXPORT_SYMBOL(__might_sleep);
void ___might_sleep(const char *file, int line, int preempt_offset)
{
static unsigned long prev_jiffy; /* ratelimiting */
+ unsigned long preempt_disable_ip;
rcu_sleep_check(); /* WARN_ON_ONCE() by default, no rate limit reqd. */
if ((preempt_count_equals(preempt_offset) && !irqs_disabled() &&
@@ -8525,6 +8528,9 @@ void ___might_sleep(const char *file, int line, int preempt_offset)
return;
prev_jiffy = jiffies;
+ /* Save this before calling printk(), since that will clobber it */
+ preempt_disable_ip = get_preempt_disable_ip(current);
+
printk(KERN_ERR
"BUG: sleeping function called from invalid context at %s:%d\n",
file, line);
@@ -8539,13 +8545,12 @@ void ___might_sleep(const char *file, int line, int preempt_offset)
debug_show_held_locks(current);
if (irqs_disabled())
print_irqtrace_events(current);
-#ifdef CONFIG_DEBUG_PREEMPT
- if (!preempt_count_equals(preempt_offset)) {
+ if (IS_ENABLED(CONFIG_DEBUG_PREEMPT)
+ && !preempt_count_equals(preempt_offset)) {
pr_err("Preemption disabled at:");
- print_ip_sym(current->preempt_disable_ip);
+ print_ip_sym(preempt_disable_ip);
pr_cont("\n");
}
-#endif
#ifdef CONFIG_PANIC_ON_SCHED_BUG
BUG();
#endif
diff --git a/sound/soc/codecs/wcd934x/wcd934x.c b/sound/soc/codecs/wcd934x/wcd934x.c
index cc8e45d77fcd..e125ed8c2a16 100644
--- a/sound/soc/codecs/wcd934x/wcd934x.c
+++ b/sound/soc/codecs/wcd934x/wcd934x.c
@@ -9076,8 +9076,9 @@ static int tavil_device_down(struct wcd9xxx *wcd9xxx)
codec = (struct snd_soc_codec *)(wcd9xxx->ssr_priv);
priv = snd_soc_codec_get_drvdata(codec);
- swrm_wcd_notify(priv->swr.ctrl_data[0].swr_pdev,
- SWR_DEVICE_DOWN, NULL);
+ if (priv->swr.ctrl_data)
+ swrm_wcd_notify(priv->swr.ctrl_data[0].swr_pdev,
+ SWR_DEVICE_DOWN, NULL);
tavil_dsd_reset(priv->dsd_config);
snd_soc_card_change_online_state(codec->component.card, 0);
for (count = 0; count < NUM_CODEC_DAIS; count++)