diff options
105 files changed, 1683 insertions, 751 deletions
diff --git a/Documentation/RCU/stallwarn.txt b/Documentation/RCU/stallwarn.txt index ef5a2fd4ff70..607270338b93 100644 --- a/Documentation/RCU/stallwarn.txt +++ b/Documentation/RCU/stallwarn.txt @@ -193,6 +193,11 @@ o For !CONFIG_PREEMPT kernels, a CPU looping anywhere in the behavior, you might need to replace some of the cond_resched() calls with calls to cond_resched_rcu_qs(). +o Anything that prevents RCU's grace-period kthreads from running. + This can result in the "All QSes seen" console-log message. + This message will include information on when the kthread last + ran and how often it should be expected to run. + o A CPU-bound real-time task in a CONFIG_PREEMPT kernel, which might happen to preempt a low-priority task in the middle of an RCU read-side critical section. This is especially damaging if diff --git a/Documentation/devicetree/bindings/i2c/i2c-msm-v2.txt b/Documentation/devicetree/bindings/i2c/i2c-msm-v2.txt index fa3abb215773..77ff94245276 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-msm-v2.txt +++ b/Documentation/devicetree/bindings/i2c/i2c-msm-v2.txt @@ -32,6 +32,10 @@ Optional property: register. When missing, default to the value given in driver. - qcom,fs-clk-div: fs divider value to configure clk-ctl register. When missing, default to the value given in driver. + - qcom,i2c-clk : clock GPIO in case SW bit-banging is needed (if HW recovery + mechanism fails, SW will bit-bang clock line upto 9 times and sniff + data until slave releases the data line) + - qcom,i2c-dat : data-line GPIO in case SW bit-banging is needed Example: aliases { @@ -354,7 +354,7 @@ include $(srctree)/scripts/Kbuild.include # Make variables (CC, etc...) AS = $(CROSS_COMPILE)as LD = $(CROSS_COMPILE)ld -REAL_CC = $(CROSS_COMPILE)gcc +CC = $(CROSS_COMPILE)gcc CPP = $(CC) -E AR = $(CROSS_COMPILE)ar NM = $(CROSS_COMPILE)nm @@ -369,10 +369,6 @@ PERL = perl PYTHON = python CHECK = sparse -# Use the wrapper for the compiler. This wrapper scans for new -# warnings and causes the build to stop upon encountering them. -CC = $(srctree)/scripts/gcc-wrapper.py $(REAL_CC) - CHECKFLAGS := -D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ \ -Wbitwise -Wno-return-void $(CF) CFLAGS_MODULE = diff --git a/arch/arm/boot/dts/qcom/msm8996-camera-sensor-mtp.dtsi b/arch/arm/boot/dts/qcom/msm8996-camera-sensor-mtp.dtsi index 63600b6abd68..20ba9d3a31b0 100644..100755 --- a/arch/arm/boot/dts/qcom/msm8996-camera-sensor-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8996-camera-sensor-mtp.dtsi @@ -22,29 +22,6 @@ }; &cci { - actuator0: qcom,actuator@0 { - cell-index = <0>; - reg = <0x0>; - compatible = "qcom,actuator"; - qcom,cci-master = <0>; - cam_vaf-supply = <&pm8994_l23>; - qcom,cam-vreg-name = "cam_vaf"; - qcom,cam-vreg-min-voltage = <2800000>; - qcom,cam-vreg-max-voltage = <2800000>; - qcom,cam-vreg-op-mode = <100000>; - }; - - actuator1: qcom,actuator@1 { - cell-index = <1>; - reg = <0x1>; - compatible = "qcom,actuator"; - qcom,cci-master = <1>; - cam_vaf-supply = <&pm8994_l23>; - qcom,cam-vreg-name = "cam_vaf"; - qcom,cam-vreg-min-voltage = <2800000>; - qcom,cam-vreg-max-voltage = <2800000>; - qcom,cam-vreg-op-mode = <100000>; - }; ois0: qcom,ois@0 { cell-index = <0>; @@ -134,7 +111,6 @@ qcom,csid-sd-index = <0>; qcom,mount-angle = <90>; qcom,led-flash-src = <&led_flash0>; - qcom,actuator-src = <&actuator0>; qcom,ois-src = <&ois0>; qcom,eeprom-src = <&eeprom0>; cam_vdig-supply = <&pm8994_s3>; @@ -178,7 +154,6 @@ qcom,csid-sd-index = <1>; qcom,mount-angle = <90>; qcom,eeprom-src = <&eeprom1>; - qcom,actuator-src = <&actuator1>; cam_vdig-supply = <&pm8994_s3>; cam_vio-supply = <&pm8994_lvs1>; cam_vana-supply = <&pm8994_l17>; @@ -221,7 +196,6 @@ qcom,csid-sd-index = <2>; qcom,mount-angle = <90>; qcom,eeprom-src = <&eeprom1>; - qcom,actuator-src = <&actuator1>; cam_vdig-supply = <&pm8994_l27>; cam_vio-supply = <&pm8994_lvs1>; cam_vana-supply = <&pm8994_l29>; diff --git a/arch/arm/boot/dts/qcom/msm8996-pinctrl.dtsi b/arch/arm/boot/dts/qcom/msm8996-pinctrl.dtsi index ff128acb376a..e1949eb31439 100644 --- a/arch/arm/boot/dts/qcom/msm8996-pinctrl.dtsi +++ b/arch/arm/boot/dts/qcom/msm8996-pinctrl.dtsi @@ -713,6 +713,19 @@ bias-pull-down; }; }; + + i2c_12_bitbang: i2c_12_bitbang { + mux { + pins = "gpio87", "gpio88"; + function = "gpio"; + }; + + config { + pins = "gpio87", "gpio88"; + drive-strength = <8>; + bias-disable; + }; + }; }; i2c_6 { diff --git a/arch/arm/boot/dts/qcom/msm8996.dtsi b/arch/arm/boot/dts/qcom/msm8996.dtsi index 76cdcfd5b0c3..41cc93940878 100644 --- a/arch/arm/boot/dts/qcom/msm8996.dtsi +++ b/arch/arm/boot/dts/qcom/msm8996.dtsi @@ -20,10 +20,6 @@ qcom,pmic-id = <0x20009 0x2000A 0x0 0x0>; interrupt-parent = <&intc>; - chosen { - bootargs = "sched_enable_hmp=1 sched_enable_power_aware=1"; - }; - aliases { sdhc1 = &sdhc_1; /* SDC1 eMMC slot */ sdhc2 = &sdhc_2; /* SDC2 SD card slot */ @@ -459,12 +455,15 @@ qcom,master-id = <84>; qcom,clk-freq-out = <400000>; qcom,clk-freq-in = <19200000>; + qcom,i2c-clk = <&tlmm 88 0>; + qcom,i2c-dat = <&tlmm 87 0>; clock-names = "iface_clk", "core_clk"; clocks = <&clock_gcc clk_gcc_blsp2_ahb_clk>, <&clock_gcc clk_gcc_blsp2_qup6_i2c_apps_clk>; - pinctrl-names = "i2c_active", "i2c_sleep"; + pinctrl-names = "i2c_active", "i2c_sleep", "i2c_bitbang"; pinctrl-0 = <&i2c_12_active>; pinctrl-1 = <&i2c_12_sleep>; + pinctrl-2 = <&i2c_12_bitbang>; }; diff --git a/arch/arm64/boot/dts/htc/dsi-panel-s1m1-ea8064tg.dtsi b/arch/arm64/boot/dts/htc/dsi-panel-s1m1-ea8064tg.dtsi index c13798318455..abe53af9871a 100644 --- a/arch/arm64/boot/dts/htc/dsi-panel-s1m1-ea8064tg.dtsi +++ b/arch/arm64/boot/dts/htc/dsi-panel-s1m1-ea8064tg.dtsi @@ -110,7 +110,6 @@ 29 01 00 00 00 00 02 B0 01 29 01 00 00 00 00 03 B2 05 48 29 01 00 00 00 00 02 F7 03 - 29 01 00 00 00 00 02 51 60 29 01 00 00 00 00 03 F0 A5 A5 ]; qcom,mdss-dsi-lp-mode-off = [ @@ -130,7 +129,6 @@ 29 01 00 00 00 00 02 B0 01 29 01 00 00 00 00 03 B2 00 10 29 01 00 00 00 00 02 F7 03 - 29 01 00 00 00 00 02 51 00 29 01 00 00 00 00 03 F0 A5 A5 ]; qcom,mdss-dsi-lp-off-offset = <16 1 0>; diff --git a/arch/arm64/boot/dts/htc/dsi-panel-s1m1-s6e3ha3.dtsi b/arch/arm64/boot/dts/htc/dsi-panel-s1m1-s6e3ha3.dtsi index 88386d7d5fd0..27ad9146a066 100644 --- a/arch/arm64/boot/dts/htc/dsi-panel-s1m1-s6e3ha3.dtsi +++ b/arch/arm64/boot/dts/htc/dsi-panel-s1m1-s6e3ha3.dtsi @@ -117,7 +117,6 @@ 29 01 00 00 00 00 02 B0 06 29 01 00 00 00 00 03 F2 0C 04 29 01 00 00 00 00 02 F7 03 - 20 01 00 00 00 00 02 51 5A 29 01 00 00 00 00 03 F0 A5 A5 ]; qcom,mdss-dsi-lp-mode-off = [ @@ -137,7 +136,6 @@ 29 01 00 00 00 00 02 B0 06 29 01 00 00 00 00 03 F2 0A 06 29 01 00 00 00 00 02 F7 03 - 29 01 00 00 00 00 02 51 00 29 01 00 00 00 00 03 F0 A5 A5 ]; qcom,mdss-dsi-lp-off-offset = <16 1 0>; diff --git a/arch/arm64/boot/dts/htc/msm8996-camera-sensor-m1s1.dtsi b/arch/arm64/boot/dts/htc/msm8996-camera-sensor-m1s1.dtsi index 0060e2ec45bc..cae8d6291831 100755 --- a/arch/arm64/boot/dts/htc/msm8996-camera-sensor-m1s1.dtsi +++ b/arch/arm64/boot/dts/htc/msm8996-camera-sensor-m1s1.dtsi @@ -295,8 +295,8 @@ qcom,camera@0 { qcom,cam-vreg-op-mode = <0 0>;//uA
qcom,gpio-no-mux = <0>;
pinctrl-names = "cam_default", "cam_suspend";
- pinctrl-0 = <&cam_sensor_mclk0_active &cam_sensor_rear_active &cci0_active>;
- pinctrl-1 = <&cam_sensor_mclk0_suspend &cam_sensor_rear_suspend &cci0_suspend>;
+ pinctrl-0 = <&cam_sensor_mclk0_active &cam_sensor_rear_active>;
+ pinctrl-1 = <&cam_sensor_mclk0_suspend &cam_sensor_rear_suspend>;
gpios = <&tlmm 13 0>,
<&tlmm 93 0>,
<&tlmm 49 0>;
@@ -337,8 +337,8 @@ qcom,camera@1 { qcom,cam-vreg-op-mode = <0 0 0>;//uA
qcom,gpio-no-mux = <0>;
pinctrl-names = "cam_default", "cam_suspend";
- pinctrl-0 = <&cam_sensor_mclk1_active &cam_sensor_rear2_active &cci1_active>;
- pinctrl-1 = <&cam_sensor_mclk1_suspend &cam_sensor_rear2_suspend &cci0_suspend>;
+ pinctrl-0 = <&cam_sensor_mclk1_active &cam_sensor_rear2_active>;
+ pinctrl-1 = <&cam_sensor_mclk1_suspend &cam_sensor_rear2_suspend>;
gpios = <&tlmm 14 0>,
<&tlmm 23 0>,
<&pm8994_gpios 14 0>;
diff --git a/arch/arm64/boot/dts/htc/msm8996-htc_marlin.dtsi b/arch/arm64/boot/dts/htc/msm8996-htc_marlin.dtsi index 2d7842a7bdcc..32a9ccdbef1e 100644 --- a/arch/arm64/boot/dts/htc/msm8996-htc_marlin.dtsi +++ b/arch/arm64/boot/dts/htc/msm8996-htc_marlin.dtsi @@ -120,10 +120,11 @@ }; &qusb_phy0 { - qcom,qusb-phy-init-seq = <0xE8 0x80 - 0x51 0x84 - 0x81 0x88 + qcom,qusb-phy-init-seq = <0xA8 0x80 + 0x63 0x84 + 0x83 0x88 0xC0 0x8C + 0x03 0x90 0x30 0x08 0x79 0x0C 0x21 0x10 @@ -240,6 +241,7 @@ qcom,ext-sense-type = <1>; qcom,cold-hot-jeita-hysteresis = <20 30>; qcom,fg-cutoff-voltage-mv = <3250>; + qcom,irq-volt-empty-mv = <3050>; /delete-property/ qcom,capacity-learning-feedback; }; diff --git a/arch/arm64/boot/dts/htc/msm8996-htc_sailfish.dtsi b/arch/arm64/boot/dts/htc/msm8996-htc_sailfish.dtsi index 242a050f65b1..310dc7b7a6bd 100644 --- a/arch/arm64/boot/dts/htc/msm8996-htc_sailfish.dtsi +++ b/arch/arm64/boot/dts/htc/msm8996-htc_sailfish.dtsi @@ -15,10 +15,11 @@ #include "msm8996-touch-s1.dtsi" &qusb_phy0 { - qcom,qusb-phy-init-seq = <0xE8 0x80 - 0x23 0x84 - 0x81 0x88 + qcom,qusb-phy-init-seq = <0xA8 0x80 + 0x63 0x84 + 0x83 0x88 0xC0 0x8C + 0x03 0x90 0x30 0x08 0x79 0x0C 0x21 0x10 @@ -56,6 +57,7 @@ qcom,ext-sense-type = <1>; qcom,cold-hot-jeita-hysteresis = <20 30>; qcom,fg-cutoff-voltage-mv = <3250>; + qcom,irq-volt-empty-mv = <3050>; /delete-property/ qcom,capacity-learning-feedback; }; diff --git a/arch/arm64/boot/dts/htc/msm8996-touch-m1.dtsi b/arch/arm64/boot/dts/htc/msm8996-touch-m1.dtsi index ee41b2591556..3f70175b5d79 100644 --- a/arch/arm64/boot/dts/htc/msm8996-touch-m1.dtsi +++ b/arch/arm64/boot/dts/htc/msm8996-touch-m1.dtsi @@ -85,6 +85,19 @@ bias-disable; }; }; + + i2c_3_bitbang: i2c_3_bitbang { + mux { + pins = "gpio47", "gpio48"; + function = "gpio"; + }; + + config { + pins = "gpio47", "gpio48"; + drive-strength = <8>; + bias-disable; + }; + }; }; }; @@ -129,12 +142,15 @@ qcom,master-id = <86>; qcom,clk-freq-out = <400000>; qcom,clk-freq-in = <19200000>; + qcom,i2c-clk = <&tlmm 48 0>; + qcom,i2c-dat = <&tlmm 47 0>; clock-names = "iface_clk", "core_clk"; clocks = <&clock_gcc clk_gcc_blsp1_ahb_clk>, <&clock_gcc clk_gcc_blsp1_qup3_i2c_apps_clk>; - pinctrl-names = "i2c_active", "i2c_sleep"; + pinctrl-names = "i2c_active", "i2c_sleep", "i2c_bitbang"; pinctrl-0 = <&i2c_3_active>; pinctrl-1 = <&i2c_3_sleep>; + pinctrl-2 = <&i2c_3_bitbang>; }; }; diff --git a/arch/arm64/boot/dts/htc/msm8996-touch-s1.dtsi b/arch/arm64/boot/dts/htc/msm8996-touch-s1.dtsi index bfa6126f181f..ede762608774 100755 --- a/arch/arm64/boot/dts/htc/msm8996-touch-s1.dtsi +++ b/arch/arm64/boot/dts/htc/msm8996-touch-s1.dtsi @@ -85,6 +85,19 @@ bias-disable; }; }; + + i2c_3_bitbang: i2c_3_bitbang { + mux { + pins = "gpio47", "gpio48"; + function = "gpio"; + }; + + config { + pins = "gpio47", "gpio48"; + drive-strength = <8>; + bias-disable; + }; + }; }; }; @@ -129,12 +142,15 @@ qcom,master-id = <86>; qcom,clk-freq-out = <400000>; qcom,clk-freq-in = <19200000>; + qcom,i2c-clk = <&tlmm 48 0>; + qcom,i2c-dat = <&tlmm 47 0>; clock-names = "iface_clk", "core_clk"; clocks = <&clock_gcc clk_gcc_blsp1_ahb_clk>, <&clock_gcc clk_gcc_blsp1_qup3_i2c_apps_clk>; - pinctrl-names = "i2c_active", "i2c_sleep"; + pinctrl-names = "i2c_active", "i2c_sleep", "i2c_bitbang"; pinctrl-0 = <&i2c_3_active>; pinctrl-1 = <&i2c_3_sleep>; + pinctrl-2 = <&i2c_3_bitbang>; }; }; diff --git a/arch/arm64/configs/marlin_defconfig b/arch/arm64/configs/marlin_defconfig index a87144fcc012..ca6fa3ae5aa3 100644 --- a/arch/arm64/configs/marlin_defconfig +++ b/arch/arm64/configs/marlin_defconfig @@ -514,7 +514,7 @@ CONFIG_MSM_DDR_HEALTH=y CONFIG_MSM_WATCHDOG_V2=y CONFIG_MSM_FORCE_WDOG_BITE_ON_PANIC=y CONFIG_MSM_CACHE_M4M_ERP64=y -CONFIG_MSM_CACHE_M4M_ERP64_PANIC_ON_CE=y +# CONFIG_MSM_CACHE_M4M_ERP64_PANIC_ON_CE is not set CONFIG_MSM_CACHE_M4M_ERP64_PANIC_ON_UE=y CONFIG_MSM_RPM_SMD=y CONFIG_MSM_RPM_LOG=y @@ -577,10 +577,6 @@ CONFIG_HTC_NC_GPIO_PIN_SETTING=y CONFIG_HTC_DEBUG_BOOTLOADER_LOG=y CONFIG_MSM_TZ_LOG=y CONFIG_MOBICORE_DRIVER=y -CONFIG_EXT2_FS=y -CONFIG_EXT2_FS_XATTR=y -CONFIG_EXT3_FS=y -# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set CONFIG_EXT4_FS=y CONFIG_EXT4_FS_SECURITY=y CONFIG_EXT4_FS_ENCRYPTION=y @@ -590,12 +586,12 @@ CONFIG_VFAT_FS=y CONFIG_TMPFS=y CONFIG_TMPFS_POSIX_ACL=y CONFIG_ECRYPT_FS=y -CONFIG_ECRYPT_FS_MESSAGING=y CONFIG_SDCARD_FS=y CONFIG_PSTORE=y CONFIG_PSTORE_CONSOLE=y CONFIG_PSTORE_PMSG=y CONFIG_PSTORE_RAM=y +# CONFIG_NETWORK_FILESYSTEMS is not set CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_ASCII=y CONFIG_NLS_ISO8859_1=y diff --git a/arch/arm64/include/asm/pmu.h b/arch/arm64/include/asm/pmu.h index 48c59086aed2..53d992a6c6f1 100644 --- a/arch/arm64/include/asm/pmu.h +++ b/arch/arm64/include/asm/pmu.h @@ -43,6 +43,8 @@ struct pmu_hw_events { struct arm_pmu { struct pmu pmu; + bool percpu_irq_requested; + int percpu_irq; cpumask_t active_irqs; const char *name; irqreturn_t (*handle_irq)(int irq_num, void *dev); diff --git a/arch/arm64/kernel/perf_event.c b/arch/arm64/kernel/perf_event.c index 386ca2617bbf..a07d1f40eaf4 100644 --- a/arch/arm64/kernel/perf_event.c +++ b/arch/arm64/kernel/perf_event.c @@ -393,7 +393,9 @@ armpmu_disable_percpu_irq(void *data) static void armpmu_release_hardware(struct arm_pmu *armpmu) { + get_online_cpus(); armpmu->free_irq(armpmu); + put_online_cpus(); } static void @@ -414,12 +416,12 @@ armpmu_reserve_hardware(struct arm_pmu *armpmu) return -ENODEV; } + get_online_cpus(); err = armpmu->request_irq(armpmu, armpmu->handle_irq); - if (err) { + if (err) armpmu_release_hardware(armpmu); - return err; - } - return 0; + put_online_cpus(); + return err; } static void @@ -1042,6 +1044,8 @@ static int armv8pmu_request_irq(struct arm_pmu *cpu_pmu, irq_handler_t handler) } on_each_cpu(armpmu_enable_percpu_irq, &irq, 1); + cpu_pmu->percpu_irq_requested = true; + cpu_pmu->percpu_irq = irq; } else { for (i = 0; i < irqs; ++i) { err = 0; @@ -1093,6 +1097,7 @@ static void armv8pmu_free_irq(struct arm_pmu *cpu_pmu) if (irq_is_percpu(irq)) { on_each_cpu(armpmu_disable_percpu_irq, &irq, 1); free_percpu_irq(irq, &cpu_hw_events); + cpu_pmu->percpu_irq_requested = false; } else { for (i = 0; i < irqs; ++i) { if (!cpumask_test_and_clear_cpu(i, @@ -1334,16 +1339,28 @@ static int __cpuinit cpu_pmu_notify(struct notifier_block *b, { int cpu = (unsigned long)hcpu; struct arm_pmu *pmu = container_of(b, struct arm_pmu, hotplug_nb); - if ((action & ~CPU_TASKS_FROZEN) != CPU_STARTING) - return NOTIFY_DONE; - if (!cpumask_test_cpu(cpu, cpu_online_mask)) - return NOTIFY_DONE; - if (pmu->reset) - cpu_pmu->reset(pmu); - else - return NOTIFY_DONE; - return NOTIFY_OK; + switch (action & ~CPU_TASKS_FROZEN) { + case CPU_DOWN_PREPARE: + if (pmu->percpu_irq_requested) { + int irq = pmu->percpu_irq; + smp_call_function_single(cpu, + armpmu_disable_percpu_irq, &irq, 1); + } + break; + + case CPU_STARTING: + case CPU_DOWN_FAILED: + if (pmu->reset) + pmu->reset(pmu); + if (pmu->percpu_irq_requested) { + int irq = pmu->percpu_irq; + smp_call_function_single(cpu, + armpmu_enable_percpu_irq, &irq, 1); + } + break; + } + return NOTIFY_DONE; } #ifdef CONFIG_CPU_PM diff --git a/build.config b/build.config index 230bfd14cafd..fa53eb4c343f 100644 --- a/build.config +++ b/build.config @@ -1,12 +1,13 @@ ARCH=arm64 -BRANCH=android-msm-marlin-3.18-ndr-factoryrom +BRANCH=android-msm-marlin-3.18 CROSS_COMPILE=aarch64-linux-android- DEFCONFIG=marlin_defconfig -EXTRA_CMDS='' +EXTRA_CMDS='python build/buildinfo/buildinfo.py' KERNEL_DIR=private/msm-google LINUX_GCC_CROSS_COMPILE_PREBUILTS_BIN=prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9/bin FILES=" arch/arm64/boot/Image.gz-dtb vmlinux System.map +compile.json " diff --git a/build.config.kasan b/build.config.kasan new file mode 100644 index 000000000000..8f0141aa0446 --- /dev/null +++ b/build.config.kasan @@ -0,0 +1,27 @@ +function update_kasan_config() { + ${KERNEL_DIR}/scripts/config --file ${OUT_DIR}/.config \ + -e CONFIG_KASAN \ + -e CONFIG_KASAN_INLINE \ + -e CONFIG_TEST_KASAN \ + -e CONFIG_KCOV \ + -e CONFIG_SLUB \ + -e CONFIG_SLUB_DEBUG \ + -e CONFIG_SLUB_DEBUG_ON \ + -d CONFIG_SLUB_DEBUG_PANIC_ON \ + -d CONFIG_KASAN_OUTLINE + (cd ${OUT_DIR} && \ + make O=${OUT_DIR} $archsubarch CROSS_COMPILE=${CROSS_COMPILE} olddefconfig) +} + +ARCH=arm64 +BRANCH=android-msm-marlin-3.18 +CROSS_COMPILE=aarch64-linux-android- +DEFCONFIG=marlin_defconfig +KERNEL_DIR=private/msm-google +POST_DEFCONFIG_CMDS="update_kasan_config" +LINUX_GCC_CROSS_COMPILE_PREBUILTS_BIN=prebuilts-master/gcc/linux-x86/aarch64/aarch64-linux-android-4.9/bin +FILES=" +arch/arm64/boot/Image.gz-dtb +vmlinux +System.map +" diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig index c7d273ba567a..1d6d1f6f7cd0 100644 --- a/drivers/base/Kconfig +++ b/drivers/base/Kconfig @@ -165,6 +165,11 @@ config FW_LOADER_USER_HELPER_FALLBACK If you are unsure about this, say N here. +config FW_CACHE + bool "Enable firmware caching during suspend" + depends on PM_SLEEP + default n + config WANT_DEV_COREDUMP bool help diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index 033b3101cbfe..b87fa5d419ae 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c @@ -1119,7 +1119,7 @@ static int fw_load_from_user_helper(struct firmware *firmware, return _request_firmware_load(fw_priv, desc->opt_flags, timeout); } -#ifdef CONFIG_PM_SLEEP +#ifdef CONFIG_FW_CACHE /* kill pending requests without uevent to avoid blocking suspend */ static void kill_requests_without_uevent(void) { @@ -1597,7 +1597,7 @@ request_firmware_nowait_into_buf( } EXPORT_SYMBOL_GPL(request_firmware_nowait_into_buf); -#ifdef CONFIG_PM_SLEEP +#ifdef CONFIG_FW_CACHE static ASYNC_DOMAIN_EXCLUSIVE(fw_cache_domain); /** @@ -1937,7 +1937,7 @@ static void __init fw_cache_init(void) INIT_LIST_HEAD(&fw_cache.head); fw_cache.state = FW_LOADER_NO_CACHE; -#ifdef CONFIG_PM_SLEEP +#ifdef CONFIG_FW_CACHE spin_lock_init(&fw_cache.name_lock); INIT_LIST_HEAD(&fw_cache.fw_names); @@ -1964,7 +1964,7 @@ static int __init firmware_class_init(void) static void __exit firmware_class_exit(void) { -#ifdef CONFIG_PM_SLEEP +#ifdef CONFIG_FW_CACHE unregister_syscore_ops(&fw_syscore_ops); unregister_pm_notifier(&fw_cache.pm_notify); #endif diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index ef5d2797fceb..230ab8d0ce67 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -30,7 +30,6 @@ #include <linux/suspend.h> #include <trace/events/power.h> #include <linux/cpufreq.h> -#include <linux/cpuidle.h> #include <linux/timer.h> #include <linux/wakeup_reason.h> @@ -606,7 +605,6 @@ void dpm_resume_noirq(pm_message_t state) async_synchronize_full(); dpm_show_time(starttime, state, "noirq"); resume_device_irqs(); - cpuidle_resume(); trace_suspend_resume(TPS("dpm_resume_noirq"), state.event, false); } @@ -1142,7 +1140,6 @@ int dpm_suspend_noirq(pm_message_t state) int error = 0; trace_suspend_resume(TPS("dpm_suspend_noirq"), state.event, true); - cpuidle_pause(); suspend_device_irqs(); mutex_lock(&dpm_list_mtx); pm_transition = state; diff --git a/drivers/char/diag/diag_dci.c b/drivers/char/diag/diag_dci.c index 62b0cf2e966f..13a3afa5409c 100644 --- a/drivers/char/diag/diag_dci.c +++ b/drivers/char/diag/diag_dci.c @@ -3000,7 +3000,7 @@ int diag_dci_write_proc(uint8_t peripheral, int pkt_type, char *buf, int len) DIAG_LOG(DIAG_DEBUG_DCI, "buf: 0x%pK, p: %d, len: %d, f_mask: %d\n", buf, peripheral, len, - driver->feature[peripheral].rcvd_feature_mask); + driver->feature[PERIPHERAL_MODEM].rcvd_feature_mask); return -EINVAL; } diff --git a/drivers/char/diag/diag_masks.c b/drivers/char/diag/diag_masks.c index 9f694a052cb8..f6709faa2d77 100644 --- a/drivers/char/diag/diag_masks.c +++ b/drivers/char/diag/diag_masks.c @@ -1779,6 +1779,15 @@ int diag_copy_to_user_msg_mask(char __user *buf, size_t count, if (!mask_info) return -EIO; + mutex_lock(&driver->diag_maskclear_mutex); + if (driver->mask_clear) { + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "diag:%s: count = %zu\n", __func__, count); + mutex_unlock(&driver->diag_maskclear_mutex); + return -EIO; + } + mutex_unlock(&driver->diag_maskclear_mutex); + mutex_lock(&mask_info->lock); mask = (struct diag_msg_mask_t *)(mask_info->ptr); for (i = 0; i < driver->msg_mask_tbl_count; i++, mask++) { diff --git a/drivers/char/diag/diag_usb.c b/drivers/char/diag/diag_usb.c index eb715cc8501c..ca54b24ec604 100644 --- a/drivers/char/diag/diag_usb.c +++ b/drivers/char/diag/diag_usb.c @@ -215,6 +215,12 @@ static void usb_connect_work_fn(struct work_struct *work) */ static void usb_disconnect(struct diag_usb_info *ch) { + if (!ch) + return; + + if (!atomic_read(&ch->connected) && driver->usb_connected) + diag_clear_masks(NULL); + if (ch && ch->ops && ch->ops->close) ch->ops->close(ch->ctxt, DIAG_USB_MODE); } diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h index fb86f6e246b1..43331190c582 100644 --- a/drivers/char/diag/diagchar.h +++ b/drivers/char/diag/diagchar.h @@ -463,6 +463,8 @@ struct diagchar_dev { struct class *diagchar_class; struct device *diag_dev; int ref_count; + int mask_clear; + struct mutex diag_maskclear_mutex; struct mutex diagchar_mutex; struct mutex diag_file_mutex; wait_queue_head_t wait_q; @@ -622,6 +624,7 @@ void diag_cmd_remove_reg(struct diag_cmd_reg_entry_t *entry, uint8_t proc); void diag_cmd_remove_reg_by_pid(int pid); void diag_cmd_remove_reg_by_proc(int proc); int diag_cmd_chk_polling(struct diag_cmd_reg_entry_t *entry); +void diag_clear_masks(struct diag_md_session_t *info); void diag_record_stats(int type, int flag); diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c index ee11ba0a5dcc..10a38dcd812b 100644 --- a/drivers/char/diag/diagchar_core.c +++ b/drivers/char/diag/diagchar_core.c @@ -387,6 +387,27 @@ static uint32_t diag_translate_kernel_to_user_mask(uint32_t peripheral_mask) return ret; } +void diag_clear_masks(struct diag_md_session_t *info) +{ + int ret; + char cmd_disable_log_mask[] = { 0x73, 0, 0, 0, 0, 0, 0, 0}; + char cmd_disable_msg_mask[] = { 0x7D, 0x05, 0, 0, 0, 0, 0, 0}; + char cmd_disable_event_mask[] = { 0x60, 0}; + + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "diag: %s: masks clear request upon %s\n", __func__, + ((info) ? "ODL exit" : "USB Disconnection")); + + ret = diag_process_apps_masks(cmd_disable_log_mask, + sizeof(cmd_disable_log_mask), info); + ret = diag_process_apps_masks(cmd_disable_msg_mask, + sizeof(cmd_disable_msg_mask), info); + ret = diag_process_apps_masks(cmd_disable_event_mask, + sizeof(cmd_disable_event_mask), info); + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "diag:%s: masks cleared successfully\n", __func__); +} + static void diag_close_logging_process(const int pid) { int i; @@ -398,6 +419,12 @@ static void diag_close_logging_process(const int pid) if (!session_info) return; + diag_clear_masks(session_info); + + mutex_lock(&driver->diag_maskclear_mutex); + driver->mask_clear = 1; + mutex_unlock(&driver->diag_maskclear_mutex); + session_peripheral_mask = session_info->peripheral_mask; diag_md_session_close(session_info); for (i = 0; i < NUM_MD_SESSIONS; i++) @@ -473,9 +500,14 @@ static int diag_remove_client_entry(struct file *file) } static int diagchar_close(struct inode *inode, struct file *file) { + int ret; DIAG_LOG(DIAG_DEBUG_USERSPACE, "diag: process exit %s\n", current->comm); - return diag_remove_client_entry(file); + ret = diag_remove_client_entry(file); + mutex_lock(&driver->diag_maskclear_mutex); + driver->mask_clear = 0; + mutex_unlock(&driver->diag_maskclear_mutex); + return ret; } void diag_record_stats(int type, int flag) @@ -3354,6 +3386,7 @@ static int __init diagchar_init(void) non_hdlc_data.len = 0; mutex_init(&driver->hdlc_disable_mutex); mutex_init(&driver->diagchar_mutex); + mutex_init(&driver->diag_maskclear_mutex); mutex_init(&driver->diag_file_mutex); mutex_init(&driver->delayed_rsp_mutex); mutex_init(&apps_data_mutex); diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c index 7ead0f1c8a30..65bbe7cdd834 100644 --- a/drivers/char/diag/diagfwd.c +++ b/drivers/char/diag/diagfwd.c @@ -1225,8 +1225,6 @@ static int diagfwd_mux_open(int id, int mode) static int diagfwd_mux_close(int id, int mode) { - uint8_t i; - switch (mode) { case DIAG_USB_MODE: driver->usb_connected = 0; @@ -1241,15 +1239,16 @@ static int diagfwd_mux_close(int id, int mode) driver->md_session_mode == DIAG_MD_NONE) || (driver->md_session_mode == DIAG_MD_PERIPHERAL)) { /* - * In this case the channel must not be closed. This case - * indicates that the USB is removed but there is a client - * running in background with Memory Device mode + * This case indicates that the USB is removed + * but there is a client running in background + * with Memory Device mode. */ } else { - for (i = 0; i < NUM_PERIPHERALS; i++) { - diagfwd_close(i, TYPE_DATA); - diagfwd_close(i, TYPE_CMD); - } + /* + * With clearing of masks on ODL exit and + * USB disconnection, closing of the channel is + * not needed.This enables read and drop of stale packets. + */ /* Re enable HDLC encoding */ pr_debug("diag: In %s, re-enabling HDLC encoding\n", __func__); diff --git a/drivers/i2c/busses/i2c-msm-v2.c b/drivers/i2c/busses/i2c-msm-v2.c index f7586ecb0f9a..aa4c887ff5fc 100644 --- a/drivers/i2c/busses/i2c-msm-v2.c +++ b/drivers/i2c/busses/i2c-msm-v2.c @@ -32,6 +32,8 @@ #include <linux/dma-mapping.h> #include <linux/i2c.h> #include <linux/of.h> +#include <linux/gpio.h> +#include <linux/of_gpio.h> #include <linux/msm-sps.h> #include <linux/msm-bus.h> #include <linux/msm-bus-board.h> @@ -50,6 +52,10 @@ static int i2c_msm_xfer_wait_for_completion(struct i2c_msm_ctrl *ctrl, static int i2c_msm_pm_resume(struct device *dev); static void i2c_msm_pm_suspend(struct device *dev); static void i2c_msm_clk_path_init(struct i2c_msm_ctrl *ctrl); +static struct pinctrl_state * +i2c_msm_rsrcs_gpio_get_state(struct i2c_msm_ctrl *ctrl, const char *name); +static void i2c_msm_pm_pinctrl_state(struct i2c_msm_ctrl *ctrl, + bool runtime_active); /* string table for enum i2c_msm_xfer_mode_id */ const char * const i2c_msm_mode_str_tbl[] = { @@ -1902,74 +1908,81 @@ static void i2c_msm_qup_init(struct i2c_msm_ctrl *ctrl) "error on verifying HW support (I2C_MAST_GEN=0)\n"); } -/* - * qup_i2c_try_recover_bus_busy: issue QUP bus clear command - */ -static int qup_i2c_try_recover_bus_busy(struct i2c_msm_ctrl *ctrl) + +static void qup_i2c_recover_bit_bang(struct i2c_msm_ctrl *ctrl) { - int ret; - ulong min_sleep_usec; + int i, ret; + int gpio_clk; + int gpio_dat; + bool gpio_clk_status = false; + uint32_t status = readl_relaxed(ctrl->rsrcs.base + QUP_I2C_STATUS); + struct pinctrl_state *bitbang; - /* call i2c_msm_qup_init() to set core in idle state */ - i2c_msm_qup_init(ctrl); + disable_irq(ctrl->rsrcs.irq); + gpio_clk = of_get_named_gpio(ctrl->adapter.dev.of_node, "qcom,i2c-clk", + 0); + gpio_dat = of_get_named_gpio(ctrl->adapter.dev.of_node, "qcom,i2c-dat", + 0); - /* must be in run state for bus clear */ - ret = i2c_msm_qup_state_set(ctrl, QUP_STATE_RUN); - if (ret < 0) { - dev_err(ctrl->dev, "error: bus clear fail to set run state\n"); - return ret; + if (gpio_clk < 0 || gpio_dat < 0) { + dev_warn(ctrl->dev, "SW bigbang err: i2c gpios not known\n"); + goto recovery_exit; } - /* - * call i2c_msm_qup_xfer_init_run_state() to set clock dividers. - * the dividers are necessary for bus clear. - */ - i2c_msm_qup_xfer_init_run_state(ctrl); - - writel_relaxed(0x1, ctrl->rsrcs.base + QUP_I2C_MASTER_BUS_CLR); - - /* - * wait for recovery (9 clock pulse cycles) to complete. - * min_time = 9 clock *10 (1000% margin) - * max_time = 10* min_time - */ - min_sleep_usec = - max_t(ulong, (9 * 10 * USEC_PER_SEC) / ctrl->rsrcs.clk_freq_out, 100); + bitbang = i2c_msm_rsrcs_gpio_get_state(ctrl, "i2c_bitbang"); + if (bitbang) + ret = pinctrl_select_state(ctrl->rsrcs.pinctrl, bitbang); + if (!bitbang || ret) { + dev_err(ctrl->dev, "GPIO pins have no bitbang setting\n"); + goto recovery_exit; + } - usleep_range(min_sleep_usec, min_sleep_usec * 10); - return ret; -} + for (i = 0; i < 9; i++) { + if (gpio_get_value(gpio_dat) && gpio_clk_status) + break; + gpio_direction_output(gpio_clk, 0); + udelay(5); + gpio_direction_output(gpio_dat, 0); + udelay(5); + gpio_direction_input(gpio_clk); + udelay(5); + if (!gpio_get_value(gpio_clk)) + udelay(20); + if (!gpio_get_value(gpio_clk)) + usleep_range(10000, 10001); + gpio_clk_status = gpio_get_value(gpio_clk); + gpio_direction_input(gpio_dat); + udelay(5); + } -static int qup_i2c_recover_bus_busy(struct i2c_msm_ctrl *ctrl) -{ - u32 bus_clr, bus_active, status; - int retry = 0; - dev_info(ctrl->dev, "Executing bus recovery procedure (9 clk pulse)\n"); + i2c_msm_pm_pinctrl_state(ctrl, true); + udelay(10); - do { - qup_i2c_try_recover_bus_busy(ctrl); - bus_clr = readl_relaxed(ctrl->rsrcs.base + - QUP_I2C_MASTER_BUS_CLR); - status = readl_relaxed(ctrl->rsrcs.base + QUP_I2C_STATUS); - bus_active = status & I2C_STATUS_BUS_ACTIVE; - if (++retry >= I2C_QUP_MAX_BUS_RECOVERY_RETRY) - break; - } while (bus_clr || bus_active); + status = readl_relaxed(ctrl->rsrcs.base + QUP_I2C_STATUS); + if (!(status & I2C_STATUS_BUS_ACTIVE)) { + dev_info(ctrl->dev, "Bus busy cleared after %d clock cycles, " + "status %x\n", + i, status); + goto recovery_exit; + } - dev_info(ctrl->dev, "Bus recovery %s after %d retries\n", - (bus_clr || bus_active) ? "fail" : "success", retry); - return 0; + dev_warn(ctrl->dev, "Bus still busy, status %x\n", status); +recovery_exit: + enable_irq(ctrl->rsrcs.irq); } static int i2c_msm_qup_post_xfer(struct i2c_msm_ctrl *ctrl, int err) { + if (ctrl->xfer.err == I2C_MSM_ERR_ARB_LOST) + qup_i2c_recover_bit_bang(ctrl); + /* poll until bus is released */ if (i2c_msm_qup_poll_bus_active_unset(ctrl)) { if ((ctrl->xfer.err == I2C_MSM_ERR_ARB_LOST) || (ctrl->xfer.err == I2C_MSM_ERR_BUS_ERR) || (ctrl->xfer.err == I2C_MSM_ERR_TIMEOUT)) { if (i2c_msm_qup_slv_holds_bus(ctrl)) - qup_i2c_recover_bus_busy(ctrl); + qup_i2c_recover_bit_bang(ctrl); /* do not generalize error to EIO if its already set */ if (!err) diff --git a/drivers/input/touchscreen/synaptics_dsx_htc_2.6/synaptics_dsx_core.c b/drivers/input/touchscreen/synaptics_dsx_htc_2.6/synaptics_dsx_core.c index 0cf705bba644..90b6fc37284b 100644 --- a/drivers/input/touchscreen/synaptics_dsx_htc_2.6/synaptics_dsx_core.c +++ b/drivers/input/touchscreen/synaptics_dsx_htc_2.6/synaptics_dsx_core.c @@ -65,6 +65,7 @@ #define REPORT_2D_PRESSURE #define TEMP_FORCE_WA /* #define USE_DATA_SERVER */ +#define USE_I2C_SWITCH #define F12_DATA_15_WORKAROUND @@ -2856,6 +2857,35 @@ exit: return retval; } +static int synaptics_rmi4_f12_configure_lpwg( + struct synaptics_rmi4_data *rmi4_data, + const struct synaptics_rmi4_fn *fhandler) +{ + int retval; + struct synaptics_rmi4_f12_ctrl_27 ctrl_27 = { + .double_tap_enable = 1, + .lpwg_report_rate = 20, + .false_activation_threshold = 3, + .maximum_active_duration = 12, + .timer_1_duration = 15, + .maximum_active_duration_timeout = 10, + }; + const struct synaptics_rmi4_f12_extra_data *extra_data = + (const struct synaptics_rmi4_f12_extra_data *)fhandler->extra; + + retval = synaptics_rmi4_reg_write(rmi4_data, + fhandler->full_addr.ctrl_base + + extra_data->ctrl27_offset, + ctrl_27.data, + sizeof(ctrl_27.data)); + if (retval < 0) + dev_err(rmi4_data->pdev->dev.parent, + "%s: Failed to change lpwg settings\n", + __func__); + + return retval; +} + static int synaptics_rmi4_f12_init(struct synaptics_rmi4_data *rmi4_data, struct synaptics_rmi4_fn *fhandler, struct synaptics_rmi4_fn_desc *fd, @@ -3326,6 +3356,10 @@ static int synaptics_rmi4_f12_init(struct synaptics_rmi4_data *rmi4_data, printk("[TP]%s:Wakeup Gesture range (%d,%d) -> (%d,%d)\n", __func__, double_tap[0], double_tap[1], double_tap[2], double_tap[3]); + + retval = synaptics_rmi4_f12_configure_lpwg(rmi4_data, fhandler); + if (retval < 0) + return retval; } synaptics_rmi4_set_intr_mask(fhandler, fd, intr_count); @@ -4950,6 +4984,7 @@ static int synaptics_rmi4_reinit_device(struct synaptics_rmi4_data *rmi4_data) list_for_each_entry(fhandler, &rmi->support_fn_list, link) { if (fhandler->fn_number == SYNAPTICS_RMI4_F12) { synaptics_rmi4_f12_set_enables(rmi4_data, 0); + synaptics_rmi4_f12_configure_lpwg(rmi4_data, fhandler); break; } } @@ -5673,7 +5708,6 @@ static void synaptics_rmi4_f12_wg(struct synaptics_rmi4_data *rmi4_data, { int retval; unsigned char reporting_control[3]; - struct synaptics_rmi4_f12_ctrl_27 ctrl_27; struct synaptics_rmi4_f12_extra_data *extra_data; struct synaptics_rmi4_fn *fhandler; struct synaptics_rmi4_device_info *rmi; @@ -5699,47 +5733,10 @@ static void synaptics_rmi4_f12_wg(struct synaptics_rmi4_data *rmi4_data, return; } - retval = synaptics_rmi4_reg_read(rmi4_data, - fhandler->full_addr.ctrl_base + - extra_data->ctrl27_offset, - ctrl_27.data, - sizeof(ctrl_27.data)); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to change lpwg settings\n", - __func__); - return; - } - - if (enable) { + if (enable) reporting_control[2] = F12_WAKEUP_GESTURE_MODE; - ctrl_27.double_tap_enable = 1; - ctrl_27.lpwg_report_rate = 20; - ctrl_27.false_activation_threshold = 3; - ctrl_27.maximum_active_duration = 12; - ctrl_27.timer_1_duration = 15; - ctrl_27.maximum_active_duration_timeout = 10; - } else { + else reporting_control[2] = F12_CONTINUOUS_MODE; - ctrl_27.double_tap_enable = 0; - ctrl_27.lpwg_report_rate = 20; - ctrl_27.false_activation_threshold = 3; - ctrl_27.maximum_active_duration = 12; - ctrl_27.timer_1_duration = 15; - ctrl_27.maximum_active_duration_timeout = 10; - } - - retval = synaptics_rmi4_reg_write(rmi4_data, - fhandler->full_addr.ctrl_base + - extra_data->ctrl27_offset, - ctrl_27.data, - sizeof(ctrl_27.data)); - if (retval < 0) { - dev_err(rmi4_data->pdev->dev.parent, - "%s: Failed to change lpwg settings\n", - __func__); - return; - } retval = synaptics_rmi4_reg_write(rmi4_data, fhandler->full_addr.ctrl_base + @@ -5909,6 +5906,13 @@ exit: } mutex_unlock(&exp_data.mutex); +#ifdef USE_I2C_SWITCH + gpio_set_value(rmi4_data->hw_if->board_data->switch_gpio, 1); + dev_dbg(rmi4_data->pdev->dev.parent, + "%s: Switch I2C mux to sensor hub\n", + __func__); +#endif // USE_I2C_SWITCH + rmi4_data->suspend = true; return 0; @@ -5925,6 +5929,13 @@ static int synaptics_rmi4_resume(struct device *dev) if (rmi4_data->stay_awake) return 0; +#ifdef USE_I2C_SWITCH + gpio_set_value(rmi4_data->hw_if->board_data->switch_gpio, 0); + dev_dbg(rmi4_data->pdev->dev.parent, + "%s: Switch I2C mux to AP\n", + __func__); +#endif // USE_I2C_SWITCH + synaptics_rmi4_free_fingers(rmi4_data); if (rmi4_data->enable_wakeup_gesture) { @@ -5937,6 +5948,10 @@ static int synaptics_rmi4_resume(struct device *dev) rmi4_data->current_page = MASK_8BIT; synaptics_rmi4_sleep_enable(rmi4_data, false); +#ifdef USE_I2C_SWITCH + synaptics_rmi4_wakeup_gesture(rmi4_data, false); + synaptics_rmi4_force_cal(rmi4_data); +#endif synaptics_rmi4_irq_enable(rmi4_data, true, false); exit: diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h index f525c71f5da2..99e19fe93f54 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h @@ -234,7 +234,7 @@ struct msm_vfe_core_ops { struct msm_vfe_rdi_cfg *rdi_cfg, enum msm_vfe_input_src input_src); void (*get_error_mask)(uint32_t *error_mask0, uint32_t *error_mask1); - void (*process_error_status)(struct vfe_device *vfe_dev); + int (*process_error_status)(struct vfe_device *vfe_dev); void (*get_overflow_mask)(uint32_t *overflow_mask); void (*get_irq_mask)(struct vfe_device *vfe_dev, uint32_t *irq0_mask, uint32_t *irq1_mask); diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c index 062ff3bea7e6..69f9f7f3a974 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c @@ -484,8 +484,9 @@ static void msm_vfe32_get_overflow_mask(uint32_t *overflow_mask) *overflow_mask = 0x0; } -static void msm_vfe32_process_error_status(struct vfe_device *vfe_dev) +static int msm_vfe32_process_error_status(struct vfe_device *vfe_dev) { + int ret = 0; uint32_t error_status1 = vfe_dev->error_info.error_mask1; if (error_status1 & BIT(0)) @@ -565,6 +566,8 @@ static void msm_vfe32_process_error_status(struct vfe_device *vfe_dev) } if (error_status1 & BIT(22)) pr_err("%s: axi error\n", __func__); + + return ret; } static void msm_vfe32_read_irq_status(struct vfe_device *vfe_dev, diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c index 5b419ecfcbfd..5dc7b8ee498c 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c @@ -466,8 +466,9 @@ static void msm_vfe40_process_violation_status( pr_err("%s: realign buf cr violation\n", __func__); } -static void msm_vfe40_process_error_status(struct vfe_device *vfe_dev) +static int msm_vfe40_process_error_status(struct vfe_device *vfe_dev) { + int ret = 0; uint32_t error_status1 = vfe_dev->error_info.error_mask1; if (error_status1 & (1 << 0)) { pr_err_ratelimited("%s: vfe %d camif error status: 0x%x\n", @@ -562,6 +563,8 @@ static void msm_vfe40_process_error_status(struct vfe_device *vfe_dev) /* Update ab/ib values for any overflow that may have occured*/ if ((error_status1 >> 9) & 0x7FFF) msm_isp_update_last_overflow_ab_ib(vfe_dev); + + return ret; } static void msm_vfe40_read_irq_status(struct vfe_device *vfe_dev, diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp44.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp44.c index b1e515c81801..90564ac215e6 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp44.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp44.c @@ -310,8 +310,9 @@ static void msm_vfe44_process_violation_status( pr_err("%s: bpc violation\n", __func__); } -static void msm_vfe44_process_error_status(struct vfe_device *vfe_dev) +static int msm_vfe44_process_error_status(struct vfe_device *vfe_dev) { + int ret = 0; uint32_t error_status1 = vfe_dev->error_info.error_mask1; if (error_status1 & (1 << 0)) { pr_err("%s: camif error status: 0x%x\n", @@ -397,6 +398,8 @@ static void msm_vfe44_process_error_status(struct vfe_device *vfe_dev) vfe_dev->stats->bfscale_overflow++; pr_err("%s: status bf scale bus overflow\n", __func__); } + + return ret; } static void msm_vfe44_read_irq_status(struct vfe_device *vfe_dev, diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp46.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp46.c index 32ffd5906627..bab4e1923973 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp46.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp46.c @@ -281,8 +281,9 @@ static void msm_vfe46_process_violation_status( violation_status); } -static void msm_vfe46_process_error_status(struct vfe_device *vfe_dev) +static int msm_vfe46_process_error_status(struct vfe_device *vfe_dev) { + int ret = 0; uint32_t error_status1 = vfe_dev->error_info.error_mask1; if (error_status1 & (1 << 0)) { @@ -337,6 +338,8 @@ static void msm_vfe46_process_error_status(struct vfe_device *vfe_dev) pr_err("%s: status skin bhist bus overflow\n", __func__); if (error_status1 & (1 << 24)) pr_err("%s: status bf scale bus overflow\n", __func__); + + return ret; } static void msm_vfe46_read_irq_status(struct vfe_device *vfe_dev, diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c index 06effe701203..0e5565516e14 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c @@ -444,8 +444,9 @@ void msm_vfe47_process_violation_status( violation_status); } -void msm_vfe47_process_error_status(struct vfe_device *vfe_dev) +int msm_vfe47_process_error_status(struct vfe_device *vfe_dev) { + int ret = 0; uint32_t error_status1 = vfe_dev->error_info.error_mask1; if (error_status1 & (1 << 0)) { @@ -471,6 +472,8 @@ void msm_vfe47_process_error_status(struct vfe_device *vfe_dev) pr_err("%s: realign buf cr overflow\n", __func__); if (error_status1 & (1 << 7)) { msm_vfe47_process_violation_status(vfe_dev); + /* force overflow recovery for violation */ + ret = -1; } if (error_status1 & (1 << 9)) pr_err("%s: image master 0 bus overflow\n", __func__); @@ -506,6 +509,8 @@ void msm_vfe47_process_error_status(struct vfe_device *vfe_dev) pr_err("%s: status aec bg bus overflow\n", __func__); if (error_status1 & (1 << 25)) pr_err("%s: status dsp error\n", __func__); + + return ret; } void msm_vfe47_read_irq_status(struct vfe_device *vfe_dev, diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp47.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp47.h index f75d64f3ff69..ae134e6deba1 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp47.h +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp47.h @@ -158,7 +158,7 @@ void msm_vfe47_process_input_irq(struct vfe_device *vfe_dev, struct msm_isp_timestamp *ts); void msm_vfe47_process_violation_status( struct vfe_device *vfe_dev); -void msm_vfe47_process_error_status(struct vfe_device *vfe_dev); +int msm_vfe47_process_error_status(struct vfe_device *vfe_dev); void msm_vfe47_clear_status_reg(struct vfe_device *vfe_dev); int msm_vfe47_get_platform_data(struct vfe_device *vfe_dev); int msm_vfe47_enable_regulators(struct vfe_device *vfe_dev, int enable); diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c index 3c7a82858bbf..5e0b685aec80 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c @@ -3046,7 +3046,7 @@ static int msm_isp_request_frame(struct vfe_device *vfe_dev, */ if (((vfe_dev->axi_data.src_info[VFE_PIX_0].active) && ((frame_id <= vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id) || - (frame_id <= vfe_dev->axi_data.src_info[VFE_PIX_0].eof_id))) || + (frame_id <= (vfe_dev->axi_data.src_info[VFE_PIX_0].eof_id + 1)))) || ((!vfe_dev->axi_data.src_info[VFE_PIX_0].active) && (frame_id <= vfe_dev->axi_data.src_info[frame_src].frame_id)) || stream_info->undelivered_request_cnt >= MAX_BUFFERS_IN_HW) { diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c index d2b3629202b2..64c44421607b 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c @@ -184,7 +184,9 @@ uint32_t msm_isp_get_framedrop_period( void msm_isp_get_timestamp(struct msm_isp_timestamp *time_stamp, struct vfe_device *vfe_dev) { struct timespec ts; - do_gettimeofday(&(time_stamp->event_time)); + ktime_get_ts(&ts); + time_stamp->event_time.tv_sec = ts.tv_sec; + time_stamp->event_time.tv_usec = ts.tv_nsec/1000; if (vfe_dev->vt_enable) { msm_isp_get_avtimer_ts(time_stamp); time_stamp->buf_time.tv_sec = time_stamp->vt_time.tv_sec; @@ -1647,19 +1649,21 @@ static int msm_isp_process_iommu_page_fault(struct vfe_device *vfe_dev) return rc; } -void msm_isp_process_error_info(struct vfe_device *vfe_dev) +int msm_isp_process_error_info(struct vfe_device *vfe_dev) { + int ret = 0; struct msm_vfe_error_info *error_info = &vfe_dev->error_info; if (error_info->error_count == 1 || !(error_info->info_dump_frame_count % 100)) { - vfe_dev->hw_info->vfe_ops.core_ops. + ret = vfe_dev->hw_info->vfe_ops.core_ops. process_error_status(vfe_dev); error_info->error_mask0 = 0; error_info->error_mask1 = 0; error_info->camif_status = 0; error_info->violation_status = 0; } + return ret; } static inline void msm_isp_update_error_info(struct vfe_device *vfe_dev, @@ -1672,7 +1676,8 @@ static inline void msm_isp_update_error_info(struct vfe_device *vfe_dev, static void msm_isp_process_overflow_irq( struct vfe_device *vfe_dev, - uint32_t *irq_status0, uint32_t *irq_status1) + uint32_t *irq_status0, uint32_t *irq_status1, + uint32_t force_overflow) { uint32_t overflow_mask; @@ -1695,7 +1700,8 @@ static void msm_isp_process_overflow_irq( /*Check if any overflow bit is set*/ vfe_dev->hw_info->vfe_ops.core_ops. get_overflow_mask(&overflow_mask); - overflow_mask &= *irq_status1; + if (!force_overflow) + overflow_mask &= *irq_status1; if (overflow_mask) { struct msm_isp_event_data error_event; @@ -1812,7 +1818,7 @@ irqreturn_t msm_isp_process_irq(int irq_num, void *data) irq_status0); } msm_isp_process_overflow_irq(vfe_dev, - &irq_status0, &irq_status1); + &irq_status0, &irq_status1, 0); vfe_dev->hw_info->vfe_ops.core_ops. get_error_mask(&error_mask0, &error_mask1); @@ -1881,7 +1887,12 @@ void msm_isp_do_tasklet(unsigned long data) __func__); continue; } - msm_isp_process_error_info(vfe_dev); + if (msm_isp_process_error_info(vfe_dev) == -1) { + /* force overflow recovery */ + msm_isp_process_overflow_irq(vfe_dev, + &irq_status0, &irq_status1 ,1); + break; + } irq_ops->process_stats_irq(vfe_dev, irq_status0, irq_status1, pingpong_status, &ts); diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.h index a8a7ea05f68e..1cc24a97ca1f 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.h +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.h @@ -62,7 +62,7 @@ irqreturn_t msm_isp_process_irq(int irq_num, void *data); int msm_isp_set_src_state(struct vfe_device *vfe_dev, void *arg); void msm_isp_do_tasklet(unsigned long data); void msm_isp_update_error_frame_count(struct vfe_device *vfe_dev); -void msm_isp_process_error_info(struct vfe_device *vfe_dev); +int msm_isp_process_error_info(struct vfe_device *vfe_dev); int msm_isp_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh); int msm_isp_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh); long msm_isp_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg); diff --git a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c index d0e308e23050..26a76cf4fc64 100644 --- a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c +++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c @@ -880,7 +880,7 @@ static int msm_ispif_start_frame_boundary(struct ispif_device *ispif, return rc; } -static int msm_ispif_restart_frame_boundary(struct ispif_device *ispif, +static int msm_ispif_reconfig(struct ispif_device *ispif, struct msm_ispif_param_data *params) { int rc = 0; @@ -890,13 +890,11 @@ static int msm_ispif_restart_frame_boundary(struct ispif_device *ispif, rc = msm_ispif_reset(ispif); if (!rc) rc = msm_ispif_config(ispif, params); - if (!rc) - rc = msm_ispif_start_frame_boundary(ispif, params); if (!rc) - pr_info("ISPIF restart Successful\n"); + pr_info("ISPIF reconfig Successful\n"); else - pr_info("ISPIF restart Failed\n"); + pr_info("ISPIF reconfig Failed\n"); return rc; } @@ -1264,8 +1262,8 @@ static long msm_ispif_cmd(struct v4l2_subdev *sd, void *arg) rc = msm_ispif_start_frame_boundary(ispif, &pcdata->params); msm_ispif_io_dump_reg(ispif); break; - case ISPIF_RESTART_FRAME_BOUNDARY: - rc = msm_ispif_restart_frame_boundary(ispif, &pcdata->params); + case ISPIF_RECONFIG: + rc = msm_ispif_reconfig(ispif, &pcdata->params); msm_ispif_io_dump_reg(ispif); break; diff --git a/drivers/platform/msm/sps/sps_bam.c b/drivers/platform/msm/sps/sps_bam.c index f34242f29e2b..351a416a0f92 100644 --- a/drivers/platform/msm/sps/sps_bam.c +++ b/drivers/platform/msm/sps/sps_bam.c @@ -170,19 +170,19 @@ polling: } /* Process active pipe sources */ - pipe = list_first_entry(&dev->pipes_q, struct sps_pipe, list); - - list_for_each_entry(pipe, &dev->pipes_q, list) { - /* Check this pipe's bit in the source mask */ - if (BAM_PIPE_IS_ASSIGNED(pipe) + if (!list_empty(&dev->pipes_q)) { + list_for_each_entry(pipe, &dev->pipes_q, list) { + /* Check this pipe's bit in the source mask */ + if (BAM_PIPE_IS_ASSIGNED(pipe) && (!pipe->disconnecting) && (source & pipe->pipe_index_mask)) { - /* This pipe has an interrupt pending */ - pipe_handler(dev, pipe); - source &= ~pipe->pipe_index_mask; + /* This pipe has an interrupt pending */ + pipe_handler(dev, pipe); + source &= ~pipe->pipe_index_mask; + } + if (source == 0) + break; } - if (source == 0) - break; } /* Process any inactive pipe sources */ @@ -812,6 +812,7 @@ int sps_bam_pipe_connect(struct sps_pipe *bam_pipe, void *desc_buf = NULL; u32 pipe_index; int result; + unsigned long flags; /* Clear the client pipe state and hw init struct */ pipe_clear(bam_pipe); @@ -1048,8 +1049,10 @@ int sps_bam_pipe_connect(struct sps_pipe *bam_pipe, /* Indicate initialization is complete */ dev->pipes[pipe_index] = bam_pipe; + spin_lock_irqsave(&dev->isr_lock, flags); dev->pipe_active_mask |= 1UL << pipe_index; list_add_tail(&bam_pipe->list, &dev->pipes_q); + spin_unlock_irqrestore(&dev->isr_lock, flags); SPS_DBG2(dev, "sps:BAM %pa; pipe %d; pipe_index_mask:0x%x; pipe_active_mask:0x%x.\n", @@ -1083,6 +1086,7 @@ int sps_bam_pipe_disconnect(struct sps_bam *dev, u32 pipe_index) { struct sps_pipe *pipe; int result; + unsigned long flags; if (pipe_index >= dev->props.num_pipes) { SPS_ERR(dev, "sps:Invalid BAM %pa pipe: %d\n", BAM_ID(dev), @@ -1094,8 +1098,10 @@ int sps_bam_pipe_disconnect(struct sps_bam *dev, u32 pipe_index) pipe = dev->pipes[pipe_index]; if (BAM_PIPE_IS_ASSIGNED(pipe)) { if ((dev->pipe_active_mask & (1UL << pipe_index))) { + spin_lock_irqsave(&dev->isr_lock, flags); list_del(&pipe->list); dev->pipe_active_mask &= ~(1UL << pipe_index); + spin_unlock_irqrestore(&dev->isr_lock, flags); } dev->pipe_remote_mask &= ~(1UL << pipe_index); if (pipe->connect.options & SPS_O_NO_DISABLE) @@ -2346,6 +2352,7 @@ int sps_bam_get_free_count(struct sps_bam *dev, u32 pipe_index, int sps_bam_set_satellite(struct sps_bam *dev, u32 pipe_index) { struct sps_pipe *pipe = dev->pipes[pipe_index]; + unsigned long flags; /* * Switch to satellite control is only supported on processor @@ -2387,8 +2394,10 @@ int sps_bam_set_satellite(struct sps_bam *dev, u32 pipe_index) } /* Indicate satellite control */ + spin_lock_irqsave(&dev->isr_lock, flags); list_del(&pipe->list); dev->pipe_active_mask &= ~(1UL << pipe_index); + spin_unlock_irqrestore(&dev->isr_lock, flags); dev->pipe_remote_mask |= pipe->pipe_index_mask; pipe->state |= BAM_STATE_REMOTE; diff --git a/drivers/power/htc_battery.c b/drivers/power/htc_battery.c index 75937b780196..4cbb9b852e1f 100644 --- a/drivers/power/htc_battery.c +++ b/drivers/power/htc_battery.c @@ -81,6 +81,7 @@ static bool g_htc_battery_probe_done = false; static bool g_is_fcc_limited = false; static bool g_is_unknown_charger = false; static bool g_rerun_apsd_done = false; +static bool g_critical_shutdown = false; /* fake soc when set this flag */ bool g_test_power_monitor = false; @@ -1409,9 +1410,16 @@ static void batt_worker(struct work_struct *work) batt_level_adjust(time_since_last_update_ms); g_is_rep_level_ready = true; - /* STEP 7: force level=0 to trigger userspace shutdown - FIXME: need discussing with HW which condition needs force shutdown - */ + /* STEP 7: force level=0 to trigger userspace shutdown */ + if ((g_critical_shutdown || (htc_batt_info.force_shutdown_batt_vol && + (htc_batt_info.rep.batt_vol <= htc_batt_info.force_shutdown_batt_vol))) && + htc_batt_info.rep.batt_temp > 0) { + BATT_LOG("critical shutdown criteria: %dmV (set level=0 to force shutdown)", + htc_batt_info.force_shutdown_batt_vol); + htc_batt_info.rep.level = 0; + gs_update_PSY = true; + wake_lock(&htc_batt_info.batt_shutdown_lock); + } /* STEP 8: Update limited charge Dou to some returned device is cause by limit charge, @@ -2169,6 +2177,12 @@ void htc_battery_info_update(enum power_supply_property prop, int intval) htc_batt_schedule_batt_info_update(); } break; + case POWER_SUPPLY_PROP_CRITICAL_SHUTDOWN: + if (g_latest_chg_src == POWER_SUPPLY_TYPE_UNKNOWN) { + g_critical_shutdown = true; + htc_batt_schedule_batt_info_update(); + } + break; default: break; } @@ -3062,6 +3076,7 @@ static int __init htc_battery_init(void) wake_lock_init(&htc_batt_timer.battery_lock, WAKE_LOCK_SUSPEND, "htc_battery"); wake_lock_init(&htc_batt_info.charger_exist_lock, WAKE_LOCK_SUSPEND,"charger_exist_lock"); + wake_lock_init(&htc_batt_info.batt_shutdown_lock, WAKE_LOCK_SUSPEND, "batt_shutdown"); /* init battery parameters. */ htc_batt_info.rep.batt_vol = 4000; @@ -3082,6 +3097,7 @@ static int __init htc_battery_init(void) htc_batt_info.smooth_chg_full_delay_min = 3; htc_batt_info.decreased_batt_level_check = 1; htc_batt_info.critical_low_voltage_mv = 3200; + htc_batt_info.force_shutdown_batt_vol = 3050; htc_batt_info.batt_full_voltage_mv = 4350; htc_batt_info.batt_full_current_ma = 300; htc_batt_info.batt_eoc_current_ma = 50; diff --git a/drivers/power/qpnp-fg.c b/drivers/power/qpnp-fg.c index 308dffa6c1b8..a7842de7b20b 100644 --- a/drivers/power/qpnp-fg.c +++ b/drivers/power/qpnp-fg.c @@ -332,6 +332,7 @@ static int fg_reset_on_lockup; #ifdef CONFIG_HTC_BATT /* Enable batterydebug log*/ bool g_fg_flag_enable_batt_debug_log = false; +int g_empty_soc_irq_count = 0; #endif static int fg_sense_type = -EINVAL; @@ -636,6 +637,8 @@ struct fg_chip { struct fg_wakeup_source sanity_wakeup_source; u8 last_beat_count; #ifdef CONFIG_HTC_BATT + struct delayed_work clear_empty_soc_irq_counter; + struct delayed_work rearm_empty_soc_irq_work; int batt_full_charge_criteria_ma; int batt_fcc_ma; int batt_capacity_mah; @@ -4904,6 +4907,9 @@ static irqreturn_t fg_jeita_soft_hot_irq_handler(int irq, void *_chip) bool batt_warm; union power_supply_propval val = {0, }; + if (!is_charger_available(chip)) + return IRQ_HANDLED; + rc = fg_read(chip, ®val, INT_RT_STS(chip->batt_base), 1); if (rc) { pr_err("spmi read failed: addr=%03X, rc=%d\n", @@ -4947,6 +4953,9 @@ static irqreturn_t fg_jeita_soft_cold_irq_handler(int irq, void *_chip) bool batt_cool; union power_supply_propval val = {0, }; + if (!is_charger_available(chip)) + return IRQ_HANDLED; + rc = fg_read(chip, ®val, INT_RT_STS(chip->batt_base), 1); if (rc) { pr_err("spmi read failed: addr=%03X, rc=%d\n", @@ -5194,6 +5203,70 @@ static irqreturn_t fg_soc_irq_handler(int irq, void *_chip) return IRQ_HANDLED; } +#ifdef CONFIG_HTC_BATT +#define CLEAR_EMPTY_SOC_IRQ_COUNTER_MS 30000 +#define REARM_EMPTY_SOC_IRQ_MS 1000 +#define FG_ALG_SYSCTL_1 0x4B0 +#define ALERT_CFG_OFFSET 3 +#define IRQ_USE_VOLTAGE_HYST_BIT BIT(0) +#define EMPTY_FROM_VOLTAGE_BIT BIT(1) +#define EMPTY_FROM_SOC_BIT BIT(2) +#define EMPTY_SOC_IRQ_MASK (IRQ_USE_VOLTAGE_HYST_BIT | \ + EMPTY_FROM_SOC_BIT | \ + EMPTY_FROM_VOLTAGE_BIT) + +static void clear_empty_soc_irq_counter(struct work_struct *work) +{ + pr_info("clear empty_soc irq counter\n"); + g_empty_soc_irq_count = 0; +} + +static void rearm_empty_soc_irq_work(struct work_struct *work) +{ + int rc; + if (!the_chip) { + pr_err("[Battery_FDA] Called before init\n"); + return; + } + + /* + * Clear bits 0-2 in 0x4B3 and set them again to make empty_soc irq + * trigger again. + */ + rc = fg_mem_masked_write(the_chip, FG_ALG_SYSCTL_1, EMPTY_SOC_IRQ_MASK, + 0, ALERT_CFG_OFFSET); + if (rc) { + pr_err("failed to write to 0x4B3 rc=%d\n", rc); + return; + } + + /* Wait for a FG cycle before enabling empty soc irq configuration */ + msleep(FG_CYCLE_MS); + + rc = fg_mem_masked_write(the_chip, FG_ALG_SYSCTL_1, EMPTY_SOC_IRQ_MASK, + EMPTY_SOC_IRQ_MASK, ALERT_CFG_OFFSET); + if (rc) { + pr_err("failed to write to 0x4B3 rc=%d\n", rc); + return; + } +} + +#define CRITICAL_SHUTDOWN_COUNT 3 +static void rearm_empty_soc_irq(void) +{ + if (!the_chip) { + pr_err("[Battery_FDA] Called before init\n"); + return; + } + + if (delayed_work_pending(&the_chip->rearm_empty_soc_irq_work)) + cancel_delayed_work_sync(&the_chip->rearm_empty_soc_irq_work); + if (g_empty_soc_irq_count < CRITICAL_SHUTDOWN_COUNT) + schedule_delayed_work(&the_chip->rearm_empty_soc_irq_work, + REARM_EMPTY_SOC_IRQ_MS); +} +#endif /* CONFIG_HTC_BATT */ + static irqreturn_t fg_empty_soc_irq_handler(int irq, void *_chip) { struct fg_chip *chip = _chip; @@ -5207,8 +5280,10 @@ static irqreturn_t fg_empty_soc_irq_handler(int irq, void *_chip) goto done; } +#ifndef CONFIG_HTC_BATT if (fg_debug_mask & FG_IRQS) pr_info("triggered 0x%x\n", soc_rt_sts); +#endif if (fg_is_batt_empty(chip)) { fg_stay_awake(&chip->empty_check_wakeup_source); schedule_delayed_work(&chip->check_empty_work, @@ -5217,6 +5292,26 @@ static irqreturn_t fg_empty_soc_irq_handler(int irq, void *_chip) chip->soc_empty = false; } +#ifdef CONFIG_HTC_BATT + /* Clear critical shutdown count after 30secs */ + if (!delayed_work_pending(&chip->clear_empty_soc_irq_counter)) + schedule_delayed_work(&chip->clear_empty_soc_irq_counter, + CLEAR_EMPTY_SOC_IRQ_COUNTER_MS); + + if (g_empty_soc_irq_count < CRITICAL_SHUTDOWN_COUNT + && fg_is_batt_empty(chip)) + g_empty_soc_irq_count++; + + pr_info("triggered=0x%x, vbatt=%dmV, irq_count:%d, is_batt_empty=%d\n", + soc_rt_sts, get_sram_prop_now(chip, FG_DATA_VOLTAGE) / 1000, + g_empty_soc_irq_count, fg_is_batt_empty(chip)); + if (g_empty_soc_irq_count >= CRITICAL_SHUTDOWN_COUNT) + htc_battery_info_update(POWER_SUPPLY_PROP_CRITICAL_SHUTDOWN, + get_sram_prop_now(chip, FG_DATA_VOLTAGE) / 1000); + + rearm_empty_soc_irq(); +#endif /* CONFIG_HTC_BATT */ + done: return IRQ_HANDLED; } @@ -6703,7 +6798,9 @@ static int update_irq_volt_empty(struct fg_chip *chip) data = (u8)VOLT_UV_TO_VOLTCMP8(volt_mv * 1000); +#ifndef CONFIG_HTC_BATT if (fg_debug_mask & FG_STATUS) +#endif /* CONFIG_HTC_BATT */ pr_info("voltage = %d, converted_raw = %04x\n", volt_mv, data); return fg_mem_write(chip, &data, settings[FG_MEM_IRQ_VOLT_EMPTY].address, 1, @@ -8612,6 +8709,10 @@ static int fg_probe(struct spmi_device *spmi) mutex_init(&chip->rslow_comp.lock); mutex_init(&chip->sysfs_restart_lock); mutex_init(&chip->ima_recovery_lock); +#ifdef CONFIG_HTC_BATT + INIT_DELAYED_WORK(&chip->clear_empty_soc_irq_counter, clear_empty_soc_irq_counter); + INIT_DELAYED_WORK(&chip->rearm_empty_soc_irq_work, rearm_empty_soc_irq_work); +#endif /* CONFIG_HTC_BATT */ INIT_DELAYED_WORK(&chip->update_jeita_setting, update_jeita_setting); INIT_DELAYED_WORK(&chip->update_sram_data, update_sram_data_work); INIT_DELAYED_WORK(&chip->update_temp_work, update_temp_data); diff --git a/drivers/power/qpnp-smbcharger.c b/drivers/power/qpnp-smbcharger.c index df37a4603a8c..702977bea3db 100644 --- a/drivers/power/qpnp-smbcharger.c +++ b/drivers/power/qpnp-smbcharger.c @@ -306,6 +306,7 @@ struct smbchg_chip { #define HARD_TEMP_MASK SMB_MASK(6, 5) #define SOFT_TEMP_MASK SMB_MASK(3, 0) #define SKIP_HARD_LIMIT_CHECK_LEVEL 70 +#define SKIP_HARD_LIMIT_CHECK_VBAT_MV 3900 static struct smbchg_chip *the_chip; static bool g_is_batt_full_eoc_stop = false; static void handle_usb_insertion(struct smbchg_chip *chip); @@ -7640,32 +7641,27 @@ void check_charger_ability(int aicl_level) { union power_supply_propval prop = {0,}; int rc, usb_supply_type; - u8 reg; - int level; + int level = 0, vbat_mv = 0; if (!the_chip) { pr_err("called before init\n"); return; } + vbat_mv = get_prop_batt_voltage_now(the_chip)/1000; level = get_prop_batt_capacity(the_chip); rc = the_chip->usb_psy->get_property(the_chip->usb_psy, POWER_SUPPLY_PROP_TYPE, &prop); usb_supply_type = prop.intval; - pr_smb(PR_STATUS, "CHG_TYPE is %d, AICL is %d, level is %d\n", - usb_supply_type, aicl_level, level); + pr_smb(PR_STATUS, "CHG_TYPE = %d, AICL = %d, level = %d, vbat_mv = %d, hard_limit = %d\n", + usb_supply_type, aicl_level, level, vbat_mv, is_smbchg_hard_limit(the_chip)); if (usb_supply_type != POWER_SUPPLY_TYPE_USB_DCP && usb_supply_type != POWER_SUPPLY_TYPE_USB_TYPE_C) return; - //checking for hard limit behavior - rc = smbchg_read(the_chip, ®, - the_chip->chgr_base + FV_STS, 1); - if (rc) - pr_err("Failed to read FV state rc=%d\n", rc); - pr_smb(PR_STATUS, "FV status = %02x, Hard Limit = %d\n", reg, ((reg & FV_AICL_STS_BIT)!=0)); - if (((reg & FV_AICL_STS_BIT) == 0) && (level > SKIP_HARD_LIMIT_CHECK_LEVEL)) { + if ((!is_smbchg_hard_limit(the_chip)) && + ((level > SKIP_HARD_LIMIT_CHECK_LEVEL) || (vbat_mv > SKIP_HARD_LIMIT_CHECK_VBAT_MV))) { if (aicl_level > USB_MA_2000) { rc = vote(the_chip->usb_icl_votable, PSY_ICL_VOTER, true, USB_MA_2000); diff --git a/drivers/soc/qcom/pil-q6v5-mss.c b/drivers/soc/qcom/pil-q6v5-mss.c index 8e1a4c714771..9cef023dd919 100644 --- a/drivers/soc/qcom/pil-q6v5-mss.c +++ b/drivers/soc/qcom/pil-q6v5-mss.c @@ -39,16 +39,16 @@ #define MAX_VDD_MSS_UV 1150000 #define PROXY_TIMEOUT_MS 10000 -#define MAX_SSR_REASON_LEN 81U #define STOP_ACK_TIMEOUT_MS 1000 #define subsys_to_drv(d) container_of(d, struct modem_data, subsys_desc) -static void log_modem_sfr(void) +static void log_modem_sfr(struct modem_data *drv) { u32 size; - char *smem_reason, reason[MAX_SSR_REASON_LEN]; + char *smem_reason, *reason; + reason = drv->subsys_desc.last_crash_reason; smem_reason = smem_get_entry_no_rlock(SMEM_SSR_REASON_MSS0, &size, 0, SMEM_ANY_HOST_FLAG); if (!smem_reason || !size) { @@ -69,7 +69,7 @@ static void log_modem_sfr(void) static void restart_modem(struct modem_data *drv) { - log_modem_sfr(); + log_modem_sfr(drv); drv->ignore_errors = true; subsystem_restart_dev(drv->subsys); } diff --git a/drivers/soc/qcom/subsys-pil-tz.c b/drivers/soc/qcom/subsys-pil-tz.c index f98cfbc8d947..d1d6608ddb2a 100644 --- a/drivers/soc/qcom/subsys-pil-tz.c +++ b/drivers/soc/qcom/subsys-pil-tz.c @@ -36,7 +36,6 @@ #define XO_FREQ 19200000 #define PROXY_TIMEOUT_MS 10000 -#define MAX_SSR_REASON_LEN 81U #define STOP_ACK_TIMEOUT_MS 1000 #define CRASH_STOP_ACK_TO_MS 200 @@ -776,15 +775,16 @@ static struct pil_reset_ops pil_ops_trusted = { .proxy_unvote = pil_remove_proxy_vote, }; -static void log_failure_reason(const struct pil_tz_data *d) +static void log_failure_reason(struct pil_tz_data *d) { u32 size; - char *smem_reason, reason[MAX_SSR_REASON_LEN]; + char *smem_reason, *reason; const char *name = d->subsys_desc.name; if (d->smem_id == -1) return; + reason = d->subsys_desc.last_crash_reason; smem_reason = smem_get_entry_no_rlock(d->smem_id, &size, 0, SMEM_ANY_HOST_FLAG); if (!smem_reason || !size) { diff --git a/drivers/soc/qcom/subsystem_restart.c b/drivers/soc/qcom/subsystem_restart.c index 016e7b89be87..20b417555e19 100644 --- a/drivers/soc/qcom/subsystem_restart.c +++ b/drivers/soc/qcom/subsystem_restart.c @@ -184,6 +184,8 @@ struct subsys_device { struct list_head list; }; +static int is_ramdump_enabled(struct subsys_device *dev); + static struct subsys_device *to_subsys(struct device *d) { return container_of(d, struct subsys_device, dev); @@ -223,6 +225,15 @@ static ssize_t crash_count_show(struct device *dev, return snprintf(buf, PAGE_SIZE, "%d\n", to_subsys(dev)->crash_count); } +static ssize_t crash_reason_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + if(is_ramdump_enabled(to_subsys(dev))) + return snprintf(buf, PAGE_SIZE, "%s\n", to_subsys(dev)->desc->last_crash_reason); + + return snprintf(buf, PAGE_SIZE, "\n"); +} + static ssize_t restart_level_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -347,6 +358,7 @@ static struct device_attribute subsys_attrs[] = { __ATTR_RO(name), __ATTR_RO(state), __ATTR_RO(crash_count), + __ATTR_RO(crash_reason), __ATTR(restart_level, 0644, restart_level_show, restart_level_store), __ATTR(firmware_name, 0644, firmware_name_show, firmware_name_store), __ATTR(system_debug, 0644, system_debug_show, system_debug_store), diff --git a/drivers/staging/qcacld-2.0/CORE/HDD/inc/wlan_hdd_cfg.h b/drivers/staging/qcacld-2.0/CORE/HDD/inc/wlan_hdd_cfg.h index 1a925415b84d..4df26571e0e1 100644 --- a/drivers/staging/qcacld-2.0/CORE/HDD/inc/wlan_hdd_cfg.h +++ b/drivers/staging/qcacld-2.0/CORE/HDD/inc/wlan_hdd_cfg.h @@ -2659,12 +2659,16 @@ This feature requires the dependent cfg.ini "gRoamPrefer5GHz" set to 1 */ * 0x1 - Enable mgmt pkt logs (no probe req/rsp). * 0x2 - Enable EAPOL pkt logs. * 0x4 - Enable DHCP pkt logs. + * 0x8 - Enable mgmt. action pkt logs. + * 0x10 - Enable ARP packet logs. + * 0x20 - Enable ICMPv6 NS packet logs. + * 0x40 - Enable ICMPv6 NA packet logs. * 0x0 - Disable all the above connection related logs. */ #define CFG_ENABLE_DEBUG_CONNECT_ISSUE "gEnableDebugLog" #define CFG_ENABLE_DEBUG_CONNECT_ISSUE_MIN (0) #define CFG_ENABLE_DEBUG_CONNECT_ISSUE_MAX (0xFF) -#define CFG_ENABLE_DEBUG_CONNECT_ISSUE_DEFAULT (6) +#define CFG_ENABLE_DEBUG_CONNECT_ISSUE_DEFAULT (0x40 | 0x20 | 0x10 | 0x04 | 0x02) /* * RX packet handling options diff --git a/drivers/staging/qcacld-2.0/CORE/HDD/src/wlan_hdd_cfg80211.c b/drivers/staging/qcacld-2.0/CORE/HDD/src/wlan_hdd_cfg80211.c index 0387b0dc11d5..e45b70456011 100644 --- a/drivers/staging/qcacld-2.0/CORE/HDD/src/wlan_hdd_cfg80211.c +++ b/drivers/staging/qcacld-2.0/CORE/HDD/src/wlan_hdd_cfg80211.c @@ -18861,6 +18861,10 @@ static int __wlan_hdd_cfg80211_disconnect( struct wiphy *wiphy, reasonCode = pHddCtx->cfg_ini->gEnableDeauthToDisassocMap ? eCSR_DISCONNECT_REASON_STA_HAS_LEFT : eCSR_DISCONNECT_REASON_DEAUTH; + vos_flush_logs(WLAN_LOG_TYPE_NON_FATAL, + WLAN_LOG_INDICATOR_FRAMEWORK, + WLAN_LOG_REASON_CODE_FRAMEWORK, + DUMP_PACKET_TRACE); break; case WLAN_REASON_DISASSOC_STA_HAS_LEFT: reasonCode = eCSR_DISCONNECT_REASON_STA_HAS_LEFT; @@ -23169,7 +23173,7 @@ int __wlan_hdd_cfg80211_resume_wlan(struct wiphy *wiphy) * results in app's is in suspended state and not able to * process the connect request to AP */ - hdd_prevent_suspend_timeout(2000, + hdd_prevent_suspend_timeout(1000, WIFI_POWER_EVENT_WAKELOCK_RESUME_WLAN); cfg80211_sched_scan_results(pHddCtx->wiphy); } diff --git a/drivers/staging/qcacld-2.0/CORE/HDD/src/wlan_hdd_softap_tx_rx.c b/drivers/staging/qcacld-2.0/CORE/HDD/src/wlan_hdd_softap_tx_rx.c index 45d9f20be0dd..e927073e3318 100644 --- a/drivers/staging/qcacld-2.0/CORE/HDD/src/wlan_hdd_softap_tx_rx.c +++ b/drivers/staging/qcacld-2.0/CORE/HDD/src/wlan_hdd_softap_tx_rx.c @@ -365,13 +365,24 @@ int __hdd_softap_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) /* Proto Trace enabled */ proto_type = vos_pkt_get_proto_type(skb, hddCtxt->cfg_ini->gEnableDebugLog, 0); - if (VOS_PKT_TRAC_TYPE_EAPOL & proto_type) - { + switch (proto_type) { + case VOS_PKT_TRAC_TYPE_EAPOL: vos_pkt_trace_buf_update("HA:T:EPL"); - } - else if (VOS_PKT_TRAC_TYPE_DHCP & proto_type) - { + break; + case VOS_PKT_TRAC_TYPE_DHCP: hdd_dhcp_pkt_trace_buf_update(skb, TX_PATH, AP); + break; + case VOS_PKT_TRAC_TYPE_ARP: + vos_pkt_trace_buf_update("HA:T:ARP"); + break; + case VOS_PKT_TRAC_TYPE_NS: + vos_pkt_trace_buf_update("HA:T:NS"); + break; + case VOS_PKT_TRAC_TYPE_NA: + vos_pkt_trace_buf_update("HA:T:NA"); + break; + default: + break; } } #endif /* QCA_PKT_PROTO_TRACE */ @@ -842,10 +853,25 @@ VOS_STATUS hdd_softap_rx_packet_cbk(v_VOID_t *vosContext, (pHddCtx->cfg_ini->gEnableDebugLog & VOS_PKT_TRAC_TYPE_DHCP)) { proto_type = vos_pkt_get_proto_type(skb, pHddCtx->cfg_ini->gEnableDebugLog, 0); - if (VOS_PKT_TRAC_TYPE_EAPOL & proto_type) - vos_pkt_trace_buf_update("HA:R:EPL"); - else if (VOS_PKT_TRAC_TYPE_DHCP & proto_type) - hdd_dhcp_pkt_trace_buf_update(skb, RX_PATH, AP); + switch (proto_type) { + case VOS_PKT_TRAC_TYPE_EAPOL: + vos_pkt_trace_buf_update("HA:R:EPL"); + break; + case VOS_PKT_TRAC_TYPE_DHCP: + hdd_dhcp_pkt_trace_buf_update(skb, RX_PATH, AP); + break; + case VOS_PKT_TRAC_TYPE_ARP: + vos_pkt_trace_buf_update("HA:R:ARP"); + break; + case VOS_PKT_TRAC_TYPE_NS: + vos_pkt_trace_buf_update("HA:R:NS"); + break; + case VOS_PKT_TRAC_TYPE_NA: + vos_pkt_trace_buf_update("HA:R:NA"); + break; + default: + break; + } } #endif /* QCA_PKT_PROTO_TRACE */ diff --git a/drivers/staging/qcacld-2.0/CORE/HDD/src/wlan_hdd_tx_rx.c b/drivers/staging/qcacld-2.0/CORE/HDD/src/wlan_hdd_tx_rx.c index 382bb8f6a460..507170a10072 100644 --- a/drivers/staging/qcacld-2.0/CORE/HDD/src/wlan_hdd_tx_rx.c +++ b/drivers/staging/qcacld-2.0/CORE/HDD/src/wlan_hdd_tx_rx.c @@ -611,13 +611,24 @@ int __hdd_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) { proto_type = vos_pkt_get_proto_type(skb, hddCtxt->cfg_ini->gEnableDebugLog, 0); - if (VOS_PKT_TRAC_TYPE_EAPOL & proto_type) - { + switch (proto_type) { + case VOS_PKT_TRAC_TYPE_EAPOL: vos_pkt_trace_buf_update("ST:T:EPL"); - } - else if (VOS_PKT_TRAC_TYPE_DHCP & proto_type) - { + break; + case VOS_PKT_TRAC_TYPE_DHCP: hdd_dhcp_pkt_trace_buf_update(skb, TX_PATH, STA); + break; + case VOS_PKT_TRAC_TYPE_ARP: + vos_pkt_trace_buf_update("ST:T:ARP"); + break; + case VOS_PKT_TRAC_TYPE_NS: + vos_pkt_trace_buf_update("ST:T:NS"); + break; + case VOS_PKT_TRAC_TYPE_NA: + vos_pkt_trace_buf_update("ST:T:NA"); + break; + default: + break; } } #endif /* QCA_PKT_PROTO_TRACE */ @@ -1214,10 +1225,25 @@ VOS_STATUS hdd_rx_packet_cbk(v_VOID_t *vosContext, (pHddCtx->cfg_ini->gEnableDebugLog & VOS_PKT_TRAC_TYPE_DHCP)) { proto_type = vos_pkt_get_proto_type(skb, pHddCtx->cfg_ini->gEnableDebugLog, 0); - if (VOS_PKT_TRAC_TYPE_EAPOL & proto_type) - vos_pkt_trace_buf_update("ST:R:EPL"); - else if (VOS_PKT_TRAC_TYPE_DHCP & proto_type) - hdd_dhcp_pkt_trace_buf_update(skb, RX_PATH, STA); + switch (proto_type) { + case VOS_PKT_TRAC_TYPE_EAPOL: + vos_pkt_trace_buf_update("ST:R:EPL"); + break; + case VOS_PKT_TRAC_TYPE_DHCP: + hdd_dhcp_pkt_trace_buf_update(skb, RX_PATH, STA); + break; + case VOS_PKT_TRAC_TYPE_ARP: + vos_pkt_trace_buf_update("ST:R:ARP"); + break; + case VOS_PKT_TRAC_TYPE_NS: + vos_pkt_trace_buf_update("ST:R:NS"); + break; + case VOS_PKT_TRAC_TYPE_NA: + vos_pkt_trace_buf_update("ST:R:NA"); + break; + default: + break; + } } #endif /* QCA_PKT_PROTO_TRACE */ diff --git a/drivers/staging/qcacld-2.0/CORE/MAC/inc/qwlan_version.h b/drivers/staging/qcacld-2.0/CORE/MAC/inc/qwlan_version.h index c59d6765883c..8011c2828f8c 100644 --- a/drivers/staging/qcacld-2.0/CORE/MAC/inc/qwlan_version.h +++ b/drivers/staging/qcacld-2.0/CORE/MAC/inc/qwlan_version.h @@ -44,7 +44,7 @@ BRIEF DESCRIPTION: #define QWLAN_VERSION_EXTRA "" #define QWLAN_VERSION_BUILD 26 -#define QWLAN_VERSIONSTR "4.4.25.026" +#define QWLAN_VERSIONSTR "4.4.25.027" #define AR6320_REV1_VERSION 0x5000000 diff --git a/drivers/staging/qcacld-2.0/CORE/MAC/src/pe/lim/limFT.c b/drivers/staging/qcacld-2.0/CORE/MAC/src/pe/lim/limFT.c index 550e36ce48bb..e69d6b5ee7b2 100644 --- a/drivers/staging/qcacld-2.0/CORE/MAC/src/pe/lim/limFT.c +++ b/drivers/staging/qcacld-2.0/CORE/MAC/src/pe/lim/limFT.c @@ -991,14 +991,14 @@ void limFillFTSession(tpAniSirGlobal pMac, #ifdef WLAN_FEATURE_11W pftSessionEntry->limRmfEnabled = psessionEntry->limRmfEnabled; - if (psessionEntry->limRmfEnabled) { - psessionEntry->pmfComebackTimerInfo.pMac = pMac; - psessionEntry->pmfComebackTimerInfo.sessionID = + if (pftSessionEntry->limRmfEnabled) { + pftSessionEntry->pmfComebackTimerInfo.pMac = pMac; + pftSessionEntry->pmfComebackTimerInfo.sessionID = psessionEntry->smeSessionId; - vosStatus = vos_timer_init(&psessionEntry->pmfComebackTimer, + vosStatus = vos_timer_init(&pftSessionEntry->pmfComebackTimer, VOS_TIMER_TYPE_SW, limPmfComebackTimerCallback, - (void *)&psessionEntry->pmfComebackTimerInfo); + (void *)&pftSessionEntry->pmfComebackTimerInfo); if (VOS_STATUS_SUCCESS != vosStatus) { limLog(pMac, LOGP, FL("cannot init pmf comeback timer.")); diff --git a/drivers/staging/qcacld-2.0/CORE/MAC/src/pe/lim/limLinkMonitoringAlgo.c b/drivers/staging/qcacld-2.0/CORE/MAC/src/pe/lim/limLinkMonitoringAlgo.c index 2c1581767ce9..b9811a31fb17 100644 --- a/drivers/staging/qcacld-2.0/CORE/MAC/src/pe/lim/limLinkMonitoringAlgo.c +++ b/drivers/staging/qcacld-2.0/CORE/MAC/src/pe/lim/limLinkMonitoringAlgo.c @@ -462,11 +462,19 @@ void limHandleHeartBeatFailure(tpAniSirGlobal pMac,tpPESession psessionEntry) { if (!pMac->sys.gSysEnableLinkMonitorMode) return; + /* Ignore HB if channel switch is in progress */ + if (psessionEntry->gLimSpecMgmt.dot11hChanSwState == + eLIM_11H_CHANSW_RUNNING) { + limLog(pMac, LOGE, + FL("Ignore Heartbeat failure as Channel switch is in progress")); + pMac->pmm.inMissedBeaconScenario = false; + return; + } /** * Beacon frame not received within heartbeat timeout. */ - PELOGW(limLog(pMac, LOGW, FL("Heartbeat Failure"));) + limLog(pMac, LOGW, FL("Heartbeat Failure")); pMac->lim.gLimHBfailureCntInLinkEstState++; /** diff --git a/drivers/staging/qcacld-2.0/CORE/MAC/src/pe/lim/limUtils.c b/drivers/staging/qcacld-2.0/CORE/MAC/src/pe/lim/limUtils.c index 7a40b74cee40..c907ef43c337 100644 --- a/drivers/staging/qcacld-2.0/CORE/MAC/src/pe/lim/limUtils.c +++ b/drivers/staging/qcacld-2.0/CORE/MAC/src/pe/lim/limUtils.c @@ -2092,9 +2092,10 @@ void limProcessChannelSwitchTimeout(tpAniSirGlobal pMac) tANI_U8 channel; // This is received and stored from channelSwitch Action frame tANI_U8 isSessionPowerActive = false; - if((psessionEntry = peFindSessionBySessionId(pMac, pMac->lim.limTimers.gLimChannelSwitchTimer.sessionId))== NULL) - { - limLog(pMac, LOGP,FL("Session Does not exist for given sessionID")); + psessionEntry = peFindSessionBySessionId(pMac, + pMac->lim.limTimers.gLimChannelSwitchTimer.sessionId); + if (!psessionEntry) { + limLog(pMac, LOGW, FL("Session Does not exist for given sessionID")); return; } @@ -2104,6 +2105,13 @@ void limProcessChannelSwitchTimeout(tpAniSirGlobal pMac) GET_LIM_SYSTEM_ROLE(psessionEntry));) return; } + if (psessionEntry->gLimSpecMgmt.dot11hChanSwState != + eLIM_11H_CHANSW_RUNNING) { + limLog(pMac, LOGW, + FL("Channel switch timer should not have been running in state %d"), + psessionEntry->gLimSpecMgmt.dot11hChanSwState); + return; + } if(pMac->psOffloadEnabled) { @@ -2113,7 +2121,6 @@ void limProcessChannelSwitchTimeout(tpAniSirGlobal pMac) { isSessionPowerActive = limIsSystemInActiveState(pMac); } - channel = psessionEntry->gLimChannelSwitch.primaryChannel; /* @@ -2173,13 +2180,19 @@ void limProcessChannelSwitchTimeout(tpAniSirGlobal pMac) return; } - /* If the channel-list that AP is asking us to switch is invalid, + /* + * If the channel-list that AP is asking us to switch is invalid, * then we cannot switch the channel. Just disassociate from AP. * We will find a better AP !!! */ - limTearDownLinkWithAp(pMac, + if ((psessionEntry->limMlmState == eLIM_MLM_LINK_ESTABLISHED_STATE) && + (psessionEntry->limSmeState != eLIM_SME_WT_DISASSOC_STATE)&& + (psessionEntry->limSmeState != eLIM_SME_WT_DEAUTH_STATE)) { + limLog(pMac, LOGE, FL("Invalid channel!! Disconnect..")); + limTearDownLinkWithAp(pMac, pMac->lim.limTimers.gLimChannelSwitchTimer.sessionId, eSIR_MAC_UNSPEC_FAILURE_REASON); + } return; } limCovertChannelScanType(pMac, psessionEntry->currentOperChannel, false); diff --git a/drivers/staging/qcacld-2.0/CORE/SAP/src/sapFsm.c b/drivers/staging/qcacld-2.0/CORE/SAP/src/sapFsm.c index 715a0c9faabc..0bbe20657493 100644 --- a/drivers/staging/qcacld-2.0/CORE/SAP/src/sapFsm.c +++ b/drivers/staging/qcacld-2.0/CORE/SAP/src/sapFsm.c @@ -1946,7 +1946,7 @@ v_BOOL_t sapDfsIsChannelInNolList(ptSapContext sapContext, v_U8_t channelNumber, ePhyChanBondState chanBondState) { - int i, j; + int i = 0, j; v_U64_t timeElapsedSinceLastRadar,timeWhenRadarFound,currentTime = 0; v_U64_t max_jiffies; tHalHandle hHal = VOS_GET_HAL_CB(sapContext->pvosGCtx); diff --git a/drivers/staging/qcacld-2.0/CORE/SERVICES/COMMON/adf/adf_nbuf.c b/drivers/staging/qcacld-2.0/CORE/SERVICES/COMMON/adf/adf_nbuf.c index 53212933a92a..dc0ef3185da2 100644 --- a/drivers/staging/qcacld-2.0/CORE/SERVICES/COMMON/adf/adf_nbuf.c +++ b/drivers/staging/qcacld-2.0/CORE/SERVICES/COMMON/adf/adf_nbuf.c @@ -747,6 +747,12 @@ __adf_nbuf_data_get_icmpv6_subtype(uint8_t *data) case ICMPV6_RESPONSE: proto_subtype = ADF_PROTO_ICMPV6_RES; break; + case ICMPV6_NS: + proto_subtype = ADF_PROTO_ICMPV6_NS; + break; + case ICMPV6_NA: + proto_subtype = ADF_PROTO_ICMPV6_NA; + break; default: break; } @@ -1146,22 +1152,33 @@ __adf_nbuf_trace_update(struct sk_buff *buf, char *event_string) NBUF_PKT_TRAC_MAX_STRING); adf_os_mem_copy(string_buf, event_string, adf_os_str_len(event_string)); - if (NBUF_PKT_TRAC_TYPE_EAPOL & - adf_nbuf_trace_get_proto_type(buf)) { + switch (adf_nbuf_trace_get_proto_type(buf)) { + case NBUF_PKT_TRAC_TYPE_EAPOL: adf_os_mem_copy(string_buf + adf_os_str_len(event_string), - "EPL", - NBUF_PKT_TRAC_PROTO_STRING); - } - else if (NBUF_PKT_TRAC_TYPE_DHCP & - adf_nbuf_trace_get_proto_type(buf)) { + "EPL", NBUF_PKT_TRAC_PROTO_STRING); + break; + case NBUF_PKT_TRAC_TYPE_DHCP: + adf_os_mem_copy(string_buf + adf_os_str_len(event_string), + "DHC", NBUF_PKT_TRAC_PROTO_STRING); + break; + case NBUF_PKT_TRAC_TYPE_MGMT_ACTION: + adf_os_mem_copy(string_buf + adf_os_str_len(event_string), + "MACT", NBUF_PKT_TRAC_PROTO_STRING); + break; + case NBUF_PKT_TRAC_TYPE_ARP: + adf_os_mem_copy(string_buf + adf_os_str_len(event_string), + "ARP", NBUF_PKT_TRAC_PROTO_STRING); + break; + case NBUF_PKT_TRAC_TYPE_NS: adf_os_mem_copy(string_buf + adf_os_str_len(event_string), - "DHC", - NBUF_PKT_TRAC_PROTO_STRING); - } else if (NBUF_PKT_TRAC_TYPE_MGMT_ACTION & - adf_nbuf_trace_get_proto_type(buf)) { + "NS", NBUF_PKT_TRAC_PROTO_STRING); + break; + case NBUF_PKT_TRAC_TYPE_NA: adf_os_mem_copy(string_buf + adf_os_str_len(event_string), - "MACT", - NBUF_PKT_TRAC_PROTO_STRING); + "NA", NBUF_PKT_TRAC_PROTO_STRING); + break; + default: + break; } trace_update_cb(string_buf); diff --git a/drivers/staging/qcacld-2.0/CORE/SERVICES/COMMON/adf/adf_nbuf.h b/drivers/staging/qcacld-2.0/CORE/SERVICES/COMMON/adf/adf_nbuf.h index 904b299a0261..db809020f0a6 100644 --- a/drivers/staging/qcacld-2.0/CORE/SERVICES/COMMON/adf/adf_nbuf.h +++ b/drivers/staging/qcacld-2.0/CORE/SERVICES/COMMON/adf/adf_nbuf.h @@ -53,6 +53,8 @@ #define NBUF_PKT_TRAC_TYPE_DHCP 0x04 #define NBUF_PKT_TRAC_TYPE_MGMT_ACTION 0x08 #define NBUF_PKT_TRAC_TYPE_ARP 0x10 +#define NBUF_PKT_TRAC_TYPE_NS 0x20 +#define NBUF_PKT_TRAC_TYPE_NA 0x40 #define NBUF_PKT_TRAC_MAX_STRING 12 #define NBUF_PKT_TRAC_PROTO_STRING 4 #define ADF_NBUF_PKT_ERROR 1 @@ -174,7 +176,8 @@ struct mon_rx_status { #define ICMPV6_SUBTYPE_OFFSET 54 #define ICMPV6_REQUEST 0x80 #define ICMPV6_RESPONSE 0x81 - +#define ICMPV6_NS 0x87 +#define ICMPV6_NA 0x88 #define ADF_NBUF_IPA_CHECK_MASK 0x80000000 enum adf_proto_type { @@ -205,6 +208,8 @@ enum adf_proto_subtype { ADF_PROTO_ICMP_RES, ADF_PROTO_ICMPV6_REQ, ADF_PROTO_ICMPV6_RES, + ADF_PROTO_ICMPV6_NS, + ADF_PROTO_ICMPV6_NA, ADF_PROTO_IPV4_UDP, ADF_PROTO_IPV4_TCP, ADF_PROTO_IPV6_UDP, diff --git a/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c b/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c index 55eb2c43e756..6369f17e08d3 100644 --- a/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c +++ b/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c @@ -2241,6 +2241,12 @@ static int wma_vdev_stop_ind(tp_wma_handle wma, u_int8_t *buf) goto free_req_msg; } + /* Clear arp and ns offload cache */ + vos_mem_zero(&iface->ns_offload_req, + sizeof(iface->ns_offload_req)); + vos_mem_zero(&iface->arp_offload_req, + sizeof(iface->arp_offload_req)); + #ifdef QCA_IBSS_SUPPORT if ( wma_is_vdev_in_ibss_mode(wma, resp_event->vdev_id)) wma_delete_all_ibss_peers(wma, resp_event->vdev_id); @@ -21136,7 +21142,7 @@ static void wma_wow_parse_data_pkt_buffer(uint8_t *data, WMA_LOGD("wow_buf_pkt_len: %u", buf_len); if (buf_len >= ADF_NBUF_TRAC_IPV4_OFFSET) - WMA_LOGE("Src_mac: " MAC_ADDRESS_STR " Dst_mac: " MAC_ADDRESS_STR, + WMA_LOGE("SA: " MAC_ADDRESS_STR " DA: " MAC_ADDRESS_STR, MAC_ADDR_ARRAY(data + ADF_NBUF_SRC_MAC_OFFSET), MAC_ADDR_ARRAY(data)); else @@ -21148,7 +21154,7 @@ static void wma_wow_parse_data_pkt_buffer(uint8_t *data, case ADF_PROTO_EAPOL_M2: case ADF_PROTO_EAPOL_M3: case ADF_PROTO_EAPOL_M4: - WMA_LOGE("WOW Wakeup: %s rcvd", + WMA_LOGE("WOW %s rcvd", wma_pkt_proto_subtype_to_string(proto_subtype)); if (buf_len >= WMA_EAPOL_INFO_GET_MIN_LEN) { pkt_len = (uint16_t)(*(uint16_t *)(data + @@ -21169,7 +21175,7 @@ static void wma_wow_parse_data_pkt_buffer(uint8_t *data, case ADF_PROTO_DHCP_RELEASE: case ADF_PROTO_DHCP_INFORM: case ADF_PROTO_DHCP_DECLINE: - WMA_LOGE("WOW Wakeup: %s rcvd", + WMA_LOGE("WOW %s rcvd", wma_pkt_proto_subtype_to_string(proto_subtype)); if (buf_len >= WMA_DHCP_INFO_GET_MIN_LEN) { pkt_len = (uint16_t)(*(uint16_t *)(data + @@ -21184,13 +21190,13 @@ static void wma_wow_parse_data_pkt_buffer(uint8_t *data, case ADF_PROTO_ARP_REQ: case ADF_PROTO_ARP_RES: - WMA_LOGE("WOW Wakeup: %s rcvd", + WMA_LOGE("WOW %s rcvd", wma_pkt_proto_subtype_to_string(proto_subtype)); break; case ADF_PROTO_ICMP_REQ: case ADF_PROTO_ICMP_RES: - WMA_LOGE("WOW Wakeup: %s rcvd", + WMA_LOGE("WOW %s rcvd", wma_pkt_proto_subtype_to_string(proto_subtype)); if (buf_len >= WMA_IPV4_PKT_INFO_GET_MIN_LEN) { pkt_len = (uint16_t)(*(uint16_t *)(data + @@ -21205,14 +21211,14 @@ static void wma_wow_parse_data_pkt_buffer(uint8_t *data, case ADF_PROTO_ICMPV6_REQ: case ADF_PROTO_ICMPV6_RES: - WMA_LOGE("WOW Wakeup: %s rcvd", + WMA_LOGE("WOW %s rcvd", wma_pkt_proto_subtype_to_string(proto_subtype)); if (buf_len >= WMA_IPV6_PKT_INFO_GET_MIN_LEN) { pkt_len = (uint16_t)(*(uint16_t *)(data + IPV6_PKT_LEN_OFFSET)); seq_num = (uint16_t)(*(uint16_t *)(data + ICMPV6_SEQ_NUM_OFFSET)); - WMA_LOGE("Pkt_len: %u, Seq_num: %u", + WMA_LOGE("len: %u, SN: %u", adf_os_cpu_to_be16(pkt_len), adf_os_cpu_to_be16(seq_num)); } @@ -21220,7 +21226,7 @@ static void wma_wow_parse_data_pkt_buffer(uint8_t *data, case ADF_PROTO_IPV4_UDP: case ADF_PROTO_IPV4_TCP: - WMA_LOGE("WOW Wakeup: %s rcvd", + WMA_LOGE("WOW %s rcvd", wma_pkt_proto_subtype_to_string(proto_subtype)); if (buf_len >= WMA_IPV4_PKT_INFO_GET_MIN_LEN) { pkt_len = (uint16_t)(*(uint16_t *)(data + @@ -21229,15 +21235,14 @@ static void wma_wow_parse_data_pkt_buffer(uint8_t *data, IPV4_SRC_PORT_OFFSET)); dst_port = (uint16_t)(*(uint16_t *)(data + IPV4_DST_PORT_OFFSET)); - WMA_LOGE("Pkt_len: %u", - adf_os_cpu_to_be16(pkt_len)); - WMA_LOGE("src_port: %u, dst_port: %u", + WMA_LOGE("len: %u sport: %u dport: %u", + adf_os_cpu_to_be16(pkt_len), adf_os_cpu_to_be16(src_port), adf_os_cpu_to_be16(dst_port)); if (proto_subtype == ADF_PROTO_IPV4_TCP) { tcp_seq_num = (uint32_t)(*(uint32_t *)(data + IPV4_TCP_SEQ_NUM_OFFSET)); - WMA_LOGE("TCP_seq_num: %u", + WMA_LOGD("TCP SN: %u", adf_os_cpu_to_be32(tcp_seq_num)); } } @@ -21245,7 +21250,7 @@ static void wma_wow_parse_data_pkt_buffer(uint8_t *data, case ADF_PROTO_IPV6_UDP: case ADF_PROTO_IPV6_TCP: - WMA_LOGE("WOW Wakeup: %s rcvd", + WMA_LOGE("WOW %s rcvd", wma_pkt_proto_subtype_to_string(proto_subtype)); if (buf_len >= WMA_IPV6_PKT_INFO_GET_MIN_LEN) { pkt_len = (uint16_t)(*(uint16_t *)(data + @@ -21254,15 +21259,14 @@ static void wma_wow_parse_data_pkt_buffer(uint8_t *data, IPV6_SRC_PORT_OFFSET)); dst_port = (uint16_t)(*(uint16_t *)(data + IPV6_DST_PORT_OFFSET)); - WMA_LOGE("Pkt_len: %u", - adf_os_cpu_to_be16(pkt_len)); - WMA_LOGE("src_port: %u, dst_port: %u", + WMA_LOGE("len: %u sport: %u dport: %u", + adf_os_cpu_to_be16(pkt_len), adf_os_cpu_to_be16(src_port), adf_os_cpu_to_be16(dst_port)); if (proto_subtype == ADF_PROTO_IPV6_TCP) { tcp_seq_num = (uint32_t)(*(uint32_t *)(data + IPV6_TCP_SEQ_NUM_OFFSET)); - WMA_LOGE("TCP_seq_num: %u", + WMA_LOGD("TCP SN: %u", adf_os_cpu_to_be32(tcp_seq_num)); } } @@ -21270,8 +21274,7 @@ static void wma_wow_parse_data_pkt_buffer(uint8_t *data, default: end: - WMA_LOGE("wow_buf_pkt_len: %u", buf_len); - WMA_LOGE("Unknown Packet or Insufficient packet buffer"); + WMA_LOGE("Unknown Packet or Insufficient packet buffer (len=%u)", buf_len); break; } } @@ -21407,12 +21410,10 @@ static int wma_wow_wakeup_host_event(void *handle, u_int8_t *event, wake_info = param_buf->fixed_param; - if ((wake_info->wake_reason != WOW_REASON_UNSPECIFIED) || - (wake_info->wake_reason == WOW_REASON_UNSPECIFIED && - !wmi_get_runtime_pm_inprogress(wma->wmi_handle))) - WMA_LOGA("WOW wakeup host event received (reason: %s(%d)) for vdev %d", - wma_wow_wake_reason_str(wake_info->wake_reason, wma), + if (!wmi_get_runtime_pm_inprogress(wma->wmi_handle)) + WMA_LOGA("WOW (%d) %s vdev:%d", wake_info->wake_reason, + wma_wow_wake_reason_str(wake_info->wake_reason, wma), wake_info->vdev_id); vos_event_set(&wma->wma_resume_event); @@ -24604,8 +24605,12 @@ static VOS_STATUS wma_process_mcbc_set_filter_req(tp_wma_handle wma_handle, uint8_t vdev_id = 0; int i; - if(mcbc_param->ulMulticastAddrCnt <= 0) { - WMA_LOGW("Number of multicast addresses is 0"); + if (mcbc_param->ulMulticastAddrCnt <= 0 || + mcbc_param->ulMulticastAddrCnt > + CFG_TGT_MAX_MULTICAST_FILTER_ENTRIES) { + WMA_LOGE("Number of multicast addresses is: %u", + mcbc_param->ulMulticastAddrCnt); + WARN_ON(1); return VOS_STATUS_E_FAILURE; } @@ -24782,208 +24787,322 @@ out: } #endif -/* - * Function : wma_enable_arp_ns_offload - * Description : To configure ARP NS off load data to firmware - * when target goes to wow mode. - * Args : @wma - wma handle, @tpSirHostOffloadReq - - * pHostOffloadParams,@bool bArpOnly - * Returns : Returns Failure or Success based on WMI cmd. - * Comments : Since firware expects ARP and NS to be configured - * at a time, Arp info is cached in wma and send along - * with NS info to make both work. +/** + * wma_fill_arp_offload_params() - Fill ARP offload data + * @wma: wma handle + * @tpSirHostOffloadReq: offload request + * @buf_ptr: buffer pointer + * + * To fill ARP offload data to firmware + * when target goes to wow mode. + * + * Return: None + */ +static void wma_fill_arp_offload_params(tp_wma_handle wma, + tpSirHostOffloadReq hostoffloadreq, uint8_t **buf_ptr) +{ + + int32_t i; + WMI_ARP_OFFLOAD_TUPLE *arp_tuple; + bool enableOrDisable = hostoffloadreq->enableOrDisable; + + WMITLV_SET_HDR(*buf_ptr, WMITLV_TAG_ARRAY_STRUC, + (WMI_MAX_ARP_OFFLOADS*sizeof(WMI_ARP_OFFLOAD_TUPLE))); + *buf_ptr += WMI_TLV_HDR_SIZE; + for (i = 0; i < WMI_MAX_ARP_OFFLOADS; i++) { + arp_tuple = (WMI_ARP_OFFLOAD_TUPLE *)*buf_ptr; + WMITLV_SET_HDR(&arp_tuple->tlv_header, + WMITLV_TAG_STRUC_WMI_ARP_OFFLOAD_TUPLE, + WMITLV_GET_STRUCT_TLVLEN(WMI_ARP_OFFLOAD_TUPLE)); + + /* Fill data for ARP and NS in the first tupple for LA */ + if ((enableOrDisable & SIR_OFFLOAD_ENABLE) && (i == 0)) { + /* Copy the target ip addr and flags */ + arp_tuple->flags = WMI_ARPOFF_FLAGS_VALID; + A_MEMCPY(&arp_tuple->target_ipaddr, + hostoffloadreq->params.hostIpv4Addr, + SIR_IPV4_ADDR_LEN); + WMA_LOGD("ARPOffload IP4 address: %pI4", + hostoffloadreq->params.hostIpv4Addr); + } + *buf_ptr += sizeof(WMI_ARP_OFFLOAD_TUPLE); + } +} + +#ifdef WLAN_NS_OFFLOAD +/** + * wma_fill_ns_offload_params() - Fill NS offload data + * @wma: wma handle + * @tpSirHostOffloadReq: offload request + * @buf_ptr: buffer pointer + * + * To fill NS offload data to firmware + * when target goes to wow mode. + * + * Return: None */ -static VOS_STATUS wma_enable_arp_ns_offload(tp_wma_handle wma, tpSirHostOffloadReq pHostOffloadParams, bool bArpOnly) +static void wma_fill_ns_offload_params(tp_wma_handle wma, + tpSirHostOffloadReq hostoffloadreq, uint8_t **buf_ptr) { + int32_t i; + WMI_NS_OFFLOAD_TUPLE *ns_tuple; + tSirNsOffloadReq ns_req; + + ns_req = hostoffloadreq->nsOffloadInfo; + WMITLV_SET_HDR(*buf_ptr, WMITLV_TAG_ARRAY_STRUC, + (WMI_MAX_NS_OFFLOADS*sizeof(WMI_NS_OFFLOAD_TUPLE))); + *buf_ptr += WMI_TLV_HDR_SIZE; + for (i = 0; i < WMI_MAX_NS_OFFLOADS; i++) { + ns_tuple = (WMI_NS_OFFLOAD_TUPLE *)*buf_ptr; + WMITLV_SET_HDR(&ns_tuple->tlv_header, + WMITLV_TAG_STRUC_WMI_NS_OFFLOAD_TUPLE, + (sizeof(WMI_NS_OFFLOAD_TUPLE) - WMI_TLV_HDR_SIZE)); + + /* + * Fill data only for NS offload in the first ARP tuple for LA + */ + if ((hostoffloadreq->enableOrDisable & SIR_OFFLOAD_ENABLE)) { + ns_tuple->flags |= WMI_NSOFF_FLAGS_VALID; + /* Copy the target/solicitation/remote ip addr */ + if (ns_req.targetIPv6AddrValid[i]) + A_MEMCPY(&ns_tuple->target_ipaddr[0], + &ns_req.targetIPv6Addr[i], + sizeof(WMI_IPV6_ADDR)); + A_MEMCPY(&ns_tuple->solicitation_ipaddr, + &ns_req.selfIPv6Addr[i], + sizeof(WMI_IPV6_ADDR)); + if (ns_req.target_ipv6_addr_type[i]) { + ns_tuple->flags |= + WMI_NSOFF_FLAGS_IS_IPV6_ANYCAST; + } + WMA_LOGD("Index %d NS solicitedIp %pI6, targetIp %pI6", + i, &ns_req.selfIPv6Addr[i], + &ns_req.targetIPv6Addr[i]); + + /* target MAC is optional, check if it is valid, + * if this is not valid, the target will use the known + * local MAC address rather than the tuple + */ + WMI_CHAR_ARRAY_TO_MAC_ADDR( + ns_req.selfMacAddr, + &ns_tuple->target_mac); + if ((ns_tuple->target_mac.mac_addr31to0 != 0) || + (ns_tuple->target_mac.mac_addr47to32 != 0)) { + ns_tuple->flags |= WMI_NSOFF_FLAGS_MAC_VALID; + } + } + *buf_ptr += sizeof(WMI_NS_OFFLOAD_TUPLE); + } +} + + +/** + * wma_fill_nsoffload_ext() - Fill NS offload ext data + * @wma: wma handle + * @tpSirHostOffloadReq: offload request + * @buf_ptr: buffer pointer + * + * To fill extended NS offload extended data to firmware + * when target goes to wow mode. + * + * Return: None + */ +static void wma_fill_nsoffload_ext(tp_wma_handle wma, tpSirHostOffloadReq + hostoffloadreq, uint8_t **buf_ptr) +{ + int32_t i; + WMI_NS_OFFLOAD_TUPLE *ns_tuple; + uint32_t count, num_ns_ext_tuples; + tSirNsOffloadReq ns_req; + + ns_req = hostoffloadreq->nsOffloadInfo; + count = hostoffloadreq->num_ns_offload_count; + num_ns_ext_tuples = hostoffloadreq->num_ns_offload_count - + WMI_MAX_NS_OFFLOADS; + + /* Populate extended NS offload tuples */ + WMITLV_SET_HDR(*buf_ptr, WMITLV_TAG_ARRAY_STRUC, + (num_ns_ext_tuples * sizeof(WMI_NS_OFFLOAD_TUPLE))); + *buf_ptr += WMI_TLV_HDR_SIZE; + for (i = WMI_MAX_NS_OFFLOADS; i < count; i++) { + ns_tuple = (WMI_NS_OFFLOAD_TUPLE *)*buf_ptr; + WMITLV_SET_HDR(&ns_tuple->tlv_header, + WMITLV_TAG_STRUC_WMI_NS_OFFLOAD_TUPLE, + (sizeof(WMI_NS_OFFLOAD_TUPLE)-WMI_TLV_HDR_SIZE)); + + /* + * Fill data only for NS offload in the first ARP tuple for LA + */ + if ((hostoffloadreq->enableOrDisable & SIR_OFFLOAD_ENABLE)) { + ns_tuple->flags |= WMI_NSOFF_FLAGS_VALID; + /* Copy the target/solicitation/remote ip addr */ + if (ns_req.targetIPv6AddrValid[i]) + A_MEMCPY(&ns_tuple->target_ipaddr[0], + &ns_req.targetIPv6Addr[i], + sizeof(WMI_IPV6_ADDR)); + A_MEMCPY(&ns_tuple->solicitation_ipaddr, + &ns_req.selfIPv6Addr[i], + sizeof(WMI_IPV6_ADDR)); + if (ns_req.target_ipv6_addr_type[i]) { + ns_tuple->flags |= + WMI_NSOFF_FLAGS_IS_IPV6_ANYCAST; + } + WMA_LOGD("Index %d NS solicitedIp %pI6, targetIp %pI6", + i, &ns_req.selfIPv6Addr[i], + &ns_req.targetIPv6Addr[i]); + + /* target MAC is optional, check if it is valid, + * if this is not valid, the target will use the + * known local MAC address rather than the tuple + */ + WMI_CHAR_ARRAY_TO_MAC_ADDR( + ns_req.selfMacAddr, + &ns_tuple->target_mac); + if ((ns_tuple->target_mac.mac_addr31to0 != 0) || + (ns_tuple->target_mac.mac_addr47to32 != 0)) { + ns_tuple->flags |= WMI_NSOFF_FLAGS_MAC_VALID; + } + } + *buf_ptr += sizeof(WMI_NS_OFFLOAD_TUPLE); + } +} +#else +static inline void wma_fill_ns_offload_params(tp_wma_handle wma, + tpSirHostOffloadReq hostoffloadreq, uint8_t **buf_ptr) +{ + return; +} + +static inline void wma_fill_nsoffload_ext(tp_wma_handle wma, + tpSirHostOffloadReq hostoffloadreq, uint8_t **buf_ptr) +{ + return; +} +#endif + + +/** + * wma_enable_arp_ns_offload() - enable ARP NS offload + * @wma: wma handle + * @tpSirHostOffloadReq: offload request + * @config_arp: flag + * + * To configure ARP NS off load data to firmware + * when target goes to wow mode. + * + * Return: VOS Status + */ +static VOS_STATUS wma_enable_arp_ns_offload(tp_wma_handle wma, + tpSirHostOffloadReq hostoffloadreq, bool config_arp) +{ int32_t res; WMI_SET_ARP_NS_OFFLOAD_CMD_fixed_param *cmd; - WMI_NS_OFFLOAD_TUPLE *ns_tuple; - WMI_ARP_OFFLOAD_TUPLE *arp_tuple; A_UINT8* buf_ptr; wmi_buf_t buf; int32_t len; + VOS_STATUS status = VOS_STATUS_SUCCESS; u_int8_t vdev_id; + tpSirHostOffloadReq ns_offload_req; + tpSirHostOffloadReq arp_offload_req; uint32_t count = 0, num_ns_ext_tuples = 0; /* Get the vdev id */ - if (!wma_find_vdev_by_bssid(wma, pHostOffloadParams->bssId, &vdev_id)) { - WMA_LOGE("vdev handle is invalid for %pM", pHostOffloadParams->bssId); - vos_mem_free(pHostOffloadParams); - return VOS_STATUS_E_INVAL; + if (!wma_find_vdev_by_bssid(wma, hostoffloadreq->bssId, &vdev_id)) { + WMA_LOGE("Invalid vdev handle for %pM", hostoffloadreq->bssId); + status = VOS_STATUS_E_FAILURE; + goto err_vdev; } if (!wma->interfaces[vdev_id].vdev_up) { - WMA_LOGE("vdev %d is not up skipping arp/ns offload", vdev_id); - vos_mem_free(pHostOffloadParams); - return VOS_STATUS_E_FAILURE; + status = VOS_STATUS_E_FAILURE; + goto err_vdev; } - if (!bArpOnly) - count = pHostOffloadParams->num_ns_offload_count; + /* + * config_arp is true means arp request comes from upper layer + * Hence ns request need to used from wma cached request. + */ + if (config_arp) { + arp_offload_req = hostoffloadreq; + ns_offload_req = &wma->interfaces[vdev_id].ns_offload_req; + count = ns_offload_req->num_ns_offload_count; + } else { + ns_offload_req = hostoffloadreq; + arp_offload_req = &wma->interfaces[vdev_id].arp_offload_req; + count = hostoffloadreq->num_ns_offload_count; + } len = sizeof(WMI_SET_ARP_NS_OFFLOAD_CMD_fixed_param) + - WMI_TLV_HDR_SIZE + // TLV place holder size for array of NS tuples + WMI_TLV_HDR_SIZE + /* Add size for array of NS tuples */ WMI_MAX_NS_OFFLOADS*sizeof(WMI_NS_OFFLOAD_TUPLE) + - WMI_TLV_HDR_SIZE + // TLV place holder size for array of ARP tuples + WMI_TLV_HDR_SIZE + /* Add size for array of ARP tuples */ WMI_MAX_ARP_OFFLOADS*sizeof(WMI_ARP_OFFLOAD_TUPLE); - /* - * If there are more than WMI_MAX_NS_OFFLOADS addresses then allocate - * extra length for extended NS offload tuples which follows ARP offload - * tuples. Host needs to fill this structure in following format: - * 2 NS ofload tuples - * 2 ARP offload tuples - * N numbers of extended NS offload tuples if HDD has given more than - * 2 NS offload addresses - */ - if (!bArpOnly && count > WMI_MAX_NS_OFFLOADS) { + if (count > WMI_MAX_NS_OFFLOADS) { num_ns_ext_tuples = count - WMI_MAX_NS_OFFLOADS; - len += WMI_TLV_HDR_SIZE + num_ns_ext_tuples * - sizeof(WMI_NS_OFFLOAD_TUPLE); + len += WMI_TLV_HDR_SIZE + num_ns_ext_tuples + * sizeof(WMI_NS_OFFLOAD_TUPLE); } buf = wmi_buf_alloc(wma->wmi_handle, len); if (!buf) { WMA_LOGE("%s: wmi_buf_alloc failed", __func__); - vos_mem_free(pHostOffloadParams); - return VOS_STATUS_E_NOMEM; + status = VOS_STATUS_E_NOMEM; + goto err_vdev; } buf_ptr = (A_UINT8*)wmi_buf_data(buf); + cmd = (WMI_SET_ARP_NS_OFFLOAD_CMD_fixed_param *)buf_ptr; WMITLV_SET_HDR(&cmd->tlv_header, - WMITLV_TAG_STRUC_WMI_SET_ARP_NS_OFFLOAD_CMD_fixed_param, - WMITLV_GET_STRUCT_TLVLEN(WMI_SET_ARP_NS_OFFLOAD_CMD_fixed_param)); + WMITLV_TAG_STRUC_WMI_SET_ARP_NS_OFFLOAD_CMD_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + WMI_SET_ARP_NS_OFFLOAD_CMD_fixed_param)); cmd->flags = 0; cmd->vdev_id = vdev_id; - if (!bArpOnly) - cmd->num_ns_ext_tuples = num_ns_ext_tuples; - - WMA_LOGD("ARP NS Offload vdev_id: %d",cmd->vdev_id); - - /* Have copy of arp info to send along with NS, Since FW expects - * both ARP and NS info in single cmd */ - if(bArpOnly) - vos_mem_copy(&wma->mArpInfo, pHostOffloadParams, sizeof(tSirHostOffloadReq)); + cmd->num_ns_ext_tuples = num_ns_ext_tuples; buf_ptr += sizeof(WMI_SET_ARP_NS_OFFLOAD_CMD_fixed_param); - WMITLV_SET_HDR(buf_ptr,WMITLV_TAG_ARRAY_STRUC,(WMI_MAX_NS_OFFLOADS*sizeof(WMI_NS_OFFLOAD_TUPLE))); - buf_ptr += WMI_TLV_HDR_SIZE; - for(i = 0; i < WMI_MAX_NS_OFFLOADS; i++ ){ - ns_tuple = (WMI_NS_OFFLOAD_TUPLE *)buf_ptr; - WMITLV_SET_HDR(&ns_tuple->tlv_header, - WMITLV_TAG_STRUC_WMI_NS_OFFLOAD_TUPLE, - (sizeof(WMI_NS_OFFLOAD_TUPLE)-WMI_TLV_HDR_SIZE)); - - /* Fill data only for NS offload in the first ARP tuple for LA */ - if (!bArpOnly && - ((pHostOffloadParams->enableOrDisable & SIR_OFFLOAD_ENABLE))) { - ns_tuple->flags |= WMI_NSOFF_FLAGS_VALID; - -#ifdef WLAN_NS_OFFLOAD - /*Copy the target/solicitation/remote ip addr */ - if(pHostOffloadParams->nsOffloadInfo.targetIPv6AddrValid[i]) - A_MEMCPY(&ns_tuple->target_ipaddr[0], - &pHostOffloadParams->nsOffloadInfo.targetIPv6Addr[i], sizeof(WMI_IPV6_ADDR)); - A_MEMCPY(&ns_tuple->solicitation_ipaddr, - &pHostOffloadParams->nsOffloadInfo.selfIPv6Addr[i], sizeof(WMI_IPV6_ADDR)); - if(pHostOffloadParams->nsOffloadInfo.target_ipv6_addr_type[i]) - ns_tuple->flags |= WMI_NSOFF_FLAGS_IS_IPV6_ANYCAST; - WMA_LOGD("Index %d NS solicitedIp: %pI6, targetIp: %pI6", i, - &pHostOffloadParams->nsOffloadInfo.selfIPv6Addr[i], - &pHostOffloadParams->nsOffloadInfo.targetIPv6Addr[i]); - - /* target MAC is optional, check if it is valid, if this is not valid, - * the target will use the known local MAC address rather than the tuple */ - WMI_CHAR_ARRAY_TO_MAC_ADDR(pHostOffloadParams->nsOffloadInfo.selfMacAddr, - &ns_tuple->target_mac); -#endif - if ((ns_tuple->target_mac.mac_addr31to0 != 0) || - (ns_tuple->target_mac.mac_addr47to32 != 0)) - { - ns_tuple->flags |= WMI_NSOFF_FLAGS_MAC_VALID; - } - } - buf_ptr += sizeof(WMI_NS_OFFLOAD_TUPLE); - } - - WMITLV_SET_HDR(buf_ptr,WMITLV_TAG_ARRAY_STRUC,(WMI_MAX_ARP_OFFLOADS*sizeof(WMI_ARP_OFFLOAD_TUPLE))); - buf_ptr += WMI_TLV_HDR_SIZE; - for(i = 0; i < WMI_MAX_ARP_OFFLOADS; i++){ - arp_tuple = (WMI_ARP_OFFLOAD_TUPLE *)buf_ptr; - WMITLV_SET_HDR(&arp_tuple->tlv_header, - WMITLV_TAG_STRUC_WMI_ARP_OFFLOAD_TUPLE, - WMITLV_GET_STRUCT_TLVLEN(WMI_ARP_OFFLOAD_TUPLE)); - - /* Fill data for ARP and NS in the first tupple for LA */ - if ((wma->mArpInfo.enableOrDisable & SIR_OFFLOAD_ENABLE) && (i==0)) { - /*Copy the target ip addr and flags*/ - arp_tuple->flags = WMI_ARPOFF_FLAGS_VALID; - A_MEMCPY(&arp_tuple->target_ipaddr,wma->mArpInfo.params.hostIpv4Addr, - SIR_IPV4_ADDR_LEN); - WMA_LOGD("ARPOffload IP4 address: %pI4", - wma->mArpInfo.params.hostIpv4Addr); - } - buf_ptr += sizeof(WMI_ARP_OFFLOAD_TUPLE); - } - - /* Populate extended NS offload tuples */ - WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, - (num_ns_ext_tuples*sizeof(WMI_NS_OFFLOAD_TUPLE))); - buf_ptr += WMI_TLV_HDR_SIZE; - - if (num_ns_ext_tuples) { - for(i = WMI_MAX_NS_OFFLOADS; i < count; i++ ){ - ns_tuple = (WMI_NS_OFFLOAD_TUPLE *)buf_ptr; - WMITLV_SET_HDR(&ns_tuple->tlv_header, - WMITLV_TAG_STRUC_WMI_NS_OFFLOAD_TUPLE, - (sizeof(WMI_NS_OFFLOAD_TUPLE)-WMI_TLV_HDR_SIZE)); - - /* Fill data only for NS offload in the first ARP tuple for LA */ - if (!bArpOnly && - ((pHostOffloadParams->enableOrDisable & SIR_OFFLOAD_ENABLE))) { - ns_tuple->flags |= WMI_NSOFF_FLAGS_VALID; -#ifdef WLAN_NS_OFFLOAD - /*Copy the target/solicitation/remote ip addr */ - if(pHostOffloadParams->nsOffloadInfo.targetIPv6AddrValid[i]) - A_MEMCPY(&ns_tuple->target_ipaddr[0], - &pHostOffloadParams->nsOffloadInfo.targetIPv6Addr[i], - sizeof(WMI_IPV6_ADDR)); - A_MEMCPY(&ns_tuple->solicitation_ipaddr, - &pHostOffloadParams->nsOffloadInfo.selfIPv6Addr[i], - sizeof(WMI_IPV6_ADDR)); - if(pHostOffloadParams->nsOffloadInfo.target_ipv6_addr_type[i]) - ns_tuple->flags |= WMI_NSOFF_FLAGS_IS_IPV6_ANYCAST; - WMA_LOGD("Index %d NS solicitedIp: %pI6, targetIp: %pI6", i, - &pHostOffloadParams->nsOffloadInfo.selfIPv6Addr[i], - &pHostOffloadParams->nsOffloadInfo.targetIPv6Addr[i]); - - /* target MAC is optional, check if it is valid, if this is not valid, - * the target will use the known local MAC address rather than the tuple */ - WMI_CHAR_ARRAY_TO_MAC_ADDR(pHostOffloadParams->nsOffloadInfo.selfMacAddr, - &ns_tuple->target_mac); -#endif - if ((ns_tuple->target_mac.mac_addr31to0 != 0) || - (ns_tuple->target_mac.mac_addr47to32 != 0)) { - ns_tuple->flags |= WMI_NSOFF_FLAGS_MAC_VALID; - } - } - buf_ptr += sizeof(WMI_NS_OFFLOAD_TUPLE); - } + if (config_arp) + WMA_LOGD(" %s: ARP Offload vdev_id: %d enable: %d ns_count: %u", + __func__, cmd->vdev_id, + hostoffloadreq->enableOrDisable, + hostoffloadreq->num_ns_offload_count); + else + WMA_LOGD(" %s: NS Offload vdev_id: %d enable: %d ns_count: %u", + __func__, cmd->vdev_id, + hostoffloadreq->enableOrDisable, + hostoffloadreq->num_ns_offload_count); + + wma_fill_ns_offload_params(wma, ns_offload_req, &buf_ptr); + wma_fill_arp_offload_params(wma, arp_offload_req, &buf_ptr); + if (count > WMI_MAX_NS_OFFLOADS) + wma_fill_nsoffload_ext(wma, ns_offload_req, &buf_ptr); + + res = wmi_unified_cmd_send(wma->wmi_handle, buf, len, + WMI_SET_ARP_NS_OFFLOAD_CMDID); + if (res) { + WMA_LOGE("Failed to enable ARP NDP/NSffload"); + goto err_cmd_send; } - res = wmi_unified_cmd_send(wma->wmi_handle, buf, len, WMI_SET_ARP_NS_OFFLOAD_CMDID); - if(res) { - WMA_LOGE("Failed to enable ARP NDP/NSffload"); - wmi_buf_free(buf); - vos_mem_free(pHostOffloadParams); - return VOS_STATUS_E_FAILURE; + if (config_arp) { + vos_mem_copy(&wma->interfaces[vdev_id].arp_offload_req, + hostoffloadreq, sizeof(tSirHostOffloadReq)); + } else { + vos_mem_copy(&wma->interfaces[vdev_id].ns_offload_req, + hostoffloadreq, sizeof(tSirHostOffloadReq)); } - vos_mem_free(pHostOffloadParams); - return VOS_STATUS_SUCCESS; + vos_mem_free(hostoffloadreq); + return status; +err_cmd_send: + wmi_buf_free(buf); +err_vdev: + vos_mem_free(hostoffloadreq); + return status; } typedef struct { diff --git a/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.h b/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.h index 8dedfab6f269..d88e9e0cf312 100644 --- a/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.h +++ b/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.h @@ -569,6 +569,10 @@ struct wma_txrx_node { v_BOOL_t vdev_up; u_int64_t tsfadjust; void *addBssStaContext; + /* Have a back up of arp offload req */ + tSirHostOffloadReq arp_offload_req; + /* tSirHostOffloadReq of ns offload req */ + tSirHostOffloadReq ns_offload_req; tANI_U8 aid; /* Robust Management Frame (RMF) enabled/disabled */ tANI_U8 rmfEnabled; @@ -763,10 +767,6 @@ typedef struct wma_handle { u_int8_t no_of_suspend_ind; u_int8_t no_of_resume_ind; - /* Have a back up of arp info to send along - * with ns info suppose if ns also enabled - */ - tSirHostOffloadReq mArpInfo; struct wma_tx_ack_work_ctx *ack_work_ctx; u_int8_t powersave_mode; v_BOOL_t ptrn_match_enable_all_vdev; diff --git a/drivers/staging/qcacld-2.0/CORE/SERVICES/WMI/wmi_unified_priv.h b/drivers/staging/qcacld-2.0/CORE/SERVICES/WMI/wmi_unified_priv.h index 780e49c26959..5a43e3fb299d 100644 --- a/drivers/staging/qcacld-2.0/CORE/SERVICES/WMI/wmi_unified_priv.h +++ b/drivers/staging/qcacld-2.0/CORE/SERVICES/WMI/wmi_unified_priv.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2014 The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -38,7 +38,7 @@ #include "adf_os_atomic.h" #define WMI_UNIFIED_MAX_EVENT 0x100 -#define WMI_MAX_CMDS 128 +#define WMI_MAX_CMDS 256 typedef adf_nbuf_t wmi_buf_t; diff --git a/drivers/staging/qcacld-2.0/CORE/VOSS/inc/vos_packet.h b/drivers/staging/qcacld-2.0/CORE/VOSS/inc/vos_packet.h index 469da0a1a923..6d86b3a2f16d 100644 --- a/drivers/staging/qcacld-2.0/CORE/VOSS/inc/vos_packet.h +++ b/drivers/staging/qcacld-2.0/CORE/VOSS/inc/vos_packet.h @@ -62,7 +62,9 @@ typedef struct vos_pkt_t vos_pkt_t; #define VOS_PKT_TRAC_TYPE_EAPOL NBUF_PKT_TRAC_TYPE_EAPOL #define VOS_PKT_TRAC_TYPE_DHCP NBUF_PKT_TRAC_TYPE_DHCP #define VOS_PKT_TRAC_TYPE_MGMT_ACTION NBUF_PKT_TRAC_TYPE_MGMT_ACTION /* Managment action frame */ - +#define VOS_PKT_TRAC_TYPE_ARP NBUF_PKT_TRAC_TYPE_ARP +#define VOS_PKT_TRAC_TYPE_NS NBUF_PKT_TRAC_TYPE_NS +#define VOS_PKT_TRAC_TYPE_NA NBUF_PKT_TRAC_TYPE_NA #define VOS_PKT_TRAC_DUMP_CMD 9999 /*--------------------------------------------------------------------------- diff --git a/drivers/staging/qcacld-2.0/CORE/VOSS/src/vos_api.c b/drivers/staging/qcacld-2.0/CORE/VOSS/src/vos_api.c index 5b536b35f019..3004ccc4c7d0 100644 --- a/drivers/staging/qcacld-2.0/CORE/VOSS/src/vos_api.c +++ b/drivers/staging/qcacld-2.0/CORE/VOSS/src/vos_api.c @@ -2898,11 +2898,11 @@ VOS_STATUS vos_flush_logs(uint32_t is_fatal, "%s: Triggering bug report: type:%d, indicator=%d reason_code=%d dump_trace=0x%x", __func__, is_fatal, indicator, reason_code, dump_trace); - if (dump_trace | DUMP_VOS_TRACE) + if (dump_trace & DUMP_VOS_TRACE) vosTraceDumpAll(vos_context->pMACContext, 0, 0, 500, 0); #ifdef QCA_PKT_PROTO_TRACE - if (dump_trace | DUMP_PACKET_TRACE) + if (dump_trace & DUMP_PACKET_TRACE) vos_pkt_trace_buf_dump(); #endif if (WLAN_LOG_INDICATOR_HOST_ONLY == indicator) { diff --git a/drivers/staging/qcacld-2.0/CORE/VOSS/src/vos_packet.c b/drivers/staging/qcacld-2.0/CORE/VOSS/src/vos_packet.c index 1795ecbfb8e1..e81c6411f68b 100644 --- a/drivers/staging/qcacld-2.0/CORE/VOSS/src/vos_packet.c +++ b/drivers/staging/qcacld-2.0/CORE/VOSS/src/vos_packet.c @@ -57,6 +57,7 @@ #define VOS_PKT_TRAC_DHCP_SRV_PORT 67 #define VOS_PKT_TRAC_DHCP_CLI_PORT 68 #define VOS_PKT_TRAC_EAPOL_ETH_TYPE 0x888E +#define VOS_PKT_TRAC_ARP_ETH_TYPE 0x0806 #ifdef QCA_PKT_PROTO_TRACE #define VOS_PKT_TRAC_MAX_STRING_LEN 40 #define VOS_PKT_TRAC_MAX_TRACE_BUF 50 @@ -256,14 +257,11 @@ v_U8_t vos_pkt_get_proto_type ) { v_U8_t pkt_proto_type = 0; - v_U16_t ether_type; - v_U16_t SPort; - v_U16_t DPort; if (dot11_type) { if (dot11_type == (VOS_PKT_TRAC_TYPE_MGMT_ACTION & tracking_map)) - pkt_proto_type |= VOS_PKT_TRAC_TYPE_MGMT_ACTION; + pkt_proto_type = VOS_PKT_TRAC_TYPE_MGMT_ACTION; /* Protocol type map */ return pkt_proto_type; @@ -272,26 +270,48 @@ v_U8_t vos_pkt_get_proto_type /* EAPOL Tracking enabled */ if (VOS_PKT_TRAC_TYPE_EAPOL & tracking_map) { - ether_type = (v_U16_t)(*(v_U16_t *)(skb->data + VOS_PKT_TRAC_ETH_TYPE_OFFSET)); - if (VOS_PKT_TRAC_EAPOL_ETH_TYPE == VOS_SWAP_U16(ether_type)) - { - pkt_proto_type |= VOS_PKT_TRAC_TYPE_EAPOL; + if (adf_nbuf_is_eapol_pkt(skb) == A_STATUS_OK) { + pkt_proto_type = VOS_PKT_TRAC_TYPE_EAPOL; + return pkt_proto_type; } } /* DHCP Tracking enabled */ if (VOS_PKT_TRAC_TYPE_DHCP & tracking_map) { - SPort = (v_U16_t)(*(v_U16_t *)(skb->data + VOS_PKT_TRAC_IP_OFFSET + - VOS_PKT_TRAC_IP_HEADER_SIZE)); - DPort = (v_U16_t)(*(v_U16_t *)(skb->data + VOS_PKT_TRAC_IP_OFFSET + - VOS_PKT_TRAC_IP_HEADER_SIZE + sizeof(v_U16_t))); - if (((VOS_PKT_TRAC_DHCP_SRV_PORT == VOS_SWAP_U16(SPort)) && - (VOS_PKT_TRAC_DHCP_CLI_PORT == VOS_SWAP_U16(DPort))) || - ((VOS_PKT_TRAC_DHCP_CLI_PORT == VOS_SWAP_U16(SPort)) && - (VOS_PKT_TRAC_DHCP_SRV_PORT == VOS_SWAP_U16(DPort)))) - { - pkt_proto_type |= VOS_PKT_TRAC_TYPE_DHCP; + if (adf_nbuf_is_dhcp_pkt(skb) == A_STATUS_OK) { + pkt_proto_type = VOS_PKT_TRAC_TYPE_DHCP; + return pkt_proto_type; + } + } + + /* ARP Tracking enabled */ + if (VOS_PKT_TRAC_TYPE_ARP & tracking_map) { + if (adf_nbuf_is_ipv4_arp_pkt(skb)) { + pkt_proto_type = VOS_PKT_TRAC_TYPE_ARP; + return pkt_proto_type; + } + } + + /* IPV6 NS Tracking enabled */ + if (VOS_PKT_TRAC_TYPE_NS & tracking_map) { + if (adf_nbuf_is_icmpv6_pkt(skb)) { + if (adf_nbuf_get_icmpv6_subtype(skb) == + ADF_PROTO_ICMPV6_NS) { + pkt_proto_type = VOS_PKT_TRAC_TYPE_NS; + return pkt_proto_type; + } + } + } + + /* IPV6 NA Tracking enabled */ + if (VOS_PKT_TRAC_TYPE_NA & tracking_map) { + if (adf_nbuf_is_icmpv6_pkt(skb)) { + if (adf_nbuf_get_icmpv6_subtype(skb) == + ADF_PROTO_ICMPV6_NA) { + pkt_proto_type = VOS_PKT_TRAC_TYPE_NA; + return pkt_proto_type; + } } } @@ -329,9 +349,8 @@ void vos_pkt_trace_buf_update do_gettimeofday(&tv); trace_buffer[slot].event_sec_time = tv.tv_sec; trace_buffer[slot].event_msec_time = tv.tv_usec; - strncpy(trace_buffer[slot].event_string, event_string, - (sizeof(trace_buffer[slot].event_string) < strlen(event_string)? - sizeof(trace_buffer[slot].event_string) : strlen(event_string))); + strlcpy(trace_buffer[slot].event_string, event_string, + sizeof(trace_buffer[slot].event_string)); return; } diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c index b4244e92e2a5..84a5c9b92ed0 100644 --- a/drivers/usb/dwc3/dwc3-msm.c +++ b/drivers/usb/dwc3/dwc3-msm.c @@ -250,6 +250,7 @@ struct dwc3_msm { int redrive_3p0_c2; struct delayed_work vbus_notify_work; bool pd_vbus_change; + bool xo_vote_for_charger; }; #define USB_HSPHY_3P3_VOL_MIN 3050000 /* uV */ @@ -2013,7 +2014,13 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc) */ clk_disable_unprepare(mdwc->iface_clk); /* USB PHY no more requires TCXO */ - clk_disable_unprepare(mdwc->xo_clk); + if (!mdwc->xo_vote_for_charger) { + clk_disable_unprepare(mdwc->xo_clk); + dev_err(mdwc->dev, "%s unvote for TCXO buffer\n", __func__); + } else { + dev_err(mdwc->dev, "%s xo_vote_for_charger = %d\n", + __func__, mdwc->xo_vote_for_charger); + } /* Perform controller power collapse */ if (!mdwc->in_host_mode && (!mdwc->vbus_active || @@ -2087,10 +2094,18 @@ static int dwc3_msm_resume(struct dwc3_msm *mdwc) } /* Vote for TCXO while waking up USB HSPHY */ - ret = clk_prepare_enable(mdwc->xo_clk); - if (ret) - dev_err(mdwc->dev, "%s failed to vote TCXO buffer%d\n", - __func__, ret); + if (!mdwc->xo_vote_for_charger) { + ret = clk_prepare_enable(mdwc->xo_clk); + if (ret) + dev_err(mdwc->dev, "%s failed to vote TCXO buffer%d\n", + __func__, ret); + else + dev_err(mdwc->dev, "%s vote for TCXO buffer\n", + __func__); + } else { + dev_err(mdwc->dev, "%s xo_vote_for_charger = %d\n", + __func__, mdwc->xo_vote_for_charger); + } /* Restore controller power collapse */ if (mdwc->lpm_flags & MDWC3_POWER_COLLAPSE) { @@ -2533,6 +2548,33 @@ static int dwc3_msm_power_set_property_usb(struct power_supply *psy, break; } + if (mdwc->chg_type == DWC3_DCP_CHARGER || mdwc->chg_type == DWC3_TYPEC_CHARGER || + mdwc->chg_type == DWC3_PD_CHARGER || mdwc->chg_type == DWC3_PD_DRP_CHARGER || + mdwc->chg_type == DWC3_PROPRIETARY_CHARGER) { + if (!mdwc->xo_vote_for_charger) { + struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3); + if (atomic_read(&dwc->in_lpm)) { + int ret; + ret = clk_prepare_enable(mdwc->xo_clk); + if (ret) + dev_err(mdwc->dev, "%s failed to vote TCXO buffer%d\n", + __func__, ret); + else + dev_err(mdwc->dev, "%s TCXO enabled\n", __func__); + } + mdwc->xo_vote_for_charger = true; + } + } else { + if (mdwc->xo_vote_for_charger) { + struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3); + if (atomic_read(&dwc->in_lpm)) { + clk_disable_unprepare(mdwc->xo_clk); + dev_err(mdwc->dev, "%s TCXO disabled\n", __func__); + } + mdwc->xo_vote_for_charger = false; + } + } + if (mdwc->chg_type != DWC3_INVALID_CHARGER) mdwc->chg_state = USB_CHG_STATE_DETECTED; @@ -3313,6 +3355,7 @@ static int dwc3_msm_remove(struct platform_device *pdev) clk_disable_unprepare(mdwc->sleep_clk); clk_disable_unprepare(mdwc->xo_clk); clk_put(mdwc->xo_clk); + mdwc->xo_vote_for_charger = false; dwc3_msm_config_gdsc(mdwc, 0); diff --git a/drivers/video/msm/mdss/mdss_rotator.c b/drivers/video/msm/mdss/mdss_rotator.c index 8a5fb5e056ec..d324b04291d1 100644 --- a/drivers/video/msm/mdss/mdss_rotator.c +++ b/drivers/video/msm/mdss/mdss_rotator.c @@ -70,7 +70,7 @@ static struct msm_bus_scale_pdata rot_reg_bus_scale_table = { }; static struct mdss_rot_mgr *rot_mgr; -static void mdss_rotator_wq_handler(struct work_struct *work); +static void mdss_rotator_work_handler(struct kthread_work *work); static int mdss_rotator_bus_scale_set_quota(struct mdss_rot_bus_data_type *bus, u64 quota) @@ -834,6 +834,7 @@ static int mdss_rotator_init_queue(struct mdss_rot_mgr *mgr) { int i, size, ret = 0; char name[32]; + struct sched_param param = { .sched_priority = 5 }; size = sizeof(struct mdss_rot_queue) * mgr->queue_count; mgr->queues = devm_kzalloc(&mgr->pdev->dev, size, GFP_KERNEL); @@ -841,14 +842,18 @@ static int mdss_rotator_init_queue(struct mdss_rot_mgr *mgr) return -ENOMEM; for (i = 0; i < mgr->queue_count; i++) { - snprintf(name, sizeof(name), "rot_workq_%d", i); - pr_debug("work queue name=%s\n", name); - mgr->queues[i].rot_work_queue = alloc_ordered_workqueue("%s", - WQ_UNBOUND | WQ_MEM_RECLAIM | WQ_HIGHPRI, name); - if (!mgr->queues[i].rot_work_queue) { - ret = -EPERM; + snprintf(name, sizeof(name), "rot_thread_%d", i); + pr_info("work thread name=%s\n", name); + init_kthread_worker(&mgr->queues[i].worker); + mgr->queues[i].thread = kthread_run(kthread_worker_fn, + &mgr->queues[i].worker, + name); + if (IS_ERR(&mgr->queues[i].thread)) { + pr_err("Unable to start rotator thread: %d", i); + ret = -ENOMEM; break; } + sched_setscheduler(mgr->queues[i].thread, SCHED_FIFO, ¶m); snprintf(name, sizeof(name), "rot_timeline_%d", i); pr_debug("timeline name=%s\n", name); @@ -878,8 +883,8 @@ static void mdss_rotator_deinit_queue(struct mdss_rot_mgr *mgr) return; for (i = 0; i < mgr->queue_count; i++) { - if (mgr->queues[i].rot_work_queue) - destroy_workqueue(mgr->queues[i].rot_work_queue); + if (mgr->queues[i].thread) + kthread_stop(mgr->queues[i].thread); if (mgr->queues[i].timeline.timeline) { struct sync_timeline *obj; @@ -1016,7 +1021,7 @@ static void mdss_rotator_queue_request(struct mdss_rot_mgr *mgr, entry = req->entries + i; queue = entry->queue; entry->output_fence = NULL; - queue_work(queue->rot_work_queue, &entry->commit_work); + queue_kthread_work(&queue->worker, &entry->commit_work); } } @@ -1513,7 +1518,8 @@ static int mdss_rotator_add_request(struct mdss_rot_mgr *mgr, entry->request = req; - INIT_WORK(&entry->commit_work, mdss_rotator_wq_handler); + init_kthread_work(&entry->commit_work, + mdss_rotator_work_handler); ret = mdss_rotator_create_fence(entry); if (ret) { @@ -1565,7 +1571,7 @@ static void mdss_rotator_cancel_request(struct mdss_rot_mgr *mgr, */ for (i = req->count - 1; i >= 0; i--) { entry = req->entries + i; - cancel_work_sync(&entry->commit_work); + flush_kthread_work(&entry->commit_work); } for (i = req->count - 1; i >= 0; i--) { @@ -1835,7 +1841,7 @@ static int mdss_rotator_handle_entry(struct mdss_rot_hw_resource *hw, return ret; } -static void mdss_rotator_wq_handler(struct work_struct *work) +static void mdss_rotator_work_handler(struct kthread_work *work) { struct mdss_rot_entry *entry; struct mdss_rot_entry_container *request; @@ -2020,7 +2026,7 @@ static int mdss_rotator_close_session(struct mdss_rot_mgr *mgr, ATRACE_BEGIN(__func__); mutex_lock(&perf->work_dis_lock); if (mdss_rotator_is_work_pending(mgr, perf)) { - pr_debug("Work is still pending, offload free to wq\n"); + pr_debug("Work is still pending, offload free to worker\n"); mutex_lock(&mgr->bus_lock); mgr->pending_close_bw_vote += perf->bw; mutex_unlock(&mgr->bus_lock); diff --git a/drivers/video/msm/mdss/mdss_rotator_internal.h b/drivers/video/msm/mdss/mdss_rotator_internal.h index 2122efee6bda..d02c04043e91 100644 --- a/drivers/video/msm/mdss/mdss_rotator_internal.h +++ b/drivers/video/msm/mdss/mdss_rotator_internal.h @@ -70,9 +70,9 @@ struct mdss_rot_hw_resource { }; struct mdss_rot_queue { - struct workqueue_struct *rot_work_queue; + struct kthread_worker worker; + struct task_struct *thread; struct mdss_rot_timeline timeline; - struct mutex hw_lock; struct mdss_rot_hw_resource *hw; }; @@ -87,7 +87,7 @@ struct mdss_rot_entry_container { struct mdss_rot_entry { struct mdp_rotation_item item; - struct work_struct commit_work; + struct kthread_work commit_work; struct mdss_rot_queue *queue; struct mdss_rot_entry_container *request; diff --git a/fs/eventpoll.c b/fs/eventpoll.c index 1c6bba7e6aa1..08a6a6ee5ecb 100644 --- a/fs/eventpoll.c +++ b/fs/eventpoll.c @@ -1230,13 +1230,15 @@ static int ep_create_wakeup_source(struct epitem *epi) const char *name; struct wakeup_source *ws; + name = epi->ffd.file->f_path.dentry->d_name.name; if (!epi->ep->ws) { - epi->ep->ws = wakeup_source_register("eventpoll"); + char buf[64]; + snprintf(buf, sizeof(buf), "eventpoll pid:%d file:%s", current->pid, name); + epi->ep->ws = wakeup_source_register(buf); if (!epi->ep->ws) return -ENOMEM; } - name = epi->ffd.file->f_path.dentry->d_name.name; ws = wakeup_source_register(name); if (!ws) diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c index 15ee78c5020b..ad1fe993d2d0 100644 --- a/fs/pstore/platform.c +++ b/fs/pstore/platform.c @@ -404,6 +404,40 @@ static int pstore_write_compat(enum pstore_type_id type, size, psi); } +static int pstore_write_buf_user_compat(enum pstore_type_id type, + enum kmsg_dump_reason reason, + u64 *id, unsigned int part, + const char __user *buf, + bool compressed, size_t size, + struct pstore_info *psi) +{ + unsigned long flags = 0; + size_t i, bufsize = size; + long ret = 0; + + if (unlikely(!access_ok(VERIFY_READ, buf, size))) + return -EFAULT; + if (bufsize > psinfo->bufsize) + bufsize = psinfo->bufsize; + spin_lock_irqsave(&psinfo->buf_lock, flags); + for (i = 0; i < size; ) { + size_t c = min(size - i, bufsize); + + ret = __copy_from_user(psinfo->buf, buf + i, c); + if (unlikely(ret != 0)) { + ret = -EFAULT; + break; + } + ret = psi->write_buf(type, reason, id, part, psinfo->buf, + compressed, c, psi); + if (unlikely(ret < 0)) + break; + i += c; + } + spin_unlock_irqrestore(&psinfo->buf_lock, flags); + return unlikely(ret < 0) ? ret : size; +} + /* * platform specific persistent storage driver registers with * us here. If pstore is already mounted, call the platform @@ -428,6 +462,8 @@ int pstore_register(struct pstore_info *psi) if (!psi->write) psi->write = pstore_write_compat; + if (!psi->write_buf_user) + psi->write_buf_user = pstore_write_buf_user_compat; psinfo = psi; mutex_init(&psinfo->read_mutex); spin_unlock(&pstore_lock); diff --git a/fs/pstore/pmsg.c b/fs/pstore/pmsg.c index 5a2f05a16c1e..64b97a2966d9 100644 --- a/fs/pstore/pmsg.c +++ b/fs/pstore/pmsg.c @@ -19,48 +19,25 @@ #include "internal.h" static DEFINE_MUTEX(pmsg_lock); -#define PMSG_MAX_BOUNCE_BUFFER_SIZE (2*PAGE_SIZE) static ssize_t write_pmsg(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { - size_t i, buffer_size; - char *buffer; + u64 id; + int ret; if (!count) return 0; + /* check outside lock, page in any data. write_buf_user also checks */ if (!access_ok(VERIFY_READ, buf, count)) return -EFAULT; - buffer_size = count; - if (buffer_size > PMSG_MAX_BOUNCE_BUFFER_SIZE) - buffer_size = PMSG_MAX_BOUNCE_BUFFER_SIZE; - buffer = vmalloc(buffer_size); - if (!buffer) - return -ENOMEM; - mutex_lock(&pmsg_lock); - for (i = 0; i < count; ) { - size_t c = min(count - i, buffer_size); - u64 id; - long ret; - - ret = __copy_from_user(buffer, buf + i, c); - if (unlikely(ret != 0)) { - mutex_unlock(&pmsg_lock); - vfree(buffer); - return -EFAULT; - } - psinfo->write_buf(PSTORE_TYPE_PMSG, 0, &id, 0, buffer, 0, c, - psinfo); - - i += c; - } - + ret = psinfo->write_buf_user(PSTORE_TYPE_PMSG, 0, &id, 0, buf, 0, count, + psinfo); mutex_unlock(&pmsg_lock); - vfree(buffer); - return count; + return ret ? ret : count; } static const struct file_operations pmsg_fops = { diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c index 58a40da3bdd7..c3b8d793d9da 100644 --- a/fs/pstore/ram.c +++ b/fs/pstore/ram.c @@ -307,6 +307,24 @@ static int notrace ramoops_pstore_write_buf(enum pstore_type_id type, return 0; } +static int notrace ramoops_pstore_write_buf_user(enum pstore_type_id type, + enum kmsg_dump_reason reason, + u64 *id, unsigned int part, + const char __user *buf, + bool compressed, size_t size, + struct pstore_info *psi) +{ + if (type == PSTORE_TYPE_PMSG) { + struct ramoops_context *cxt = psi->data; + + if (!cxt->mprz) + return -ENOMEM; + return persistent_ram_write_user(cxt->mprz, buf, size); + } + + return -EINVAL; +} + static int ramoops_pstore_erase(enum pstore_type_id type, u64 id, int count, struct timespec time, struct pstore_info *psi) { @@ -345,6 +363,7 @@ static struct ramoops_context oops_cxt = { .open = ramoops_pstore_open, .read = ramoops_pstore_read, .write_buf = ramoops_pstore_write_buf, + .write_buf_user = ramoops_pstore_write_buf_user, .erase = ramoops_pstore_erase, }, }; diff --git a/fs/pstore/ram_core.c b/fs/pstore/ram_core.c index 76c3f80efdfa..aa9afe573155 100644 --- a/fs/pstore/ram_core.c +++ b/fs/pstore/ram_core.c @@ -17,15 +17,16 @@ #include <linux/device.h> #include <linux/err.h> #include <linux/errno.h> -#include <linux/kernel.h> #include <linux/init.h> #include <linux/io.h> +#include <linux/kernel.h> #include <linux/list.h> #include <linux/memblock.h> +#include <linux/pstore_ram.h> #include <linux/rslib.h> #include <linux/slab.h> +#include <linux/uaccess.h> #include <linux/vmalloc.h> -#include <linux/pstore_ram.h> #include <asm/page.h> struct persistent_ram_buffer { @@ -303,6 +304,16 @@ static void notrace persistent_ram_update(struct persistent_ram_zone *prz, persistent_ram_update_ecc(prz, start, count); } +static int notrace persistent_ram_update_user(struct persistent_ram_zone *prz, + const void __user *s, unsigned int start, unsigned int count) +{ + struct persistent_ram_buffer *buffer = prz->buffer; + int ret = unlikely(__copy_from_user(buffer->data + start, s, count)) ? + -EFAULT : 0; + persistent_ram_update_ecc(prz, start, count); + return ret; +} + void persistent_ram_save_old(struct persistent_ram_zone *prz) { struct persistent_ram_buffer *buffer = prz->buffer; @@ -356,6 +367,38 @@ int notrace persistent_ram_write(struct persistent_ram_zone *prz, return count; } +int notrace persistent_ram_write_user(struct persistent_ram_zone *prz, + const void __user *s, unsigned int count) +{ + int rem, ret = 0, c = count; + size_t start; + + if (unlikely(!access_ok(VERIFY_READ, s, count))) + return -EFAULT; + if (unlikely(c > prz->buffer_size)) { + s += c - prz->buffer_size; + c = prz->buffer_size; + } + + buffer_size_add(prz, c); + + start = buffer_start_add(prz, c); + + rem = prz->buffer_size - start; + if (unlikely(rem < c)) { + ret = persistent_ram_update_user(prz, s, start, rem); + s += rem; + c -= rem; + start = 0; + } + if (likely(!ret)) + ret = persistent_ram_update_user(prz, s, start, c); + + persistent_ram_update_header_ecc(prz); + + return unlikely(ret) ? ret : count; +} + size_t persistent_ram_old_size(struct persistent_ram_zone *prz) { return prz->old_log_size; diff --git a/include/linux/inet_diag.h b/include/linux/inet_diag.h index 25de5e73845c..4f214275d13c 100644 --- a/include/linux/inet_diag.h +++ b/include/linux/inet_diag.h @@ -36,7 +36,7 @@ int inet_sk_diag_fill(struct sock *sk, struct inet_connection_sock *icsk, struct sk_buff *skb, struct inet_diag_req_v2 *req, struct user_namespace *user_ns, u32 pid, u32 seq, u16 nlmsg_flags, - const struct nlmsghdr *unlh); + const struct nlmsghdr *unlh, bool net_admin); void inet_diag_dump_icsk(struct inet_hashinfo *h, struct sk_buff *skb, struct netlink_callback *cb, struct inet_diag_req_v2 *r, struct nlattr *bc); diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h index 2357215b0ac4..bceb0928f8a3 100644 --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h @@ -402,6 +402,12 @@ enum }; #define SOFTIRQ_STOP_IDLE_MASK (~(1 << RCU_SOFTIRQ)) +/* Softirq's where the handling might be long: */ +#define LONG_SOFTIRQ_MASK ((1 << NET_TX_SOFTIRQ) | \ + (1 << NET_RX_SOFTIRQ) | \ + (1 << BLOCK_SOFTIRQ) | \ + (1 << BLOCK_IOPOLL_SOFTIRQ) | \ + (1 << TASKLET_SOFTIRQ)) /* map softirq index to softirq name. update 'softirq_to_name' in * kernel/softirq.c when adding a new softirq. @@ -437,6 +443,7 @@ extern void raise_softirq_irqoff(unsigned int nr); extern void raise_softirq(unsigned int nr); DECLARE_PER_CPU(struct task_struct *, ksoftirqd); +DECLARE_PER_CPU(__u32, active_softirqs); static inline struct task_struct *this_cpu_ksoftirqd(void) { diff --git a/include/linux/power/htc_battery.h b/include/linux/power/htc_battery.h index 94247c346f80..b5662e84e2f5 100644 --- a/include/linux/power/htc_battery.h +++ b/include/linux/power/htc_battery.h @@ -154,6 +154,7 @@ struct htc_battery_info { struct power_supply *usb_psy; struct power_supply *parallel_psy; int critical_low_voltage_mv; + int force_shutdown_batt_vol; int smooth_chg_full_delay_min; int decreased_batt_level_check; int batt_full_voltage_mv; @@ -161,6 +162,7 @@ struct htc_battery_info { int batt_eoc_current_ma; int overload_curr_thr_ma; struct wake_lock charger_exist_lock; + struct wake_lock batt_shutdown_lock; struct delayed_work chg_full_check_work; struct delayed_work is_usb_overheat_work; struct delayed_work chk_unknown_chg_work; diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h index 0aa38701e404..87ee0454808b 100644 --- a/include/linux/power_supply.h +++ b/include/linux/power_supply.h @@ -223,6 +223,7 @@ enum power_supply_property { #ifdef CONFIG_HTC_BATT POWER_SUPPLY_PROP_SYSTEM_SOC, POWER_SUPPLY_PROP_TYPEC_SINK_CURRENT, + POWER_SUPPLY_PROP_CRITICAL_SHUTDOWN, #endif /* CONFIG_HTC_BATT */ }; diff --git a/include/linux/pstore.h b/include/linux/pstore.h index 8884f6e507f7..2eec52d597ce 100644 --- a/include/linux/pstore.h +++ b/include/linux/pstore.h @@ -22,12 +22,13 @@ #ifndef _LINUX_PSTORE_H #define _LINUX_PSTORE_H -#include <linux/time.h> +#include <linux/compiler.h> +#include <linux/errno.h> #include <linux/kmsg_dump.h> #include <linux/mutex.h> -#include <linux/types.h> #include <linux/spinlock.h> -#include <linux/errno.h> +#include <linux/time.h> +#include <linux/types.h> /* types */ enum pstore_type_id { @@ -66,6 +67,10 @@ struct pstore_info { enum kmsg_dump_reason reason, u64 *id, unsigned int part, const char *buf, bool compressed, size_t size, struct pstore_info *psi); + int (*write_buf_user)(enum pstore_type_id type, + enum kmsg_dump_reason reason, u64 *id, + unsigned int part, const char __user *buf, + bool compressed, size_t size, struct pstore_info *psi); int (*erase)(enum pstore_type_id type, u64 id, int count, struct timespec time, struct pstore_info *psi); diff --git a/include/linux/pstore_ram.h b/include/linux/pstore_ram.h index 712757f320a4..45ac5a0d29ee 100644 --- a/include/linux/pstore_ram.h +++ b/include/linux/pstore_ram.h @@ -17,11 +17,12 @@ #ifndef __LINUX_PSTORE_RAM_H__ #define __LINUX_PSTORE_RAM_H__ +#include <linux/compiler.h> #include <linux/device.h> +#include <linux/init.h> #include <linux/kernel.h> #include <linux/list.h> #include <linux/types.h> -#include <linux/init.h> struct persistent_ram_buffer; struct rs_control; @@ -59,7 +60,9 @@ void persistent_ram_free(struct persistent_ram_zone *prz); void persistent_ram_zap(struct persistent_ram_zone *prz); int persistent_ram_write(struct persistent_ram_zone *prz, const void *s, - unsigned int count); + unsigned int count); +int persistent_ram_write_user(struct persistent_ram_zone *prz, + const void __user *s, unsigned int count); void persistent_ram_save_old(struct persistent_ram_zone *prz); size_t persistent_ram_old_size(struct persistent_ram_zone *prz); diff --git a/include/linux/trace_clock.h b/include/linux/trace_clock.h index 1d7ca2739272..5ad5b6b2c1db 100644 --- a/include/linux/trace_clock.h +++ b/include/linux/trace_clock.h @@ -19,5 +19,6 @@ extern u64 notrace trace_clock(void); extern u64 notrace trace_clock_jiffies(void); extern u64 notrace trace_clock_global(void); extern u64 notrace trace_clock_counter(void); +extern u64 notrace trace_clock_boot(void); #endif /* _LINUX_TRACE_CLOCK_H */ diff --git a/include/net/udp.h b/include/net/udp.h index 07f9b70962f6..a274df0c3421 100644 --- a/include/net/udp.h +++ b/include/net/udp.h @@ -229,6 +229,7 @@ int udp_get_port(struct sock *sk, unsigned short snum, int (*saddr_cmp)(const struct sock *, const struct sock *)); void udp_err(struct sk_buff *, u32); +int udp_abort(struct sock *sk, int err); int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, size_t len); int udp_push_pending_frames(struct sock *sk); diff --git a/include/soc/qcom/subsystem_restart.h b/include/soc/qcom/subsystem_restart.h index 3a5f6e678b4f..c13b864b9bf1 100644 --- a/include/soc/qcom/subsystem_restart.h +++ b/include/soc/qcom/subsystem_restart.h @@ -17,6 +17,8 @@ #include <linux/spinlock.h> #include <linux/interrupt.h> +#define MAX_SSR_REASON_LEN 81U + struct subsys_device; enum { @@ -85,6 +87,7 @@ struct subsys_desc { int sysmon_shutdown_ret; bool system_debug; const char *edge; + char last_crash_reason[MAX_SSR_REASON_LEN]; }; /** diff --git a/include/uapi/linux/inet_diag.h b/include/uapi/linux/inet_diag.h index d65c0a09efd3..e835704ab807 100644 --- a/include/uapi/linux/inet_diag.h +++ b/include/uapi/linux/inet_diag.h @@ -72,6 +72,8 @@ enum { INET_DIAG_BC_AUTO, INET_DIAG_BC_S_COND, INET_DIAG_BC_D_COND, + INET_DIAG_BC_DEV_COND, /* u32 ifindex */ + INET_DIAG_BC_MARK_COND, }; struct inet_diag_hostcond { @@ -81,6 +83,11 @@ struct inet_diag_hostcond { __be32 addr[0]; }; +struct inet_diag_markcond { + __u32 mark; + __u32 mask; +}; + /* Base info structure. It contains socket identity (addrs/ports/cookie) * and, alas, the information shown by netstat. */ struct inet_diag_msg { @@ -111,9 +118,15 @@ enum { INET_DIAG_SKMEMINFO, INET_DIAG_SHUTDOWN, INET_DIAG_DCTCPINFO, + INET_DIAG_PROTOCOL, /* response attribute only */ + INET_DIAG_SKV6ONLY, + INET_DIAG_LOCALS, + INET_DIAG_PEERS, + INET_DIAG_PAD, + INET_DIAG_MARK, }; -#define INET_DIAG_MAX INET_DIAG_DCTCPINFO +#define INET_DIAG_MAX INET_DIAG_MARK /* INET_DIAG_MEM */ diff --git a/include/uapi/media/msmb_ispif.h b/include/uapi/media/msmb_ispif.h index 26bd8a2ce87f..7d4e489a3f04 100644 --- a/include/uapi/media/msmb_ispif.h +++ b/include/uapi/media/msmb_ispif.h @@ -105,7 +105,7 @@ enum ispif_cfg_type_t { ISPIF_INIT, ISPIF_CFG, ISPIF_START_FRAME_BOUNDARY, - ISPIF_RESTART_FRAME_BOUNDARY, + ISPIF_RECONFIG, ISPIF_STOP_FRAME_BOUNDARY, ISPIF_STOP_IMMEDIATELY, ISPIF_RELEASE, diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c index 6c5eeee441e9..69690c7d5ad2 100644 --- a/kernel/rcu/tree.c +++ b/kernel/rcu/tree.c @@ -1045,11 +1045,13 @@ static void rcu_dump_cpu_stacks(struct rcu_state *rsp) } } -static void print_other_cpu_stall(struct rcu_state *rsp) +static void print_other_cpu_stall(struct rcu_state *rsp, unsigned long gpnum) { int cpu; long delta; unsigned long flags; + unsigned long gpa; + unsigned long j; int ndetected = 0; struct rcu_node *rnp = rcu_get_root(rsp); long totqlen = 0; @@ -1102,10 +1104,22 @@ static void print_other_cpu_stall(struct rcu_state *rsp) pr_cont("(detected by %d, t=%ld jiffies, g=%ld, c=%ld, q=%lu)\n", smp_processor_id(), (long)(jiffies - rsp->gp_start), (long)rsp->gpnum, (long)rsp->completed, totqlen); - if (ndetected == 0) - pr_err("INFO: Stall ended before state dump start\n"); - else + if (ndetected) { rcu_dump_cpu_stacks(rsp); + } else { + if (ACCESS_ONCE(rsp->gpnum) != gpnum || + ACCESS_ONCE(rsp->completed) == gpnum) { + pr_err("INFO: Stall ended before state dump start\n"); + } else { + j = jiffies; + gpa = ACCESS_ONCE(rsp->gp_activity); + pr_err("All QSes seen, last %s kthread activity %ld (%ld-%ld), jiffies_till_next_fqs=%ld\n", + rsp->name, j - gpa, j, gpa, + jiffies_till_next_fqs); + /* In this case, the current CPU might be at fault. */ + sched_show_task(current); + } + } /* Complain about tasks blocking the grace period. */ @@ -1205,7 +1219,7 @@ static void check_cpu_stall(struct rcu_state *rsp, struct rcu_data *rdp) ULONG_CMP_GE(j, js + RCU_STALL_RAT_DELAY)) { /* They had a few time units to dump stack, so complain. */ - print_other_cpu_stall(rsp); + print_other_cpu_stall(rsp, gpnum); } } @@ -1601,6 +1615,7 @@ static int rcu_gp_init(struct rcu_state *rsp) struct rcu_data *rdp; struct rcu_node *rnp = rcu_get_root(rsp); + ACCESS_ONCE(rsp->gp_activity) = jiffies; rcu_bind_gp_kthread(); raw_spin_lock_irq(&rnp->lock); smp_mb__after_unlock_lock(); @@ -1661,6 +1676,7 @@ static int rcu_gp_init(struct rcu_state *rsp) rnp->grphi, rnp->qsmask); raw_spin_unlock_irq(&rnp->lock); cond_resched_rcu_qs(); + ACCESS_ONCE(rsp->gp_activity) = jiffies; } mutex_unlock(&rsp->onoff_mutex); @@ -1677,6 +1693,7 @@ static int rcu_gp_fqs(struct rcu_state *rsp, int fqs_state_in) unsigned long maxj; struct rcu_node *rnp = rcu_get_root(rsp); + ACCESS_ONCE(rsp->gp_activity) = jiffies; rsp->n_force_qs++; if (fqs_state == RCU_SAVE_DYNTICK) { /* Collect dyntick-idle snapshots. */ @@ -1715,6 +1732,7 @@ static void rcu_gp_cleanup(struct rcu_state *rsp) struct rcu_data *rdp; struct rcu_node *rnp = rcu_get_root(rsp); + ACCESS_ONCE(rsp->gp_activity) = jiffies; raw_spin_lock_irq(&rnp->lock); smp_mb__after_unlock_lock(); gp_duration = jiffies - rsp->gp_start; @@ -1751,6 +1769,7 @@ static void rcu_gp_cleanup(struct rcu_state *rsp) nocb += rcu_future_gp_cleanup(rsp, rnp); raw_spin_unlock_irq(&rnp->lock); cond_resched_rcu_qs(); + ACCESS_ONCE(rsp->gp_activity) = jiffies; } rnp = rcu_get_root(rsp); raw_spin_lock_irq(&rnp->lock); @@ -1800,6 +1819,7 @@ static int __noreturn rcu_gp_kthread(void *arg) if (rcu_gp_init(rsp)) break; cond_resched_rcu_qs(); + ACCESS_ONCE(rsp->gp_activity) = jiffies; WARN_ON(signal_pending(current)); trace_rcu_grace_period(rsp->name, ACCESS_ONCE(rsp->gpnum), @@ -1843,9 +1863,11 @@ static int __noreturn rcu_gp_kthread(void *arg) ACCESS_ONCE(rsp->gpnum), TPS("fqsend")); cond_resched_rcu_qs(); + ACCESS_ONCE(rsp->gp_activity) = jiffies; } else { /* Deal with stray signal. */ cond_resched_rcu_qs(); + ACCESS_ONCE(rsp->gp_activity) = jiffies; WARN_ON(signal_pending(current)); trace_rcu_grace_period(rsp->name, ACCESS_ONCE(rsp->gpnum), diff --git a/kernel/rcu/tree.h b/kernel/rcu/tree.h index 0185bcc00504..81ee56afd6cf 100644 --- a/kernel/rcu/tree.h +++ b/kernel/rcu/tree.h @@ -493,6 +493,8 @@ struct rcu_state { /* due to no GP active. */ unsigned long gp_start; /* Time at which GP started, */ /* but in jiffies. */ + unsigned long gp_activity; /* Time of last GP kthread */ + /* activity in jiffies. */ unsigned long jiffies_stall; /* Time at which to check */ /* for CPU stalls. */ unsigned long jiffies_resched; /* Time at which to resched */ diff --git a/kernel/sched/cpupri.c b/kernel/sched/cpupri.c index 981fcd7dc394..d6f5d003793c 100644 --- a/kernel/sched/cpupri.c +++ b/kernel/sched/cpupri.c @@ -27,6 +27,8 @@ * of the License. */ +#include "sched.h" + #include <linux/gfp.h> #include <linux/sched.h> #include <linux/sched/rt.h> @@ -51,6 +53,24 @@ static int convert_prio(int prio) } /** + * cpupri_find - remove a cpu from the mask if it is likely non-preemptible + * @lowest_mask: mask with selected CPUs (non-NULL) + */ +static void +drop_nopreempt_cpus(struct cpumask *lowest_mask) +{ + unsigned cpu = cpumask_first(lowest_mask); + while (cpu < nr_cpu_ids) { + /* unlocked access */ + struct task_struct *task = READ_ONCE(cpu_rq(cpu)->curr); + if (task_may_not_preempt(task, cpu)) { + cpumask_clear_cpu(cpu, lowest_mask); + } + cpu = cpumask_next(cpu, lowest_mask); + } +} + +/** * cpupri_find - find the best (lowest-pri) CPU in the system * @cp: The cpupri context * @p: The task @@ -70,9 +90,11 @@ int cpupri_find(struct cpupri *cp, struct task_struct *p, { int idx = 0; int task_pri = convert_prio(p->prio); + bool drop_nopreempts = task_pri <= MAX_RT_PRIO; BUG_ON(task_pri >= CPUPRI_NR_PRIORITIES); +retry: for (idx = 0; idx < task_pri; idx++) { struct cpupri_vec *vec = &cp->pri_to_cpu[idx]; int skip = 0; @@ -108,7 +130,9 @@ int cpupri_find(struct cpupri *cp, struct task_struct *p, if (lowest_mask) { cpumask_and(lowest_mask, &p->cpus_allowed, vec->mask); - + if (drop_nopreempts) { + drop_nopreempt_cpus(lowest_mask); + } /* * We have to ensure that we have at least one bit * still set in the array, since the map could have @@ -123,7 +147,14 @@ int cpupri_find(struct cpupri *cp, struct task_struct *p, return 1; } - + /* + * If we can't find any non-preemptible cpu's, retry so we can + * find the lowest priority target and avoid priority inversion. + */ + if (drop_nopreempts) { + drop_nopreempts = false; + goto retry; + } return 0; } diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index e3c4491b0d8f..50885d9c0e4c 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -6950,7 +6950,8 @@ static void update_cpu_capacity(struct sched_domain *sd, int cpu) mcc->cpu = cpu; #ifdef CONFIG_SCHED_DEBUG raw_spin_unlock_irqrestore(&mcc->lock, flags); - pr_info("CPU%d: update max cpu_capacity %lu\n", cpu, capacity); + printk_deferred(KERN_INFO "CPU%d: update max cpu_capacity %lu\n", + cpu, capacity); goto skip_unlock; #endif } diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c index 24ad9f1deb83..56316f26e25e 100644 --- a/kernel/sched/rt.c +++ b/kernel/sched/rt.c @@ -5,6 +5,7 @@ #include "sched.h" +#include <linux/interrupt.h> #include <linux/slab.h> #include "walt.h" @@ -1350,11 +1351,29 @@ static void yield_task_rt(struct rq *rq) #ifdef CONFIG_SMP static int find_lowest_rq(struct task_struct *task); +/* + * Return whether the task on the given cpu is currently non-preemptible + * while handling a potentially long softint, or if the task is likely + * to block preemptions soon because it is a ksoftirq thread that is + * handling slow softints. + */ +bool +task_may_not_preempt(struct task_struct *task, int cpu) +{ + __u32 softirqs = per_cpu(active_softirqs, cpu) | + __IRQ_STAT(cpu, __softirq_pending); + struct task_struct *cpu_ksoftirqd = per_cpu(ksoftirqd, cpu); + return ((softirqs & LONG_SOFTIRQ_MASK) && + (task == cpu_ksoftirqd || + task_thread_info(task)->preempt_count & SOFTIRQ_MASK)); +} + static int select_task_rq_rt(struct task_struct *p, int cpu, int sd_flag, int flags) { struct task_struct *curr; struct rq *rq; + bool may_not_preempt; if (p->nr_cpus_allowed == 1) goto out; @@ -1369,7 +1388,12 @@ select_task_rq_rt(struct task_struct *p, int cpu, int sd_flag, int flags) curr = READ_ONCE(rq->curr); /* unlocked access */ /* - * If the current task on @p's runqueue is an RT task, then + * If the current task on @p's runqueue is a softirq task, + * it may run without preemption for a time that is + * ill-suited for a waiting RT task. Therefore, try to + * wake this RT task on another runqueue. + * + * Also, if the current task on @p's runqueue is an RT task, then * try to see if we can wake this RT task up on another * runqueue. Otherwise simply start this RT task * on its current runqueue. @@ -1390,17 +1414,21 @@ select_task_rq_rt(struct task_struct *p, int cpu, int sd_flag, int flags) * This test is optimistic, if we get it wrong the load-balancer * will have to sort it out. */ - if (curr && unlikely(rt_task(curr)) && - (curr->nr_cpus_allowed < 2 || - curr->prio <= p->prio)) { + may_not_preempt = task_may_not_preempt(curr, cpu); + if (curr && (may_not_preempt || + (unlikely(rt_task(curr)) && + (curr->nr_cpus_allowed < 2 || + curr->prio <= p->prio)))) { int target = find_lowest_rq(p); - - /* - * Possible race. Don't bother moving it if the + /* + * If cpu is non-preemptible, prefer remote cpu + * even if it's running a higher-prio task. + * Otherwise: Possible race. Don't bother moving it if the * destination CPU is not running a lower priority task. - */ - if (target != -1 && - p->prio < cpu_rq(target)->rt.highest_prio.curr) + */ + if (target != -1 && + (may_not_preempt || + p->prio < cpu_rq(target)->rt.highest_prio.curr)) cpu = target; } rcu_read_unlock(); diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index 5aee6642c0ec..fba847e50001 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -1842,3 +1842,8 @@ static inline u64 irq_time_read(int cpu) } #endif /* CONFIG_64BIT */ #endif /* CONFIG_IRQ_TIME_ACCOUNTING */ + +/* + * task_may_not_preempt - check whether a task may not be preemptible soon + */ +extern bool task_may_not_preempt(struct task_struct *task, int cpu); diff --git a/kernel/softirq.c b/kernel/softirq.c index 8b0708ad35a1..4726b886622f 100644 --- a/kernel/softirq.c +++ b/kernel/softirq.c @@ -58,6 +58,13 @@ static struct softirq_action softirq_vec[NR_SOFTIRQS] __cacheline_aligned_in_smp DEFINE_PER_CPU(struct task_struct *, ksoftirqd); +/* + * active_softirqs -- per cpu, a mask of softirqs that are being handled, + * with the expectation that approximate answers are acceptable and therefore + * no synchronization. + */ +DEFINE_PER_CPU(__u32, active_softirqs); + const char * const softirq_to_name[NR_SOFTIRQS] = { "HI", "TIMER", "NET_TX", "NET_RX", "BLOCK", "BLOCK_IOPOLL", "TASKLET", "SCHED", "HRTIMER", "RCU" @@ -250,6 +257,7 @@ asmlinkage __visible void __do_softirq(void) restart: /* Reset the pending bitmask before enabling irqs */ set_softirq_pending(0); + __this_cpu_write(active_softirqs, pending); local_irq_enable(); @@ -281,6 +289,7 @@ restart: pending >>= softirq_bit; } + __this_cpu_write(active_softirqs, 0); rcu_bh_qs(); local_irq_disable(); diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 445f12467b6b..7922e8edef98 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -832,6 +832,7 @@ static struct { { trace_clock_jiffies, "uptime", 0 }, { trace_clock, "perf", 1 }, { ktime_get_mono_fast_ns, "mono", 1 }, + { trace_clock_boot, "boot", 1 }, ARCH_TRACE_CLOCKS }; diff --git a/kernel/trace/trace_clock.c b/kernel/trace/trace_clock.c index 57b67b1f24d1..0bce235a7a33 100644 --- a/kernel/trace/trace_clock.c +++ b/kernel/trace/trace_clock.c @@ -135,3 +135,17 @@ u64 notrace trace_clock_counter(void) { return atomic64_add_return(1, &trace_counter); } + +/* + * trace_clock_boot(): use CLOCK_BOOTTIME for tracing + * This should be equivalent to trace_clock_global for most users, + * but it has the added advantage of tracking time spent in suspend. + */ +u64 notrace trace_clock_boot(void) +{ + struct timespec uptime; + get_monotonic_boottime(&uptime); + return (uptime.tv_sec * 1000000000ull) + uptime.tv_nsec; +} + +EXPORT_SYMBOL_GPL(trace_clock_boot); diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c index 0a55318da183..2a2eecb16adf 100644 --- a/net/ipv4/inet_diag.c +++ b/net/ipv4/inet_diag.c @@ -48,6 +48,8 @@ struct inet_diag_entry { struct in6_addr saddr_storage; /* for IPv4-mapped-IPv6 addresses */ struct in6_addr daddr_storage; /* for IPv4-mapped-IPv6 addresses */ #endif + u32 ifindex; + u32 mark; }; static DEFINE_MUTEX(inet_diag_table_mutex); @@ -89,7 +91,7 @@ int inet_sk_diag_fill(struct sock *sk, struct inet_connection_sock *icsk, struct sk_buff *skb, struct inet_diag_req_v2 *req, struct user_namespace *user_ns, u32 portid, u32 seq, u16 nlmsg_flags, - const struct nlmsghdr *unlh) + const struct nlmsghdr *unlh, bool net_admin) { const struct inet_sock *inet = inet_sk(sk); struct inet_diag_msg *r; @@ -150,6 +152,9 @@ int inet_sk_diag_fill(struct sock *sk, struct inet_connection_sock *icsk, } #endif + if (net_admin && nla_put_u32(skb, INET_DIAG_MARK, sk->sk_mark)) + goto errout; + r->idiag_uid = from_kuid_munged(user_ns, sock_i_uid(sk)); r->idiag_inode = sock_i_ino(sk); @@ -229,10 +234,12 @@ static int inet_csk_diag_fill(struct sock *sk, struct sk_buff *skb, struct inet_diag_req_v2 *req, struct user_namespace *user_ns, u32 portid, u32 seq, u16 nlmsg_flags, - const struct nlmsghdr *unlh) + const struct nlmsghdr *unlh, + bool net_admin) { return inet_sk_diag_fill(sk, inet_csk(sk), - skb, req, user_ns, portid, seq, nlmsg_flags, unlh); + skb, req, user_ns, portid, seq, nlmsg_flags, unlh, + net_admin); } static int inet_twsk_diag_fill(struct inet_timewait_sock *tw, @@ -292,14 +299,14 @@ static int sk_diag_fill(struct sock *sk, struct sk_buff *skb, struct inet_diag_req_v2 *r, struct user_namespace *user_ns, u32 portid, u32 seq, u16 nlmsg_flags, - const struct nlmsghdr *unlh) + const struct nlmsghdr *unlh, bool net_admin) { if (sk->sk_state == TCP_TIME_WAIT) return inet_twsk_diag_fill(inet_twsk(sk), skb, r, portid, seq, nlmsg_flags, unlh); return inet_csk_diag_fill(sk, skb, r, user_ns, portid, seq, - nlmsg_flags, unlh); + nlmsg_flags, unlh, net_admin); } struct sock *inet_diag_find_one_icsk(struct net *net, @@ -368,7 +375,8 @@ int inet_diag_dump_one_icsk(struct inet_hashinfo *hashinfo, err = sk_diag_fill(sk, rep, req, sk_user_ns(NETLINK_CB(in_skb).sk), NETLINK_CB(in_skb).portid, - nlh->nlmsg_seq, 0, nlh); + nlh->nlmsg_seq, 0, nlh, + netlink_net_capable(in_skb, CAP_NET_ADMIN)); if (err < 0) { WARN_ON(err == -EMSGSIZE); nlmsg_free(rep); @@ -507,6 +515,22 @@ static int inet_diag_bc_run(const struct nlattr *_bc, yes = 0; break; } + case INET_DIAG_BC_DEV_COND: { + u32 ifindex; + + ifindex = *((const u32 *)(op + 1)); + if (ifindex != entry->ifindex) + yes = 0; + break; + } + case INET_DIAG_BC_MARK_COND: { + struct inet_diag_markcond *cond; + + cond = (struct inet_diag_markcond *)(op + 1); + if ((entry->mark & cond->mask) != cond->mark) + yes = 0; + break; + } } if (yes) { @@ -543,6 +567,8 @@ int inet_diag_bc_sk(const struct nlattr *bc, struct sock *sk) entry.sport = inet->inet_num; entry.dport = ntohs(inet->inet_dport); entry.userlocks = sk->sk_userlocks; + entry.ifindex = sk->sk_bound_dev_if; + entry.mark = sk->sk_mark; return inet_diag_bc_run(bc, &entry); } @@ -565,6 +591,17 @@ static int valid_cc(const void *bc, int len, int cc) return 0; } +/* data is u32 ifindex */ +static bool valid_devcond(const struct inet_diag_bc_op *op, int len, + int *min_len) +{ + /* Check ifindex space. */ + *min_len += sizeof(u32); + if (len < *min_len) + return false; + + return true; +} /* Validate an inet_diag_hostcond. */ static bool valid_hostcond(const struct inet_diag_bc_op *op, int len, int *min_len) @@ -614,10 +651,25 @@ static inline bool valid_port_comparison(const struct inet_diag_bc_op *op, return true; } -static int inet_diag_bc_audit(const void *bytecode, int bytecode_len) +static bool valid_markcond(const struct inet_diag_bc_op *op, int len, + int *min_len) +{ + *min_len += sizeof(struct inet_diag_markcond); + return len >= *min_len; +} + +static int inet_diag_bc_audit(const struct nlattr *attr, + const struct sk_buff *skb) { - const void *bc = bytecode; - int len = bytecode_len; + bool net_admin = netlink_net_capable(skb, CAP_NET_ADMIN); + const void *bytecode, *bc; + int bytecode_len, len; + + if (!attr || nla_len(attr) < sizeof(struct inet_diag_bc_op)) + return -EINVAL; + + bytecode = bc = nla_data(attr); + len = bytecode_len = nla_len(attr); while (len > 0) { const struct inet_diag_bc_op *op = bc; @@ -630,6 +682,10 @@ static int inet_diag_bc_audit(const void *bytecode, int bytecode_len) if (!valid_hostcond(bc, len, &min_len)) return -EINVAL; break; + case INET_DIAG_BC_DEV_COND: + if (!valid_devcond(bc, len, &min_len)) + return -EINVAL; + break; case INET_DIAG_BC_S_GE: case INET_DIAG_BC_S_LE: case INET_DIAG_BC_D_GE: @@ -637,6 +693,12 @@ static int inet_diag_bc_audit(const void *bytecode, int bytecode_len) if (!valid_port_comparison(bc, len, &min_len)) return -EINVAL; break; + case INET_DIAG_BC_MARK_COND: + if (!net_admin) + return -EPERM; + if (!valid_markcond(bc, len, &min_len)) + return -EINVAL; + break; case INET_DIAG_BC_AUTO: case INET_DIAG_BC_JMP: case INET_DIAG_BC_NOP: @@ -665,7 +727,8 @@ static int inet_csk_diag_dump(struct sock *sk, struct sk_buff *skb, struct netlink_callback *cb, struct inet_diag_req_v2 *r, - const struct nlattr *bc) + const struct nlattr *bc, + bool net_admin) { if (!inet_diag_bc_sk(bc, sk)) return 0; @@ -673,7 +736,8 @@ static int inet_csk_diag_dump(struct sock *sk, return inet_csk_diag_fill(sk, skb, r, sk_user_ns(NETLINK_CB(cb->skb).sk), NETLINK_CB(cb->skb).portid, - cb->nlh->nlmsg_seq, NLM_F_MULTI, cb->nlh); + cb->nlh->nlmsg_seq, NLM_F_MULTI, cb->nlh, + net_admin); } static int inet_twsk_diag_dump(struct sock *sk, @@ -701,6 +765,7 @@ static int inet_twsk_diag_dump(struct sock *sk, entry.sport = tw->tw_num; entry.dport = ntohs(tw->tw_dport); entry.userlocks = 0; + entry.mark = 0; if (!inet_diag_bc_run(bc, &entry)) return 0; @@ -827,6 +892,7 @@ static int inet_diag_dump_reqs(struct sk_buff *skb, struct sock *sk, if (bc != NULL) { entry.sport = inet->inet_num; entry.userlocks = sk->sk_userlocks; + entry.mark = sk->sk_mark; } for (j = s_j; j < lopt->nr_table_entries; j++) { @@ -876,6 +942,7 @@ void inet_diag_dump_icsk(struct inet_hashinfo *hashinfo, struct sk_buff *skb, int i, num; int s_i, s_num; struct net *net = sock_net(skb->sk); + bool net_admin = netlink_net_capable(cb->skb, CAP_NET_ADMIN); s_i = cb->args[1]; s_num = num = cb->args[2]; @@ -916,7 +983,8 @@ void inet_diag_dump_icsk(struct inet_hashinfo *hashinfo, struct sk_buff *skb, cb->args[3] > 0) goto syn_recv; - if (inet_csk_diag_dump(sk, skb, cb, r, bc) < 0) { + if (inet_csk_diag_dump(sk, skb, cb, r, + bc, net_admin) < 0) { spin_unlock_bh(&ilb->lock); goto done; } @@ -988,7 +1056,8 @@ skip_listen_ht: if (sk->sk_state == TCP_TIME_WAIT) res = inet_twsk_diag_dump(sk, skb, cb, r, bc); else - res = inet_csk_diag_dump(sk, skb, cb, r, bc); + res = inet_csk_diag_dump(sk, skb, cb, r, bc, + net_admin); if (res < 0) { spin_unlock_bh(lock); goto done; @@ -1093,13 +1162,13 @@ static int inet_diag_rcv_msg_compat(struct sk_buff *skb, struct nlmsghdr *nlh) if (nlh->nlmsg_flags & NLM_F_DUMP) { if (nlmsg_attrlen(nlh, hdrlen)) { struct nlattr *attr; + int err; attr = nlmsg_find_attr(nlh, hdrlen, INET_DIAG_REQ_BYTECODE); - if (attr == NULL || - nla_len(attr) < sizeof(struct inet_diag_bc_op) || - inet_diag_bc_audit(nla_data(attr), nla_len(attr))) - return -EINVAL; + err = inet_diag_bc_audit(attr, skb); + if (err) + return err; } { struct netlink_dump_control c = { @@ -1124,12 +1193,13 @@ static int inet_diag_handler_cmd(struct sk_buff *skb, struct nlmsghdr *h) h->nlmsg_flags & NLM_F_DUMP) { if (nlmsg_attrlen(h, hdrlen)) { struct nlattr *attr; + int err; + attr = nlmsg_find_attr(h, hdrlen, INET_DIAG_REQ_BYTECODE); - if (attr == NULL || - nla_len(attr) < sizeof(struct inet_diag_bc_op) || - inet_diag_bc_audit(nla_data(attr), nla_len(attr))) - return -EINVAL; + err = inet_diag_bc_audit(attr, skb); + if (err) + return err; } { struct netlink_dump_control c = { diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 44a7c83d1a36..c621c6fc6e80 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -2239,6 +2239,20 @@ unsigned int udp_poll(struct file *file, struct socket *sock, poll_table *wait) } EXPORT_SYMBOL(udp_poll); +int udp_abort(struct sock *sk, int err) +{ + lock_sock(sk); + + sk->sk_err = err; + sk->sk_error_report(sk); + udp_disconnect(sk, 0); + + release_sock(sk); + + return 0; +} +EXPORT_SYMBOL_GPL(udp_abort); + struct proto udp_prot = { .name = "UDP", .owner = THIS_MODULE, @@ -2270,6 +2284,7 @@ struct proto udp_prot = { .compat_getsockopt = compat_udp_getsockopt, #endif .clear_sk = sk_prot_clear_portaddr_nulls, + .diag_destroy = udp_abort, }; EXPORT_SYMBOL(udp_prot); diff --git a/net/ipv4/udp_diag.c b/net/ipv4/udp_diag.c index 4a000f1dd757..9f5d1419f628 100644 --- a/net/ipv4/udp_diag.c +++ b/net/ipv4/udp_diag.c @@ -19,7 +19,7 @@ static int sk_diag_dump(struct sock *sk, struct sk_buff *skb, struct netlink_callback *cb, struct inet_diag_req_v2 *req, - struct nlattr *bc) + struct nlattr *bc, bool net_admin) { if (!inet_diag_bc_sk(bc, sk)) return 0; @@ -27,7 +27,7 @@ static int sk_diag_dump(struct sock *sk, struct sk_buff *skb, return inet_sk_diag_fill(sk, NULL, skb, req, sk_user_ns(NETLINK_CB(cb->skb).sk), NETLINK_CB(cb->skb).portid, - cb->nlh->nlmsg_seq, NLM_F_MULTI, cb->nlh); + cb->nlh->nlmsg_seq, NLM_F_MULTI, cb->nlh, net_admin); } static int udp_dump_one(struct udp_table *tbl, struct sk_buff *in_skb, @@ -73,7 +73,8 @@ static int udp_dump_one(struct udp_table *tbl, struct sk_buff *in_skb, err = inet_sk_diag_fill(sk, NULL, rep, req, sk_user_ns(NETLINK_CB(in_skb).sk), NETLINK_CB(in_skb).portid, - nlh->nlmsg_seq, 0, nlh); + nlh->nlmsg_seq, 0, nlh, + netlink_net_capable(in_skb, CAP_NET_ADMIN)); if (err < 0) { WARN_ON(err == -EMSGSIZE); kfree_skb(rep); @@ -95,6 +96,7 @@ static void udp_dump(struct udp_table *table, struct sk_buff *skb, struct netlin { int num, s_num, slot, s_slot; struct net *net = sock_net(skb->sk); + bool net_admin = netlink_net_capable(cb->skb, CAP_NET_ADMIN); s_slot = cb->args[0]; num = s_num = cb->args[1]; @@ -129,7 +131,7 @@ static void udp_dump(struct udp_table *table, struct sk_buff *skb, struct netlin r->id.idiag_dport) goto next; - if (sk_diag_dump(sk, skb, cb, r, bc) < 0) { + if (sk_diag_dump(sk, skb, cb, r, bc, net_admin) < 0) { spin_unlock_bh(&hslot->lock); goto done; } @@ -162,11 +164,87 @@ static void udp_diag_get_info(struct sock *sk, struct inet_diag_msg *r, r->idiag_wqueue = sk_wmem_alloc_get(sk); } +#ifdef CONFIG_INET_DIAG_DESTROY +static int __udp_diag_destroy(struct sk_buff *in_skb, + struct inet_diag_req_v2 *req, + struct udp_table *tbl) +{ + struct net *net = sock_net(in_skb->sk); + struct sock *sk; + int err; + + rcu_read_lock(); + + if (req->sdiag_family == AF_INET) + sk = __udp4_lib_lookup(net, + req->id.idiag_dst[0], req->id.idiag_dport, + req->id.idiag_src[0], req->id.idiag_sport, + req->id.idiag_if, tbl); +#if IS_ENABLED(CONFIG_IPV6) + else if (req->sdiag_family == AF_INET6) { + if (ipv6_addr_v4mapped((struct in6_addr *)req->id.idiag_dst) && + ipv6_addr_v4mapped((struct in6_addr *)req->id.idiag_src)) + sk = __udp4_lib_lookup(net, + req->id.idiag_dst[3], req->id.idiag_dport, + req->id.idiag_src[3], req->id.idiag_sport, + req->id.idiag_if, tbl); + + else + sk = __udp6_lib_lookup(net, + (struct in6_addr *)req->id.idiag_dst, + req->id.idiag_dport, + (struct in6_addr *)req->id.idiag_src, + req->id.idiag_sport, + req->id.idiag_if, tbl); + } +#endif + else { + rcu_read_unlock(); + return -EINVAL; + } + + if (sk && !atomic_inc_not_zero(&sk->sk_refcnt)) + sk = NULL; + + rcu_read_unlock(); + + if (!sk) + return -ENOENT; + + if (sock_diag_check_cookie(sk, req->id.idiag_cookie)) { + sock_put(sk); + return -ENOENT; + } + + err = sock_diag_destroy(sk, ECONNABORTED); + + sock_put(sk); + + return err; +} + +static int udp_diag_destroy(struct sk_buff *in_skb, + struct inet_diag_req_v2 *req) +{ + return __udp_diag_destroy(in_skb, req, &udp_table); +} + +static int udplite_diag_destroy(struct sk_buff *in_skb, + struct inet_diag_req_v2 *req) +{ + return __udp_diag_destroy(in_skb, req, &udplite_table); +} + +#endif + static const struct inet_diag_handler udp_diag_handler = { .dump = udp_diag_dump, .dump_one = udp_diag_dump_one, .idiag_get_info = udp_diag_get_info, .idiag_type = IPPROTO_UDP, +#ifdef CONFIG_INET_DIAG_DESTROY + .destroy = udp_diag_destroy, +#endif }; static void udplite_diag_dump(struct sk_buff *skb, struct netlink_callback *cb, @@ -186,6 +264,9 @@ static const struct inet_diag_handler udplite_diag_handler = { .dump_one = udplite_diag_dump_one, .idiag_get_info = udp_diag_get_info, .idiag_type = IPPROTO_UDPLITE, +#ifdef CONFIG_INET_DIAG_DESTROY + .destroy = udplite_diag_destroy, +#endif }; static int __init udp_diag_init(void) diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index 070d591332c3..1415f1327dd6 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c @@ -97,7 +97,7 @@ static void icmpv6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, if (!(type & ICMPV6_INFOMSG_MASK)) if (icmp6->icmp6_type == ICMPV6_ECHO_REQUEST) - ping_err(skb, offset, info); + ping_err(skb, offset, ntohl(info)); } static int icmpv6_rcv(struct sk_buff *skb); diff --git a/net/ipv6/ping.c b/net/ipv6/ping.c index 75aa8c1c403b..51f5bce11761 100644 --- a/net/ipv6/ping.c +++ b/net/ipv6/ping.c @@ -85,7 +85,7 @@ int ping_v6_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, struct icmp6hdr user_icmph; int addr_type; struct in6_addr *daddr; - int iif = 0; + int oif = 0; struct flowi6 fl6; int err; int hlimit; @@ -107,25 +107,30 @@ int ping_v6_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, if (u->sin6_family != AF_INET6) { return -EAFNOSUPPORT; } - if (sk->sk_bound_dev_if && - sk->sk_bound_dev_if != u->sin6_scope_id) { - return -EINVAL; - } daddr = &(u->sin6_addr); - iif = u->sin6_scope_id; + if (__ipv6_addr_needs_scope_id(ipv6_addr_type(daddr))) + oif = u->sin6_scope_id; } else { if (sk->sk_state != TCP_ESTABLISHED) return -EDESTADDRREQ; daddr = &sk->sk_v6_daddr; } - if (!iif) - iif = sk->sk_bound_dev_if; + if (!oif) + oif = sk->sk_bound_dev_if; + + if (!oif) + oif = np->sticky_pktinfo.ipi6_ifindex; + + if (!oif && ipv6_addr_is_multicast(daddr)) + oif = np->mcast_oif; + else if (!oif) + oif = np->ucast_oif; addr_type = ipv6_addr_type(daddr); - if (__ipv6_addr_needs_scope_id(addr_type) && !iif) - return -EINVAL; - if (addr_type & IPV6_ADDR_MAPPED) + if ((__ipv6_addr_needs_scope_id(addr_type) && !oif) || + (addr_type & IPV6_ADDR_MAPPED) || + (oif && sk->sk_bound_dev_if && oif != sk->sk_bound_dev_if)) return -EINVAL; /* TODO: use ip6_datagram_send_ctl to get options from cmsg */ @@ -135,17 +140,13 @@ int ping_v6_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, fl6.flowi6_proto = IPPROTO_ICMPV6; fl6.saddr = np->saddr; fl6.daddr = *daddr; + fl6.flowi6_oif = oif; fl6.flowi6_mark = sk->sk_mark; fl6.flowi6_uid = sock_i_uid(sk); fl6.fl6_icmp_type = user_icmph.icmp6_type; fl6.fl6_icmp_code = user_icmph.icmp6_code; security_sk_classify_flow(sk, flowi6_to_flowi(&fl6)); - if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr)) - fl6.flowi6_oif = np->mcast_oif; - else if (!fl6.flowi6_oif) - fl6.flowi6_oif = np->ucast_oif; - dst = ip6_sk_dst_lookup_flow(sk, &fl6, daddr); if (IS_ERR(dst)) return PTR_ERR(dst); @@ -155,11 +156,6 @@ int ping_v6_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, if (!np) return -EBADF; - if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr)) - fl6.flowi6_oif = np->mcast_oif; - else if (!fl6.flowi6_oif) - fl6.flowi6_oif = np->ucast_oif; - pfh.icmph.type = user_icmph.icmp6_type; pfh.icmph.code = user_icmph.icmp6_code; pfh.icmph.checksum = 0; diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 978641648951..e4a05fa60130 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -1507,6 +1507,7 @@ struct proto udpv6_prot = { .compat_getsockopt = compat_udpv6_getsockopt, #endif .clear_sk = udp_v6_clear_sk, + .diag_destroy = udp_abort, }; static struct inet_protosw udpv6_protosw = { diff --git a/scripts/gcc-wrapper.py b/scripts/gcc-wrapper.py deleted file mode 100755 index bb0ecb977165..000000000000 --- a/scripts/gcc-wrapper.py +++ /dev/null @@ -1,102 +0,0 @@ -#! /usr/bin/env python2 -# -*- coding: utf-8 -*- - -# Copyright (c) 2011-2015, The Linux Foundation. All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# * Neither the name of The Linux Foundation nor -# the names of its contributors may be used to endorse or promote -# products derived from this software without specific prior written -# permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; -# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -# Invoke gcc, looking for warnings, and causing a failure if there are -# non-whitelisted warnings. - -import errno -import re -import os -import sys -import subprocess - -# Note that gcc uses unicode, which may depend on the locale. TODO: -# force LANG to be set to en_US.UTF-8 to get consistent warnings. - -allowed_warnings = set([ - "fdt.c:932", - "hid-magicmouse.c:579", - "sysrq.c:956", - "hci_sock.c:980", - "pppopns.c:296", - "pppopns.c:305", - "pppopns.c:336", - ]) - -# Capture the name of the object file, can find it. -ofile = None - -warning_re = re.compile(r'''(.*/|)([^/]+\.[a-z]+:\d+):(\d+:)? warning:''') -def interpret_warning(line): - """Decode the message from gcc. The messages we care about have a filename, and a warning""" - line = line.rstrip('\n') - m = warning_re.match(line) - if m and m.group(2) not in allowed_warnings: - print "error, forbidden warning:", m.group(2) - - # If there is a warning, remove any object if it exists. - if ofile: - try: - os.remove(ofile) - except OSError: - pass - sys.exit(1) - -def run_gcc(): - args = sys.argv[1:] - # Look for -o - try: - i = args.index('-o') - global ofile - ofile = args[i+1] - except (ValueError, IndexError): - pass - - compiler = sys.argv[0] - - try: - proc = subprocess.Popen(args, stderr=subprocess.PIPE) - for line in proc.stderr: - print line, - interpret_warning(line) - - result = proc.wait() - except OSError as e: - result = e.errno - if result == errno.ENOENT: - print args[0] + ':',e.strerror - print 'Is your PATH set correctly?' - else: - print ' '.join(args), str(e) - - return result - -if __name__ == '__main__': - status = run_gcc() - sys.exit(status) diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c index 926ae130e92d..aa32fd1127fc 100755 --- a/sound/soc/codecs/wcd9335.c +++ b/sound/soc/codecs/wcd9335.c @@ -4372,9 +4372,11 @@ static int tasha_codec_hphl_dac_event(struct snd_soc_dapm_widget *w, if (!ret) { wcd_clsh_imped_config(codec, impedl, false); set_bit(CLASSH_CONFIG, &tasha->status_mask); - } else + } else { dev_dbg(codec->dev, "%s: Failed to get mbhc impedance %d\n", __func__, ret); + ret = 0; + } break; diff --git a/sound/soc/msm/msm-cpe-lsm.c b/sound/soc/msm/msm-cpe-lsm.c index 8588a4bcb4be..5c21e2e30244 100644 --- a/sound/soc/msm/msm-cpe-lsm.c +++ b/sound/soc/msm/msm-cpe-lsm.c @@ -980,8 +980,7 @@ static int msm_cpe_lsm_get_conf_levels( goto done; } - session->conf_levels = kzalloc(session->num_confidence_levels, - GFP_KERNEL); + session->conf_levels = vzalloc(session->num_confidence_levels); if (!session->conf_levels) { pr_err("%s: No memory for confidence levels %u\n", __func__, session->num_confidence_levels); @@ -994,7 +993,7 @@ static int msm_cpe_lsm_get_conf_levels( session->num_confidence_levels)) { pr_err("%s: copy_from_user failed for confidence levels %u\n", __func__, session->num_confidence_levels); - kfree(session->conf_levels); + vfree(session->conf_levels); session->conf_levels = NULL; rc = -EFAULT; goto done; @@ -1237,12 +1236,12 @@ static int msm_cpe_lsm_ioctl_shared(struct snd_pcm_substream *substream, break; } - session->snd_model_data = kzalloc(snd_model.data_size, - GFP_KERNEL); + session->snd_model_data = vzalloc(snd_model.data_size); if (!session->snd_model_data) { dev_err(rtd->dev, "%s: No memory for sound model\n", __func__); - kfree(session->conf_levels); + vfree(session->conf_levels); + session->conf_levels = NULL; return -ENOMEM; } session->snd_model_size = snd_model.data_size; @@ -1252,8 +1251,10 @@ static int msm_cpe_lsm_ioctl_shared(struct snd_pcm_substream *substream, dev_err(rtd->dev, "%s: copy_from_user failed for snd_model\n", __func__); - kfree(session->conf_levels); - kfree(session->snd_model_data); + vfree(session->conf_levels); + session->conf_levels = NULL; + vfree(session->snd_model_data); + session->snd_model_data = NULL; return -EFAULT; } @@ -1263,8 +1264,10 @@ static int msm_cpe_lsm_ioctl_shared(struct snd_pcm_substream *substream, dev_err(rtd->dev, "%s: shared memory allocation failed, err = %d\n", __func__, rc); - kfree(session->snd_model_data); - kfree(session->conf_levels); + vfree(session->conf_levels); + session->conf_levels = NULL; + vfree(session->snd_model_data); + session->snd_model_data = NULL; return rc; } @@ -1276,8 +1279,10 @@ static int msm_cpe_lsm_ioctl_shared(struct snd_pcm_substream *substream, "%s: snd_model_reg failed, err = %d\n", __func__, rc); lsm_ops->lsm_shmem_dealloc(cpe->core_handle, session); - kfree(session->snd_model_data); - kfree(session->conf_levels); + vfree(session->conf_levels); + session->conf_levels = NULL; + vfree(session->snd_model_data); + session->snd_model_data = NULL; return rc; } @@ -1337,10 +1342,10 @@ static int msm_cpe_lsm_ioctl_shared(struct snd_pcm_substream *substream, return rc; } - kfree(session->snd_model_data); - kfree(session->conf_levels); - session->snd_model_data = NULL; + vfree(session->conf_levels); session->conf_levels = NULL; + vfree(session->snd_model_data); + session->snd_model_data = NULL; rc = lsm_ops->lsm_shmem_dealloc(cpe->core_handle, session); if (rc != 0) { @@ -1496,16 +1501,16 @@ static int msm_cpe_lsm_ioctl_shared(struct snd_pcm_substream *substream, rc = lsm_ops->lsm_set_data(cpe->core_handle, session, det_params.detect_mode, det_params.detect_failure); + + vfree(session->conf_levels); + session->conf_levels = NULL; + if (rc) { dev_err(rtd->dev, "%s: lsm_set_data failed, err = %d\n", __func__, rc); return rc; } - - kfree(session->conf_levels); - session->conf_levels = NULL; - break; case SNDRV_LSM_OUT_FORMAT_CFG: { diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-noirq.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-noirq.c index 7d433a1c5438..05c5e1e8a50a 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-noirq.c +++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-noirq.c @@ -390,6 +390,30 @@ static int msm_pcm_trigger(struct snd_pcm_substream *substream, int cmd) return ret; } +static int msm_pcm_ioctl(struct snd_pcm_substream *substream, + unsigned int cmd, void *arg) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct msm_audio *prtd = runtime->private_data; + int dir = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? 0 : 1; + struct audio_buffer *buf; + + switch (cmd) { + case SNDRV_PCM_IOCTL1_RESET: + pr_debug("%s: %s SNDRV_PCM_IOCTL1_RESET\n", __func__, + dir == 0 ? "P" : "C"); + buf = q6asm_shared_io_buf(prtd->audio_client, dir); + + if (buf && buf->data) + memset(buf->data, 0, buf->actual_size); + break; + default: + break; + } + + return snd_pcm_lib_ioctl(substream, cmd, arg); +} + static snd_pcm_uframes_t msm_pcm_pointer(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; @@ -723,7 +747,7 @@ static struct snd_pcm_ops msm_pcm_ops = { .prepare = msm_pcm_prepare, .copy = msm_pcm_copy, .hw_params = msm_pcm_hw_params, - .ioctl = snd_pcm_lib_ioctl, + .ioctl = msm_pcm_ioctl, .trigger = msm_pcm_trigger, .pointer = msm_pcm_pointer, .mmap = msm_pcm_mmap, diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c index bc73018fcee6..3c117e755164 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c @@ -148,6 +148,13 @@ static void event_handler(uint32_t opcode, case ASM_DATA_EVENT_WRITE_DONE_V2: { pr_debug("ASM_DATA_EVENT_WRITE_DONE_V2\n"); pr_debug("Buffer Consumed = 0x%08x\n", *ptrmem); + + if (payload[3]) { + pr_err("%s WRITE FAILED w/ err 0x%x\n", + __func__, + payload[3]); + } + prtd->pcm_irq_pos += prtd->pcm_count; if (atomic_read(&prtd->start)) snd_pcm_period_elapsed(substream); diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c index 77433384a139..97c914ac35a4 100755 --- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c @@ -2270,6 +2270,7 @@ static int msm_routing_ec_ref_rx_put(struct snd_kcontrol *kcontrol, int mux = ucontrol->value.enumerated.item[0]; struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; struct snd_soc_dapm_update *update = NULL; + int valid_port = true; mutex_lock(&routing_lock); switch (ucontrol->value.integer.value[0]) { @@ -2345,7 +2346,12 @@ static int msm_routing_ec_ref_rx_put(struct snd_kcontrol *kcontrol, msm_route_ec_ref_rx = 18; ec_ref_port_id = AFE_PORT_ID_TERTIARY_TDM_TX; break; + case 19: + msm_route_ec_ref_rx = 19; + ec_ref_port_id = AFE_PORT_ID_PRIMARY_PCM_RX; + break; default: + valid_port = false; msm_route_ec_ref_rx = 0; /* NONE */ pr_err("%s EC ref rx %ld not valid\n", __func__, ucontrol->value.integer.value[0]); @@ -2356,7 +2362,10 @@ static int msm_routing_ec_ref_rx_put(struct snd_kcontrol *kcontrol, pr_debug("%s: msm_route_ec_ref_rx = %d\n", __func__, msm_route_ec_ref_rx); mutex_unlock(&routing_lock); - snd_soc_dapm_mux_update_power(widget->dapm, kcontrol, mux, e, update); + + if (valid_port) + snd_soc_dapm_mux_update_power(widget->dapm, kcontrol, mux, e, update); + return 0; } @@ -2365,7 +2374,7 @@ static const char *const ec_ref_rx[] = { "None", "SLIM_RX", "I2S_RX", "TERT_MI2S_TX", "QUAT_MI2S_TX", "SEC_I2S_RX", "PROXY_RX", "SLIM_5_RX", "SLIM_1_TX", "QUAT_TDM_TX_1", "QUAT_TDM_RX_0", "QUAT_TDM_RX_1", "QUAT_TDM_RX_2", "SLIM_6_RX", - "TERT_MI2S_RX", "QUAT_MI2S_RX", "TERT_TDM_TX_0"}; + "TERT_MI2S_RX", "QUAT_MI2S_RX", "TERT_TDM_TX_0", "AUX_PCM_RX"}; static const struct soc_enum msm_route_ec_ref_rx_enum[] = { SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(ec_ref_rx), ec_ref_rx), diff --git a/verity_rdev_keys.der.x509 b/verity_rdev_keys.der.x509 Binary files differnew file mode 100644 index 000000000000..7848032f2974 --- /dev/null +++ b/verity_rdev_keys.der.x509 |