summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/arm/boot/dts/qcom/dsi-panel-sharp-split-link-wuxga-video.dtsi68
-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/msm8998-pinctrl.dtsi14
-rw-r--r--arch/arm/boot/dts/qcom/sdm660-pinctrl.dtsi14
-rw-r--r--arch/arm64/configs/msmcortex-perf_defconfig6
-rw-r--r--arch/arm64/configs/msmcortex_defconfig6
-rw-r--r--drivers/clk/msm/mdss/mdss-dsi-pll-8998.c112
-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/net/ethernet/msm/msm_rmnet_mhi.c453
-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/supply/qcom/smb138x-charger.c12
-rw-r--r--drivers/scsi/ufs/ufshcd.c20
-rw-r--r--drivers/soc/qcom/icnss.c3
-rw-r--r--drivers/usb/gadget/function/f_gsi.c17
-rw-r--r--include/linux/sched.h9
-rw-r--r--kernel/sched/core.c21
-rw-r--r--sound/soc/codecs/wcd934x/wcd934x.c5
23 files changed, 678 insertions, 356 deletions
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/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/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/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/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/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/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/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/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/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/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/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/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/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++)