aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinux Build Service Account <lnxbuild@localhost>2019-02-17 10:16:56 -0800
committerLinux Build Service Account <lnxbuild@localhost>2019-02-17 10:16:56 -0800
commite2f180b56585f70bc9521bd89900a89ae8ef53f6 (patch)
tree3f1843dd05260bd3c3eab9308978bdfc0e37052a
parent9753c747140da1ffbc114cf38fb7e4a0438345a4 (diff)
parente4c9b6f1af3b6dbbc6e01a00a4e9fbc7cdebd3a2 (diff)
Merge e4c9b6f1af3b6dbbc6e01a00a4e9fbc7cdebd3a2 on remote branchLA.UM.7.8.r1-04800-SDM710.0
Change-Id: I3159c8dc8c0e4fdf4fce8c85c38e261cb9737b24
-rw-r--r--Documentation/devicetree/bindings/arm/msm/clock-controller.txt1
-rw-r--r--Documentation/devicetree/bindings/media/video/msm-camera-flash.txt18
-rw-r--r--Documentation/devicetree/bindings/power/supply/qcom/qpnp-qg.txt5
-rw-r--r--arch/arm/configs/msm8909w-perf_defconfig1
-rw-r--r--arch/arm64/boot/dts/qcom/Makefile6
-rw-r--r--arch/arm64/boot/dts/qcom/pm8916.dtsi3
-rw-r--r--arch/arm64/boot/dts/qcom/qm215-camera-sensor-qrd.dtsi18
-rw-r--r--arch/arm64/boot/dts/qcom/qm215-pm8916.dtsi98
-rw-r--r--arch/arm64/boot/dts/qcom/qm215-qrd-smb1360-overlay.dts22
-rw-r--r--arch/arm64/boot/dts/qcom/qm215-qrd-smb1360.dts24
-rw-r--r--arch/arm64/boot/dts/qcom/qm215-qrd-smb1360.dtsi66
-rw-r--r--arch/arm64/boot/dts/qcom/qm215.dtsi16
-rw-r--r--arch/arm64/configs/msm8937-perf_defconfig1
-rw-r--r--arch/arm64/kernel/perf_event.c4
-rw-r--r--drivers/char/diag/diag_dci.c32
-rw-r--r--drivers/char/diag/diag_dci.h3
-rw-r--r--drivers/char/diag/diag_masks.c1
-rw-r--r--drivers/char/diag/diagchar.h5
-rw-r--r--drivers/clk/msm/clock-gcc-8952.c42
-rw-r--r--drivers/iommu/dma-mapping-fast.c14
-rw-r--r--drivers/iommu/iommu-debug.c24
-rw-r--r--drivers/leds/leds-qpnp-vibrator.c11
-rw-r--r--drivers/media/platform/msm/camera_v2/sensor/flash/Makefile1
-rw-r--r--drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c14
-rw-r--r--drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.h6
-rw-r--r--drivers/media/platform/msm/camera_v2/sensor/flash/qm215_gpio_flash.c264
-rw-r--r--drivers/media/platform/msm/camera_v3/cam_cdm/cam_cdm_virtual_core.c10
-rw-r--r--drivers/media/platform/msm/camera_v3/cam_core/cam_context.c5
-rw-r--r--drivers/media/platform/msm/camera_v3/cam_core/cam_context_utils.c18
-rw-r--r--drivers/media/platform/msm/camera_v3/cam_core/cam_hw_mgr_intf.h4
-rw-r--r--drivers/media/platform/msm/camera_v3/cam_cpas/cam_cpas_hw.c18
-rw-r--r--drivers/media/platform/msm/camera_v3/cam_cpas/cam_cpas_hw.h4
-rw-r--r--drivers/media/platform/msm/camera_v3/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c32
-rw-r--r--drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/bps_hw/bps_core.c9
-rw-r--r--drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c5
-rw-r--r--drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/ipe_hw/ipe_core.c8
-rw-r--r--drivers/media/platform/msm/camera_v3/cam_isp/cam_isp_context.c547
-rw-r--r--drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c46
-rw-r--r--drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h7
-rw-r--r--drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c17
-rw-r--r--drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h16
-rw-r--r--drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid170.h3
-rw-r--r--drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c97
-rw-r--r--drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h3
-rw-r--r--drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.c91
-rw-r--r--drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.h12
-rw-r--r--drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c152
-rw-r--r--drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c182
-rw-r--r--drivers/media/platform/msm/camera_v3/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c10
-rw-r--r--drivers/media/platform/msm/camera_v3/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c15
-rw-r--r--drivers/media/platform/msm/camera_v3/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c7
-rw-r--r--drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_req_mgr_core.h4
-rw-r--r--drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_actuator/cam_actuator_core.c53
-rw-r--r--drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_actuator/cam_actuator_dev.c35
-rw-r--r--drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_csiphy/cam_csiphy_core.c40
-rw-r--r--drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c11
-rw-r--r--drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_eeprom/cam_eeprom_core.c84
-rw-r--r--drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_eeprom/cam_eeprom_dev.c28
-rw-r--r--drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_flash/cam_flash_core.c216
-rw-r--r--drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_flash/cam_flash_dev.c14
-rw-r--r--drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_flash/cam_flash_dev.h4
-rw-r--r--drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_ois/cam_ois_core.c47
-rw-r--r--drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_ois/cam_ois_core.h4
-rw-r--r--drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_ois/cam_ois_dev.c28
-rw-r--r--drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_sensor/cam_sensor_core.c82
-rw-r--r--drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_sensor/cam_sensor_dev.c19
-rw-r--r--drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c142
-rw-r--r--drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_sensor_utils/cam_sensor_util.h5
-rw-r--r--drivers/media/platform/msm/camera_v3/cam_utils/cam_packet_util.c95
-rw-r--r--drivers/media/platform/msm/camera_v3/cam_utils/cam_packet_util.h7
-rw-r--r--drivers/media/platform/msm/vidc/hfi_response_handler.c12
-rw-r--r--drivers/media/platform/msm/vidc/venus_hfi.c68
-rw-r--r--drivers/media/platform/msm/vidc/vidc_hfi_api.h5
-rw-r--r--drivers/media/platform/msm/vidc_3x/hfi_response_handler.c12
-rw-r--r--drivers/media/platform/msm/vidc_3x/msm_vidc_common.c4
-rw-r--r--drivers/media/platform/msm/vidc_3x/venus_hfi.c67
-rw-r--r--drivers/media/platform/msm/vidc_3x/vidc_hfi_api.h5
-rw-r--r--drivers/misc/qseecom.c321
-rw-r--r--drivers/mmc/card/block.c17
-rw-r--r--drivers/perf/arm_pmu.c14
-rw-r--r--drivers/platform/msm/ipa/ipa_v2/ipa_intf.c21
-rw-r--r--drivers/power/supply/power_supply_sysfs.c1
-rw-r--r--drivers/power/supply/qcom/fg-alg.c21
-rw-r--r--drivers/power/supply/qcom/qg-core.h2
-rw-r--r--drivers/power/supply/qcom/qg-reg.h1
-rw-r--r--drivers/power/supply/qcom/qg-util.c5
-rw-r--r--drivers/power/supply/qcom/qpnp-qg.c62
-rw-r--r--drivers/scsi/ufs/ufshcd.c61
-rw-r--r--drivers/soc/qcom/glink_smem_native_xprt.c6
-rw-r--r--drivers/soc/qcom/glink_spi_xprt.c33
-rw-r--r--drivers/soc/qcom/icnss.c5
-rw-r--r--drivers/usb/pd/policy_engine.c2
-rw-r--r--drivers/video/fbdev/msm/mdp3_ctrl.c10
-rw-r--r--drivers/video/fbdev/msm/mdss_fb.c6
-rw-r--r--fs/proc/inode.c9
-rw-r--r--fs/proc/internal.h3
-rw-r--r--fs/proc/root.c52
-rw-r--r--include/dt-bindings/clock/msm-clocks-hwio-8952.h5
-rw-r--r--include/linux/perf_event.h14
-rw-r--r--include/linux/power_supply.h1
-rw-r--r--include/uapi/linux/qg.h3
-rw-r--r--include/uapi/media/cam_req_mgr.h2
-rw-r--r--kernel/cpu.c2
-rw-r--r--kernel/events/core.c207
-rw-r--r--mm/memory.c10
-rwxr-xr-xscripts/checkpatch.pl2
106 files changed, 3128 insertions, 879 deletions
diff --git a/Documentation/devicetree/bindings/arm/msm/clock-controller.txt b/Documentation/devicetree/bindings/arm/msm/clock-controller.txt
index 75f901bcde9c..fd53d9f1e127 100644
--- a/Documentation/devicetree/bindings/arm/msm/clock-controller.txt
+++ b/Documentation/devicetree/bindings/arm/msm/clock-controller.txt
@@ -30,6 +30,7 @@ Required properties:
"qcom,gcc-8917"
"qcom,gcc-8940"
"qcom,gcc-8920"
+ "qcom,gcc-qm215"
"qcom,gcc-spm-8952"
"qcom,gcc-spm-8937"
"qcom,rpmcc-8909"
diff --git a/Documentation/devicetree/bindings/media/video/msm-camera-flash.txt b/Documentation/devicetree/bindings/media/video/msm-camera-flash.txt
index d24314ae196d..970dae26dc57 100644
--- a/Documentation/devicetree/bindings/media/video/msm-camera-flash.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-camera-flash.txt
@@ -124,3 +124,21 @@ led_flash_rear: qcom,camera-flash@0 {
qcom,max-current = <1500>;
qcom,max-duration = <1200>;
};
+
+
+Example:
+
+flash0: qcom,camera-flash {
+ cell-index = <0>;
+ compatible = "qcom,qm215-gpio-flash";
+ qcom,flash-type = <2>;
+ gpios = <&tlmm 34 0>;
+ <&tlmm 33 0>;
+ qcom,gpio-req-tbl-num = <0 1>;
+ qcom,gpio-req-tbl-flags = <1 0>;
+ qcom,gpio-flash-en = <0>;
+ qcom,gpio-flash-now = <1>;
+ qcom,gpio-req-tbl-label = "CAM_FLASH",
+ "CAM_TORCH";
+ status = "ok";
+ };
diff --git a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-qg.txt b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-qg.txt
index 1e49e9642443..d8e459bc3769 100644
--- a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-qg.txt
+++ b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-qg.txt
@@ -308,6 +308,11 @@ First Level Node - QGAUGE device
Definition: Boolean property to support external-rsense based
configuration.
+- qcom,qg-vbms-mode
+ Usage: optional
+ Value type: <bool>
+ Definition: Boolean property to run QG in Voltage-only mode of QG.
+
- qcom,shutdown-temp-diff
Usage: optional
Value type: <u32>
diff --git a/arch/arm/configs/msm8909w-perf_defconfig b/arch/arm/configs/msm8909w-perf_defconfig
index 084e48707f58..8a5099dc084a 100644
--- a/arch/arm/configs/msm8909w-perf_defconfig
+++ b/arch/arm/configs/msm8909w-perf_defconfig
@@ -329,7 +329,6 @@ CONFIG_FB_MSM_MDSS=y
CONFIG_FB_MSM_MDSS_WRITEBACK=y
CONFIG_FB_MSM_MDSS_SPI_PANEL=y
CONFIG_FB_MSM_MDSS_MDP3=y
-CONFIG_FB_MSM_MDSS_XLOG_DEBUG=y
CONFIG_BACKLIGHT_LCD_SUPPORT=y
CONFIG_BACKLIGHT_CLASS_DEVICE=y
CONFIG_SOUND=y
diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile
index c4a509e6372e..9b305fd30300 100644
--- a/arch/arm64/boot/dts/qcom/Makefile
+++ b/arch/arm64/boot/dts/qcom/Makefile
@@ -349,6 +349,7 @@ dtbo-$(CONFIG_ARCH_MSM8917) += msm8917-mtp-overlay.dtbo \
apq8017-cdp-wcd-rome-overlay.dtbo
dtbo-$(CONFIG_ARCH_QM215) +=qm215-qrd-overlay.dtbo
+dtbo-$(CONFIG_ARCH_QM215) +=qm215-qrd-smb1360-overlay.dtbo
dtbo-$(CONFIG_ARCH_MSM8953) += msm8953-mtp-overlay.dtbo \
msm8953-cdp-overlay.dtbo \
@@ -425,6 +426,7 @@ apq8017-cdp-wcd-rome-overlay.dtbo-base := apq8017-pmi8950.dtb \
apq8017-pmi8937.dtb
qm215-qrd-overlay.dtbo-base := qm215.dtb
+qm215-qrd-smb1360-overlay.dtbo-base := qm215.dtb
msm8953-mtp-overlay.dtbo-base := sdm450.dtb \
msm8953.dtb \
@@ -563,6 +565,7 @@ dtb-$(CONFIG_ARCH_MSM8917) += msm8917-pmi8950-mtp.dtb \
msm8917-pmi8940-rcm.dtb
dtb-$(CONFIG_ARCH_QM215) += qm215-qrd.dtb
+dtb-$(CONFIG_ARCH_QM215) += qm215-qrd-smb1360.dtb
dtb-$(CONFIG_ARCH_MSM8909) += sdw3100-msm8909w-wtp.dtb \
sdw3100-apq8009w-wtp.dtb \
@@ -616,7 +619,8 @@ dtb-$(CONFIG_ARCH_SDM439) += sdm439-mtp.dtb \
sda439-cdp.dtb \
sdm439-external-codec-mtp.dtb \
sdm439-rcm.dtb \
- qm215-qrd.dtb
+ qm215-qrd.dtb \
+ qm215-qrd-smb1360.dtb
dtb-$(CONFIG_ARCH_SDM429) += sdm429-mtp.dtb \
sdm429-cdp.dtb \
diff --git a/arch/arm64/boot/dts/qcom/pm8916.dtsi b/arch/arm64/boot/dts/qcom/pm8916.dtsi
index 45516be974c3..7c925d0d4464 100644
--- a/arch/arm64/boot/dts/qcom/pm8916.dtsi
+++ b/arch/arm64/boot/dts/qcom/pm8916.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2014, 2016-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014, 2016-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -180,6 +180,7 @@
compatible = "qcom,qpnp-linear-charger";
#address-cells = <1>;
#size-cells = <1>;
+ #cooling-cells = <2>;
qcom,vddmax-mv = <4200>;
qcom,vddsafe-mv = <4200>;
diff --git a/arch/arm64/boot/dts/qcom/qm215-camera-sensor-qrd.dtsi b/arch/arm64/boot/dts/qcom/qm215-camera-sensor-qrd.dtsi
index f7c6814a0333..ab5557216974 100644
--- a/arch/arm64/boot/dts/qcom/qm215-camera-sensor-qrd.dtsi
+++ b/arch/arm64/boot/dts/qcom/qm215-camera-sensor-qrd.dtsi
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -97,6 +97,21 @@
qcom,clock-rates = <19200000 0>;
};
+ flash0: qcom,camera-flash {
+ cell-index = <0>;
+ compatible = "qcom,qm215-gpio-flash";
+ qcom,flash-type = <2>;
+ gpios = <&tlmm 34 0>,
+ <&tlmm 33 0>;
+ qcom,gpio-req-tbl-num = <0 1>;
+ qcom,gpio-req-tbl-flags = <1 0>;
+ qcom,gpio-flash-en = <0>;
+ qcom,gpio-flash-now = <1>;
+ qcom,gpio-req-tbl-label = "CAM_FLASH",
+ "CAM_TORCH";
+ status = "ok";
+ };
+
qcom,camera@0 {
cell-index = <0>;
compatible = "qcom,camera";
@@ -104,6 +119,7 @@
qcom,csiphy-sd-index = <0>;
qcom,csid-sd-index = <0>;
qcom,mount-angle = <90>;
+ qcom,led-flash-src = <&flash0>;
qcom,actuator-src = <&actuator0>;
qcom,eeprom-src = <&eeprom0>;
cam_vana-supply = <&pm8916_l16>;
diff --git a/arch/arm64/boot/dts/qcom/qm215-pm8916.dtsi b/arch/arm64/boot/dts/qcom/qm215-pm8916.dtsi
index 6b08005014ee..7cce2d7b3d2b 100644
--- a/arch/arm64/boot/dts/qcom/qm215-pm8916.dtsi
+++ b/arch/arm64/boot/dts/qcom/qm215-pm8916.dtsi
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -476,6 +476,102 @@
};
};
};
+
+ xo-therm-step {
+ polling-delay-passive = <1000>;
+ polling-delay = <5000>;
+ thermal-sensors = <&pm8916_vadc 0x32>;
+ thermal-governor = "step_wise";
+
+ trips {
+ qm215_batt_trip0: qm215-batt-trip0 {
+ temperature = <41000>;
+ hysteresis = <2000>;
+ type = "passive";
+ };
+ qm215_modem_trip0: qm215-modem-trip0 {
+ temperature = <44000>;
+ hysteresis = <4000>;
+ type = "passive";
+ };
+ qm215_batt_trip1: qm215-batt-trip1 {
+ temperature = <45000>;
+ hysteresis = <4000>;
+ type = "passive";
+ };
+ qm215_modem_trip1: qm215-modem-trip1 {
+ temperature = <46000>;
+ hysteresis = <2000>;
+ type = "passive";
+ };
+ qm215_cpu_trip: qm215-cpu-trip {
+ temperature = <48000>;
+ hysteresis = <0>;
+ type = "passive";
+ };
+ qm215_gpu_trip: qm215-gpu-trip {
+ temperature = <50000>;
+ hysteresis = <0>;
+ type = "passive";
+ };
+ qm215_modem_trip2: qm215-modem-trip2 {
+ temperature = <60000>;
+ hysteresis = <5000>;
+ type = "passive";
+ };
+ };
+
+ cooling-maps {
+ skin_cpu0 {
+ trip = <&qm215_cpu_trip>;
+ /* throttle from fmax to 1094400KHz */
+ cooling-device = <&CPU0 THERMAL_NO_LIMIT
+ (THERMAL_MAX_LIMIT-2)>;
+ };
+ skin_cpu1 {
+ trip = <&qm215_cpu_trip>;
+ cooling-device = <&CPU1 THERMAL_NO_LIMIT
+ (THERMAL_MAX_LIMIT-2)>;
+ };
+ skin_cpu2 {
+ trip = <&qm215_cpu_trip>;
+ cooling-device = <&CPU2 THERMAL_NO_LIMIT
+ (THERMAL_MAX_LIMIT-2)>;
+ };
+ skin_cpu3 {
+ trip = <&qm215_cpu_trip>;
+ cooling-device = <&CPU3 THERMAL_NO_LIMIT
+ (THERMAL_MAX_LIMIT-2)>;
+ };
+ skin_gpu {
+ trip = <&qm215_gpu_trip>;
+ /* throttle from fmax to 400000000Hz */
+ cooling-device = <&msm_gpu
+ THERMAL_NO_LIMIT
+ (THERMAL_MAX_LIMIT-1)>;
+ };
+ modem_lvl1 {
+ trip = <&qm215_modem_trip0>;
+ cooling-device = <&modem_pa 1 1>;
+ };
+ modem_lvl2 {
+ trip = <&qm215_modem_trip1>;
+ cooling-device = <&modem_pa 2 2>;
+ };
+ modem_lvl3 {
+ trip = <&qm215_modem_trip2>;
+ cooling-device = <&modem_pa 3 3>;
+ };
+ battery_lvl1 {
+ trip = <&qm215_batt_trip0>;
+ cooling-device = <&pm8916_chg 1 1>;
+ };
+ battery_lvl2 {
+ trip = <&qm215_batt_trip1>;
+ cooling-device = <&pm8916_chg 2 2>;
+ };
+ };
+ };
};
};
diff --git a/arch/arm64/boot/dts/qcom/qm215-qrd-smb1360-overlay.dts b/arch/arm64/boot/dts/qcom/qm215-qrd-smb1360-overlay.dts
new file mode 100644
index 000000000000..2ada905efcb6
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/qm215-qrd-smb1360-overlay.dts
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2019 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include "qm215-qrd-smb1360.dtsi"
+
+/ {
+ model = "QRD + SMB1360";
+ qcom,board-id = <0x0b 5>;
+};
diff --git a/arch/arm64/boot/dts/qcom/qm215-qrd-smb1360.dts b/arch/arm64/boot/dts/qcom/qm215-qrd-smb1360.dts
new file mode 100644
index 000000000000..c64753db2317
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/qm215-qrd-smb1360.dts
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2019, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+#include "qm215.dtsi"
+#include "qm215-pm8916.dtsi"
+#include "qm215-qrd-smb1360.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. qm215 SMB1360 QRD";
+ compatible = "qcom,qm215-qrd", "qcom,qm215", "qcom,qrd";
+ qcom,board-id = <0x0b 5>;
+};
diff --git a/arch/arm64/boot/dts/qcom/qm215-qrd-smb1360.dtsi b/arch/arm64/boot/dts/qcom/qm215-qrd-smb1360.dtsi
new file mode 100644
index 000000000000..285f91a3e300
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/qm215-qrd-smb1360.dtsi
@@ -0,0 +1,66 @@
+/* Copyright (c) 2019, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "qm215-qrd.dtsi"
+
+&pm8916_chg{
+ qcom,use-external-charger;
+};
+
+&pm8916_bms{
+ qcom,disable-bms;
+};
+
+&tlmm {
+ /* SMB interrupt pin */
+ smb_int_pin {
+ smb_int_default: smb_int_default {
+ mux {
+ pins = "gpio13";
+ function ="gpio";
+ };
+ config {
+ pins = "gpio13";
+ bias-pull-up; /* PULL UP*/
+ input-enable;
+ };
+ };
+ };
+};
+
+&i2c_2 {
+ status ="ok";
+ smb1360_otg_supply: smb1360-chg-fg@14 {
+ compatible = "qcom,smb1360-chg-fg";
+ reg = <0x14>;
+ interrupt-parent = <&tlmm>;
+ interrupts = <13 8>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&smb_int_default>;
+ qcom,empty-soc-disabled;
+ qcom,chg-inhibit-disabled;
+ qcom,float-voltage-mv = <4400>;
+ qcom,iterm-ma = <100>;
+ qcom,recharge-thresh-mv = <100>;
+ qcom,thermal-mitigation = <1500 700 600 0>;
+ regulator-name = "smb1360_otg_vreg";
+ qcom,fg-batt-capacity-mah = <2800>;
+ qcom,fg-cutoff-voltage-mv = <3400>;
+ qcom,fg-iterm-ma = <130>;
+ qcom,fg-delta-soc = <1>;
+ status= "okay";
+ };
+};
+
+&usb_otg {
+ extcon = <&smb1360_otg_supply>;
+};
diff --git a/arch/arm64/boot/dts/qcom/qm215.dtsi b/arch/arm64/boot/dts/qcom/qm215.dtsi
index e805d93080c2..810932ae7d8c 100644
--- a/arch/arm64/boot/dts/qcom/qm215.dtsi
+++ b/arch/arm64/boot/dts/qcom/qm215.dtsi
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -56,6 +56,10 @@
};
};
+&clock_gcc {
+ compatible = "qcom,gcc-qm215";
+};
+
/* GPU overrides */
&msm_gpu {
@@ -264,3 +268,13 @@
};
};
};
+
+&thermal_zones {
+ gpu0-step {
+ trips {
+ gpu-step-trip {
+ temperature = <85000>;
+ };
+ };
+ };
+};
diff --git a/arch/arm64/configs/msm8937-perf_defconfig b/arch/arm64/configs/msm8937-perf_defconfig
index 2a801e9a4620..467dc4fbb133 100644
--- a/arch/arm64/configs/msm8937-perf_defconfig
+++ b/arch/arm64/configs/msm8937-perf_defconfig
@@ -640,7 +640,6 @@ CONFIG_CORESIGHT_QCOM_REPLICATOR=y
CONFIG_CORESIGHT_STM=y
CONFIG_CORESIGHT_TPDA=y
CONFIG_CORESIGHT_TPDM=y
-CONFIG_CORESIGHT_CTI=y
CONFIG_CORESIGHT_EVENT=y
CONFIG_CORESIGHT_HWEVENT=y
CONFIG_PFK=y
diff --git a/arch/arm64/kernel/perf_event.c b/arch/arm64/kernel/perf_event.c
index e0b731e70f66..c845bf57ccb3 100644
--- a/arch/arm64/kernel/perf_event.c
+++ b/arch/arm64/kernel/perf_event.c
@@ -779,8 +779,8 @@ static irqreturn_t armv8pmu_handle_irq(int irq_num, void *dev)
struct perf_event *event = cpuc->events[idx];
struct hw_perf_event *hwc;
- /* Ignore if we don't have an event or if it's a zombie event */
- if (!event || event->state == PERF_EVENT_STATE_ZOMBIE)
+ /* Ignore if we don't have an event */
+ if (!event || event->state != PERF_EVENT_STATE_ACTIVE)
continue;
/*
diff --git a/drivers/char/diag/diag_dci.c b/drivers/char/diag/diag_dci.c
index 0937b2f14d77..5a1afd0e41c7 100644
--- a/drivers/char/diag/diag_dci.c
+++ b/drivers/char/diag/diag_dci.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -2757,10 +2757,11 @@ err:
int diag_dci_init(void)
{
- int ret = 0;
+ int ret = 0, i;
driver->dci_tag = 0;
- driver->dci_client_id = 0;
+ for (i = 0; i < MAX_DCI_CLIENTS; i++)
+ driver->dci_client_id[i] = 0;
driver->num_dci_client = 0;
mutex_init(&driver->dci_mutex);
mutex_init(&dci_log_mask_mutex);
@@ -2956,8 +2957,8 @@ int diag_dci_register_client(struct diag_dci_reg_tbl_t *reg_entry)
mutex_init(&new_entry->write_buf_mutex);
new_entry->dci_log_mask = vzalloc(DCI_LOG_MASK_SIZE);
if (!new_entry->dci_log_mask) {
- pr_err("diag: Unable to create log mask for client, %d",
- driver->dci_client_id);
+ pr_err("diag: Unable to create log mask for DCI client, tgid: %d\n",
+ current->tgid);
goto fail_alloc;
}
create_dci_log_mask_tbl(new_entry->dci_log_mask, DCI_LOG_MASK_CLEAN);
@@ -3006,17 +3007,24 @@ int diag_dci_register_client(struct diag_dci_reg_tbl_t *reg_entry)
proc_buf->buf_curr = proc_buf->buf_primary;
}
- list_add_tail(&new_entry->track, &driver->dci_client_list);
- driver->dci_client_id++;
- new_entry->client_info.client_id = driver->dci_client_id;
- reg_entry->client_id = driver->dci_client_id;
+ for (i = 0; i < MAX_DCI_CLIENTS; i++) {
+ if (driver->dci_client_id[i] == 0)
+ break;
+ }
+
+ if (i == MAX_DCI_CLIENTS)
+ goto fail_alloc;
+ driver->dci_client_id[i] = 1;
+ new_entry->client_info.client_id = i+1;
+ reg_entry->client_id = i+1;
driver->num_dci_client++;
+ list_add_tail(&new_entry->track, &driver->dci_client_list);
if (driver->num_dci_client == 1)
diag_update_proc_vote(DIAG_PROC_DCI, VOTE_UP, reg_entry->token);
queue_work(driver->diag_real_time_wq, &driver->diag_real_time_work);
mutex_unlock(&driver->dci_mutex);
- return driver->dci_client_id;
+ return reg_entry->client_id;
fail_alloc:
if (new_entry) {
@@ -3075,7 +3083,11 @@ int diag_dci_deinit_client(struct diag_dci_client_tbl *entry)
*/
if (!list_empty(&entry->track))
list_del(&entry->track);
+
+ if (entry->client_info.client_id > MAX_DCI_CLIENTS)
+ return DIAG_DCI_NO_REG;
driver->num_dci_client--;
+ driver->dci_client_id[entry->client_info.client_id - 1] = 0;
/*
* Clear the client's log and event masks, update the cumulative
* masks and send the masks to peripherals
diff --git a/drivers/char/diag/diag_dci.h b/drivers/char/diag/diag_dci.h
index 2fb0e3f7adf3..835c0c1708cf 100644
--- a/drivers/char/diag/diag_dci.h
+++ b/drivers/char/diag/diag_dci.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2016, 2018 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2016, 2018-2019 The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -12,7 +12,6 @@
#ifndef DIAG_DCI_H
#define DIAG_DCI_H
-#define MAX_DCI_CLIENTS 10
#define DCI_PKT_RSP_CODE 0x93
#define DCI_DELAYED_RSP_CODE 0x94
#define DCI_CONTROL_PKT_CODE 0x9A
diff --git a/drivers/char/diag/diag_masks.c b/drivers/char/diag/diag_masks.c
index 41ab3386f138..8d53a06c62a3 100644
--- a/drivers/char/diag/diag_masks.c
+++ b/drivers/char/diag/diag_masks.c
@@ -1773,6 +1773,7 @@ static int __diag_mask_init(struct diag_mask_info *mask_info, int mask_len,
mask_info->update_buf = kzalloc(update_buf_len, GFP_KERNEL);
if (!mask_info->update_buf) {
kfree(mask_info->ptr);
+ mask_info->ptr = NULL;
return -ENOMEM;
}
kmemleak_not_leak(mask_info->update_buf);
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index f63d78c32b6e..2a32397b5ef6 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2008-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -288,6 +288,7 @@ for (i = 0; i <= fwd_info->num_pd - 2; i++) \
#define DIAG_CNTL_TYPE 2
#define DIAG_DCI_TYPE 3
+#define MAX_DCI_CLIENTS 10
/*
* List of diag ids
* 0 is reserved for unknown diag id, 1 for apps, diag ids
@@ -580,7 +581,7 @@ struct diagchar_dev {
struct list_head dci_req_list;
struct list_head dci_client_list;
int dci_tag;
- int dci_client_id;
+ int dci_client_id[MAX_DCI_CLIENTS];
struct mutex dci_mutex;
int num_dci_client;
unsigned char *apps_dci_buf;
diff --git a/drivers/clk/msm/clock-gcc-8952.c b/drivers/clk/msm/clock-gcc-8952.c
index 71f0ea6fb746..ed39a8ba777f 100644
--- a/drivers/clk/msm/clock-gcc-8952.c
+++ b/drivers/clk/msm/clock-gcc-8952.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -371,6 +371,7 @@ DEFINE_EXT_CLK(gpll0_clk_src, NULL);
DEFINE_EXT_CLK(gpll0_ao_clk_src, NULL);
DEFINE_EXT_CLK(gpll0_out_aux_clk_src, &gpll0_clk_src.c);
DEFINE_EXT_CLK(gpll0_out_main_clk_src, &gpll0_clk_src.c);
+DEFINE_EXT_CLK(gpll0_gfx_clk_src, &gpll0_clk_src.c);
DEFINE_EXT_CLK(ext_pclk0_clk_src, NULL);
DEFINE_EXT_CLK(ext_byte0_clk_src, NULL);
DEFINE_EXT_CLK(ext_pclk1_clk_src, NULL);
@@ -428,6 +429,7 @@ static struct pll_vote_clk gpll6_clk_src = {
DEFINE_EXT_CLK(gpll6_aux_clk_src, &gpll6_clk_src.c);
DEFINE_EXT_CLK(gpll6_out_main_clk_src, &gpll6_clk_src.c);
+DEFINE_EXT_CLK(gpll6_gfx_clk_src, &gpll6_clk_src.c);
static struct alpha_pll_masks pll_masks_p = {
.lock_mask = BIT(31),
@@ -873,6 +875,28 @@ static struct clk_freq_tbl ftbl_gcc_oxili_gfx3d_clk_8917_650MHz[] = {
F_END
};
+static struct clk_freq_tbl ftbl_gcc_oxili_gfx3d_clk_qm215[] = {
+ F_SLEW( 19200000, FIXED_CLK_SRC, xo, 1, 0, 0),
+ F_SLEW( 50000000, FIXED_CLK_SRC, gpll0_gfx, 16, 0, 0),
+ F_SLEW( 80000000, FIXED_CLK_SRC, gpll0_gfx, 10, 0, 0),
+ F_SLEW( 100000000, FIXED_CLK_SRC, gpll0_gfx, 8, 0, 0),
+ F_SLEW( 160000000, FIXED_CLK_SRC, gpll0_gfx, 5, 0, 0),
+ F_SLEW( 200000000, FIXED_CLK_SRC, gpll0_gfx, 4, 0, 0),
+ F_SLEW( 228570000, FIXED_CLK_SRC, gpll0_gfx, 3.5, 0, 0),
+ F_SLEW( 240000000, FIXED_CLK_SRC, gpll6_gfx, 4.5, 0, 0),
+ F_SLEW( 266670000, FIXED_CLK_SRC, gpll0_gfx, 3, 0, 0),
+ F_SLEW( 270000000, FIXED_CLK_SRC, gpll6_gfx, 4, 0, 0),
+ F_SLEW( 320000000, FIXED_CLK_SRC, gpll0_gfx, 2.5, 0, 0),
+ F_SLEW( 400000000, FIXED_CLK_SRC, gpll0_gfx, 2, 0, 0),
+ F_SLEW( 465000000, 930000000, gpll3, 1, 0, 0),
+ F_SLEW( 484800000, 969600000, gpll3, 1, 0, 0),
+ F_SLEW( 500000000, 1000000000, gpll3, 1, 0, 0),
+ F_SLEW( 523200000, 1046400000, gpll3, 1, 0, 0),
+ F_SLEW( 550000000, 1100000000, gpll3, 1, 0, 0),
+ F_SLEW( 598000000, 1196000000, gpll3, 1, 0, 0),
+ F_END
+};
+
static struct rcg_clk gfx3d_clk_src = {
.cmd_rcgr_reg = GFX3D_CMD_RCGR,
.set_rate = set_rate_hid,
@@ -4388,6 +4412,7 @@ static int msm_gcc_probe(struct platform_device *pdev)
bool compat_bin4 = false;
bool compat_bin5 = false;
bool compat_bin6 = false;
+ bool compat_bin7 = false;
compat_bin = of_device_is_compatible(pdev->dev.of_node,
"qcom,gcc-8937");
@@ -4407,11 +4432,14 @@ static int msm_gcc_probe(struct platform_device *pdev)
compat_bin6 = of_device_is_compatible(pdev->dev.of_node,
"qcom,gcc-sdm439");
+ compat_bin7 = of_device_is_compatible(pdev->dev.of_node,
+ "qcom,gcc-qm215");
+
ret = vote_bimc(&bimc_clk, INT_MAX);
if (ret < 0)
return ret;
- if (compat_bin2 || compat_bin4 || compat_bin5)
+ if (compat_bin2 || compat_bin4 || compat_bin5 || compat_bin7)
nbases = APCS_C0_PLL_BASE;
if (compat_bin5 || compat_bin6) {
@@ -4444,7 +4472,7 @@ static int msm_gcc_probe(struct platform_device *pdev)
return PTR_ERR(vdd_dig.regulator[0]);
}
- if (!compat_bin2 && !compat_bin4 && !compat_bin5) {
+ if (!compat_bin2 && !compat_bin4 && !compat_bin5 && !compat_bin7) {
vdd_sr2_pll.regulator[0] = devm_regulator_get(&pdev->dev,
"vdd_sr2_pll");
if (IS_ERR(vdd_sr2_pll.regulator[0])) {
@@ -4538,7 +4566,7 @@ static int msm_gcc_probe(struct platform_device *pdev)
475000000;
}
}
- } else if (compat_bin2 || compat_bin4) {
+ } else if (compat_bin2 || compat_bin4 || compat_bin7) {
gpll0_clk_src.c.parent = &gpll0_clk_src_8937.c;
gpll0_ao_clk_src.c.parent = &gpll0_ao_clk_src_8937.c;
vdd_dig.num_levels = VDD_DIG_NUM_8917;
@@ -4548,6 +4576,9 @@ static int msm_gcc_probe(struct platform_device *pdev)
get_speed_bin(pdev, &speed_bin);
override_for_8917(speed_bin);
+ if (compat_bin7)
+ OVERRIDE_FTABLE(gfx3d, ftbl_gcc_oxili_gfx3d_clk, qm215);
+
if (compat_bin2) {
blsp1_qup2_spi_apps_clk_src.freq_tbl =
ftbl_gcc_blsp1_2_qup1_4_spi_apps_clk_8917;
@@ -4577,7 +4608,7 @@ static int msm_gcc_probe(struct platform_device *pdev)
ret = of_msm_clock_register(pdev->dev.of_node,
msm_clocks_lookup_8937,
ARRAY_SIZE(msm_clocks_lookup_8937));
- else if (compat_bin2)
+ else if (compat_bin2 || compat_bin7)
ret = of_msm_clock_register(pdev->dev.of_node,
msm_clocks_lookup_8917,
ARRAY_SIZE(msm_clocks_lookup_8917));
@@ -4650,6 +4681,7 @@ static const struct of_device_id msm_clock_gcc_match_table[] = {
{ .compatible = "qcom,gcc-8920" },
{ .compatible = "qcom,gcc-sdm439" },
{ .compatible = "qcom,gcc-sdm429" },
+ { .compatible = "qcom,gcc-qm215" },
{}
};
diff --git a/drivers/iommu/dma-mapping-fast.c b/drivers/iommu/dma-mapping-fast.c
index 7e6287c986ef..31482f99f37f 100644
--- a/drivers/iommu/dma-mapping-fast.c
+++ b/drivers/iommu/dma-mapping-fast.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -546,12 +546,22 @@ static void *fast_smmu_alloc(struct device *dev, size_t size,
av8l_fast_iopte *ptep;
unsigned long flags;
struct sg_mapping_iter miter;
- unsigned int count = ALIGN(size, SZ_4K) >> PAGE_SHIFT;
+ size_t count = ALIGN(size, SZ_4K) >> PAGE_SHIFT;
int prot = IOMMU_READ | IOMMU_WRITE; /* TODO: extract from attrs */
bool is_coherent = is_dma_coherent(dev, attrs);
pgprot_t remap_prot = __get_dma_pgprot(attrs, PAGE_KERNEL, is_coherent);
struct page **pages;
+ /*
+ * sg_alloc_table_from_pages accepts unsigned int value for count
+ * so check count doesn't exceed UINT_MAX.
+ */
+
+ if (count > UINT_MAX) {
+ dev_err(dev, "count: %zx exceeds UNIT_MAX\n", count);
+ return NULL;
+ }
+
prot = __get_iommu_pgprot(attrs, prot, is_coherent);
*handle = DMA_ERROR_CODE;
diff --git a/drivers/iommu/iommu-debug.c b/drivers/iommu/iommu-debug.c
index 25b85ab146a2..2dcac176812c 100644
--- a/drivers/iommu/iommu-debug.c
+++ b/drivers/iommu/iommu-debug.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -1349,6 +1349,7 @@ static ssize_t iommu_debug_dma_attach_read(struct file *file, char __user *ubuf,
struct iommu_debug_device *ddev = file->private_data;
struct device *dev = ddev->dev;
char c[2];
+ size_t buflen = sizeof(c);
if (*offset)
return 0;
@@ -1359,13 +1360,14 @@ static ssize_t iommu_debug_dma_attach_read(struct file *file, char __user *ubuf,
c[0] = dev->archdata.mapping->domain ? '1' : '0';
c[1] = '\n';
- if (copy_to_user(ubuf, &c, 2)) {
+ buflen = min(count, buflen);
+ if (copy_to_user(ubuf, &c, buflen)) {
pr_err("copy_to_user failed\n");
return -EFAULT;
}
*offset = 1; /* non-zero means we're done */
- return 2;
+ return buflen;
}
static const struct file_operations iommu_debug_dma_attach_fops = {
@@ -1393,7 +1395,7 @@ static ssize_t iommu_debug_test_virt_addr_read(struct file *file,
else
snprintf(buf, buf_len, "0x%pK\n", test_virt_addr);
- buflen = strlen(buf);
+ buflen = min(count, strlen(buf)+1);
if (copy_to_user(ubuf, buf, buflen)) {
pr_err("Couldn't copy_to_user\n");
retval = -EFAULT;
@@ -1424,19 +1426,21 @@ static ssize_t iommu_debug_attach_read(struct file *file, char __user *ubuf,
{
struct iommu_debug_device *ddev = file->private_data;
char c[2];
+ size_t buflen = sizeof(c);
if (*offset)
return 0;
c[0] = ddev->domain ? '1' : '0';
c[1] = '\n';
- if (copy_to_user(ubuf, &c, 2)) {
+ buflen = min(count, buflen);
+ if (copy_to_user(ubuf, &c, buflen)) {
pr_err("copy_to_user failed\n");
return -EFAULT;
}
*offset = 1; /* non-zero means we're done */
- return 2;
+ return buflen;
}
static const struct file_operations iommu_debug_attach_fops = {
@@ -1514,7 +1518,7 @@ static ssize_t iommu_debug_pte_read(struct file *file, char __user *ubuf,
else
snprintf(buf, sizeof(buf), "pte=%016llx\n", pte);
- buflen = strlen(buf);
+ buflen = min(count, strlen(buf)+1);
if (copy_to_user(ubuf, buf, buflen)) {
pr_err("Couldn't copy_to_user\n");
retval = -EFAULT;
@@ -1583,7 +1587,7 @@ static ssize_t iommu_debug_atos_read(struct file *file, char __user *ubuf,
snprintf(buf, 100, "%pa\n", &phys);
}
- buflen = strlen(buf);
+ buflen = min(count, strlen(buf)+1);
if (copy_to_user(ubuf, buf, buflen)) {
pr_err("Couldn't copy_to_user\n");
retval = -EFAULT;
@@ -1636,7 +1640,7 @@ static ssize_t iommu_debug_dma_atos_read(struct file *file, char __user *ubuf,
else
snprintf(buf, sizeof(buf), "%pa\n", &phys);
- buflen = strlen(buf);
+ buflen = min(count, strlen(buf)+1);
if (copy_to_user(ubuf, buf, buflen)) {
pr_err("Couldn't copy_to_user\n");
retval = -EFAULT;
@@ -1869,7 +1873,7 @@ static ssize_t iommu_debug_dma_map_read(struct file *file, char __user *ubuf,
iova = ddev->iova;
snprintf(buf, sizeof(buf), "%pa\n", &iova);
- buflen = strlen(buf);
+ buflen = min(count, strlen(buf)+1);
if (copy_to_user(ubuf, buf, buflen)) {
pr_err("Couldn't copy_to_user\n");
retval = -EFAULT;
diff --git a/drivers/leds/leds-qpnp-vibrator.c b/drivers/leds/leds-qpnp-vibrator.c
index cc2615daf1c1..d8dcdf6e0b9a 100644
--- a/drivers/leds/leds-qpnp-vibrator.c
+++ b/drivers/leds/leds-qpnp-vibrator.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2015, 2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2015, 2018-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -314,6 +314,13 @@ static ssize_t qpnp_vib_get_state(struct device *dev,
return snprintf(buf, PAGE_SIZE, "%d\n", !!chip->reg_en_ctl);
}
+static ssize_t qpnp_vib_set_state(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ /* At present, nothing to do with setting state */
+ return count;
+}
+
static ssize_t qpnp_vib_get_duration(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -399,7 +406,7 @@ static ssize_t qpnp_vib_set_activate(struct device *dev,
}
static struct device_attribute qpnp_vib_attrs[] = {
- __ATTR(state, 0444, qpnp_vib_get_state, NULL),
+ __ATTR(state, 0664, qpnp_vib_get_state, qpnp_vib_set_state),
__ATTR(duration, 0664, qpnp_vib_get_duration, qpnp_vib_set_duration),
__ATTR(activate, 0664, qpnp_vib_get_activate, qpnp_vib_set_activate),
};
diff --git a/drivers/media/platform/msm/camera_v2/sensor/flash/Makefile b/drivers/media/platform/msm/camera_v2/sensor/flash/Makefile
index 6a28da5926c7..69be506f6b0b 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/flash/Makefile
+++ b/drivers/media/platform/msm/camera_v2/sensor/flash/Makefile
@@ -3,3 +3,4 @@ ccflags-y += -Idrivers/media/platform/msm/camera_v2
ccflags-y += -Idrivers/media/platform/msm/camera_v2/common
ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/io
obj-$(CONFIG_MSMB_CAMERA) += msm_flash.o
+obj-$(CONFIG_MSMB_CAMERA) += qm215_gpio_flash.o
diff --git a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c
index 656b1ca2dc98..89a5ea06cc49 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2009-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -17,6 +17,7 @@
#include <linux/of_gpio.h>
#include <linux/leds-qpnp-flash.h>
#include "msm_flash.h"
+#include "msm_camera_io_util.h"
#include "msm_camera_dt_util.h"
#include "msm_cci.h"
@@ -514,6 +515,8 @@ static int32_t msm_flash_init(
__func__, __LINE__,
flash_data->cfg.flash_init_info->flash_driver_type);
}
+ if (flash_ctrl->platform_flash_init)
+ flash_ctrl->platform_flash_init(flash_ctrl, flash_data);
if (flash_ctrl->func_tbl->camera_flash_init) {
rc = flash_ctrl->func_tbl->camera_flash_init(
@@ -600,6 +603,8 @@ static int32_t msm_flash_prepare(
__func__, __LINE__, flash_ctrl->flash_state);
if (flash_ctrl->switch_trigger == NULL) {
+ if (flash_ctrl->platform_flash_init)
+ return ret;
pr_err("%s:%d Invalid argument\n",
__func__, __LINE__);
return -EINVAL;
@@ -1286,6 +1291,8 @@ static int32_t msm_flash_platform_probe(struct platform_device *pdev)
kfree(flash_ctrl);
return -EINVAL;
}
+ if (flash_ctrl->flash_driver_type == FLASH_DRIVER_GPIO)
+ platform_set_drvdata(pdev, flash_ctrl);
flash_ctrl->flash_state = MSM_CAMERA_FLASH_RELEASE;
flash_ctrl->power_info.dev = &flash_ctrl->pdev->dev;
@@ -1334,6 +1341,11 @@ static int32_t msm_flash_platform_probe(struct platform_device *pdev)
return rc;
}
+int32_t camera_flash_platform_probe(struct platform_device *pdev)
+{
+ return msm_flash_platform_probe(pdev);
+}
+
MODULE_DEVICE_TABLE(of, msm_flash_dt_match);
static struct platform_driver msm_flash_platform_driver = {
diff --git a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.h b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.h
index eda6ce44b6bc..67a8c2c7333a 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.h
+++ b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2016, 2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2009-2016, 2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -102,6 +102,8 @@ struct msm_flash_ctrl_t {
/* flash state */
enum msm_camera_flash_state_t flash_state;
+ int32_t (*platform_flash_init)(struct msm_flash_ctrl_t *flash_ctrl,
+ struct msm_flash_cfg_data_t *flash_data);
};
int msm_flash_i2c_probe(struct i2c_client *client,
@@ -124,4 +126,6 @@ int msm_flash_led_release(struct msm_flash_ctrl_t *fctrl);
int msm_flash_led_off(struct msm_flash_ctrl_t *fctrl);
int msm_flash_led_low(struct msm_flash_ctrl_t *fctrl);
int msm_flash_led_high(struct msm_flash_ctrl_t *fctrl);
+int32_t camera_flash_platform_probe(struct platform_device *pdev);
+
#endif
diff --git a/drivers/media/platform/msm/camera_v2/sensor/flash/qm215_gpio_flash.c b/drivers/media/platform/msm/camera_v2/sensor/flash/qm215_gpio_flash.c
new file mode 100644
index 000000000000..11a7db55e3f4
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/flash/qm215_gpio_flash.c
@@ -0,0 +1,264 @@
+/* Copyright (c) 2019, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/export.h>
+#include "msm_camera_io_util.h"
+#include "msm_flash.h"
+
+#define FLASH_NAME "qcom,gpio-flash"
+
+#undef CDBG
+#define CDBG(fmt, args...) pr_debug(fmt, ##args)
+
+static const struct of_device_id msm_gpio_flash_dt_match[] = {
+ {.compatible = "qcom,qm215-gpio-flash", .data = NULL},
+ {}
+};
+static struct msm_flash_table qm215_gpio_flash_table;
+MODULE_DEVICE_TABLE(of, msm_flash_dt_match);
+
+static int32_t qm215_flash_low(
+ struct msm_flash_ctrl_t *flash_ctrl,
+ struct msm_flash_cfg_data_t *flash_data)
+{
+ struct msm_camera_power_ctrl_t *power_info = NULL;
+ struct msm_camera_gpio_num_info *gpio_num_info = NULL;
+
+ if (!flash_ctrl) {
+ pr_err("device data NULL\n");
+ return -EINVAL;
+ }
+
+ CDBG("Enter");
+ power_info = &flash_ctrl->power_info;
+ gpio_num_info = power_info->gpio_conf->gpio_num_info;
+
+ if (flash_ctrl->flash_driver_type == FLASH_DRIVER_GPIO &&
+ gpio_num_info->valid[SENSOR_GPIO_FL_NOW] &&
+ gpio_num_info->gpio_num[SENSOR_GPIO_FL_EN]) {
+
+ CDBG("flash op low gpio num %d(state:%d) %d(state: %d)\n",
+ gpio_num_info->gpio_num[SENSOR_GPIO_FL_NOW],
+ GPIO_OUT_HIGH,
+ gpio_num_info->gpio_num[SENSOR_GPIO_FL_EN],
+ GPIO_OUT_HIGH);
+ gpio_set_value_cansleep(
+ gpio_num_info->gpio_num[SENSOR_GPIO_FL_NOW],
+ GPIO_OUT_HIGH);
+ gpio_set_value_cansleep(
+ gpio_num_info->gpio_num[SENSOR_GPIO_FL_EN],
+ GPIO_OUT_HIGH);
+ }
+ CDBG("Exit\n");
+ return 0;
+}
+
+static int32_t qm215_flash_high(
+ struct msm_flash_ctrl_t *flash_ctrl,
+ struct msm_flash_cfg_data_t *flash_data)
+{
+ struct msm_camera_power_ctrl_t *power_info = NULL;
+ struct msm_camera_gpio_num_info *gpio_num_info = NULL;
+
+ if (!flash_ctrl) {
+ pr_err("device data NULL\n");
+ return -EINVAL;
+ }
+
+ CDBG("Enter\n");
+ power_info = &flash_ctrl->power_info;
+ gpio_num_info = power_info->gpio_conf->gpio_num_info;
+
+ if (flash_ctrl->flash_driver_type == FLASH_DRIVER_GPIO &&
+ gpio_num_info->valid[SENSOR_GPIO_FL_NOW] &&
+ gpio_num_info->gpio_num[SENSOR_GPIO_FL_EN]) {
+
+ CDBG("flash op high gpio num %d(state:%d) %d(state:%d)\n",
+ gpio_num_info->gpio_num[SENSOR_GPIO_FL_NOW],
+ GPIO_OUT_LOW,
+ gpio_num_info->gpio_num[SENSOR_GPIO_FL_EN],
+ GPIO_OUT_HIGH);
+ gpio_set_value_cansleep(
+ gpio_num_info->gpio_num[SENSOR_GPIO_FL_NOW],
+ GPIO_OUT_LOW);
+ gpio_set_value_cansleep(
+ gpio_num_info->gpio_num[SENSOR_GPIO_FL_EN],
+ GPIO_OUT_HIGH);
+ }
+ CDBG("Exit\n");
+
+ return 0;
+}
+
+static int32_t qm215_flash_release(
+ struct msm_flash_ctrl_t *flash_ctrl)
+{
+ int32_t rc = 0;
+
+ if (!flash_ctrl) {
+ pr_err("device data NULL\n");
+ return -EINVAL;
+ }
+
+ CDBG("Enter\n");
+ rc = flash_ctrl->func_tbl->camera_flash_off(flash_ctrl, NULL);
+ if (rc < 0) {
+ pr_err("%s:%d camera_flash_init failed rc = %d",
+ __func__, __LINE__, rc);
+ return rc;
+ }
+ flash_ctrl->flash_state = MSM_CAMERA_FLASH_RELEASE;
+ CDBG("Exit\n");
+ return 0;
+}
+
+static int32_t qm215_flash_off(struct msm_flash_ctrl_t *flash_ctrl,
+ struct msm_flash_cfg_data_t *flash_data)
+{
+ struct msm_camera_power_ctrl_t *power_info = NULL;
+ struct msm_camera_gpio_num_info *gpio_num_info = NULL;
+
+ if (!flash_ctrl) {
+ pr_err("device data NULL\n");
+ return -EINVAL;
+ }
+
+ CDBG("Enter\n");
+ power_info = &flash_ctrl->power_info;
+ gpio_num_info = power_info->gpio_conf->gpio_num_info;
+
+ if (flash_ctrl->flash_driver_type == FLASH_DRIVER_GPIO &&
+ gpio_num_info->valid[SENSOR_GPIO_FL_NOW] &&
+ gpio_num_info->gpio_num[SENSOR_GPIO_FL_EN]) {
+
+ CDBG("flash off gpio num %d(state:%d) %d(state: %d)\n",
+ gpio_num_info->gpio_num[SENSOR_GPIO_FL_NOW],
+ GPIO_OUT_LOW,
+ gpio_num_info->gpio_num[SENSOR_GPIO_FL_EN],
+ GPIO_OUT_LOW);
+ gpio_set_value_cansleep(
+ gpio_num_info->gpio_num[SENSOR_GPIO_FL_NOW],
+ GPIO_OUT_LOW);
+ gpio_set_value_cansleep(
+ gpio_num_info->gpio_num[SENSOR_GPIO_FL_EN],
+ GPIO_OUT_LOW);
+ }
+
+ CDBG("Exit\n");
+ return 0;
+}
+
+static int32_t qm215_flash_gpio_init(
+ struct msm_flash_ctrl_t *flash_ctrl,
+ struct msm_flash_cfg_data_t *flash_data)
+{
+ int32_t rc = 0;
+
+ CDBG("Enter");
+ rc = flash_ctrl->func_tbl->camera_flash_off(flash_ctrl, flash_data);
+
+ CDBG("Exit");
+ return rc;
+}
+
+
+static int32_t qm215_platform_flash_init(struct msm_flash_ctrl_t *flash_ctrl,
+ struct msm_flash_cfg_data_t *flash_data)
+{
+ if (!flash_ctrl) {
+ pr_err("devices data NULL\n");
+ return -EINVAL;
+ }
+
+ if (flash_ctrl->flash_driver_type == FLASH_DRIVER_GPIO)
+ flash_ctrl->func_tbl = &qm215_gpio_flash_table.func_tbl;
+
+ return 0;
+}
+static int32_t qm215_flash_platform_probe(struct platform_device *pdev)
+{
+ int32_t rc = 0;
+ struct msm_flash_ctrl_t *flash_ctrl = NULL;
+ struct msm_camera_power_ctrl_t *power_info = NULL;
+ struct msm_camera_gpio_conf *gpio_conf = NULL;
+
+ if (!pdev->dev.of_node) {
+ pr_err("of_node NULL\n");
+ return -EINVAL;
+ }
+ CDBG("enter probe\n");
+ rc = camera_flash_platform_probe(pdev);
+ if (rc >= 0) {
+ flash_ctrl =
+ (struct msm_flash_ctrl_t *) platform_get_drvdata(pdev);
+ CDBG("device data %pK\n", flash_ctrl);
+ if (!flash_ctrl) {
+ pr_err("of_node NULL\n");
+ return -EINVAL;
+ }
+ power_info = &flash_ctrl->power_info;
+ gpio_conf = power_info->gpio_conf;
+ rc = msm_camera_request_gpio_table(gpio_conf->cam_gpio_req_tbl,
+ gpio_conf->cam_gpio_req_tbl_size, 1);
+ if (rc < 0) {
+ pr_err("%s: request gpio failed\n", __func__);
+ return rc;
+ }
+ flash_ctrl->platform_flash_init = qm215_platform_flash_init;
+ }
+ return rc;
+}
+
+static struct platform_driver msm_gpio_flash_platform_driver = {
+ .probe = qm215_flash_platform_probe,
+ .driver = {
+ .name = "qcom,camera-gpio-flash",
+ .owner = THIS_MODULE,
+ .of_match_table = msm_gpio_flash_dt_match,
+ },
+};
+
+static int __init qm215_gpio_flash_init_module(void)
+{
+ int32_t rc = 0;
+
+ CDBG("Enter\n");
+ rc = platform_driver_register(&msm_gpio_flash_platform_driver);
+ if (rc)
+ pr_err("platform probe for flash failed");
+
+ return rc;
+}
+
+static void __exit qm215_gpio_flash_exit_module(void)
+{
+ platform_driver_unregister(&msm_gpio_flash_platform_driver);
+}
+
+static struct msm_flash_table qm215_gpio_flash_table = {
+ .flash_driver_type = FLASH_DRIVER_GPIO,
+ .func_tbl = {
+ .camera_flash_init = qm215_flash_gpio_init,
+ .camera_flash_release = qm215_flash_release,
+ .camera_flash_off = qm215_flash_off,
+ .camera_flash_low = qm215_flash_low,
+ .camera_flash_high = qm215_flash_high,
+ .camera_flash_query_current = NULL,
+ },
+};
+
+module_init(qm215_gpio_flash_init_module);
+module_exit(qm215_gpio_flash_exit_module);
+MODULE_DESCRIPTION("MSM GPIO FLASH");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/msm/camera_v3/cam_cdm/cam_cdm_virtual_core.c b/drivers/media/platform/msm/camera_v3/cam_cdm/cam_cdm_virtual_core.c
index 9021ecabb27c..b2575825f983 100644
--- a/drivers/media/platform/msm/camera_v3/cam_cdm/cam_cdm_virtual_core.c
+++ b/drivers/media/platform/msm/camera_v3/cam_cdm/cam_cdm_virtual_core.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -118,6 +118,14 @@ int cam_virtual_cdm_submit_bl(struct cam_hw_info *cdm_hw,
if ((!rc) && (vaddr_ptr) && (len) &&
(len >= cdm_cmd->cmd[i].offset)) {
+
+
+ if ((len - cdm_cmd->cmd[i].offset) <=
+ cdm_cmd->cmd[i].len) {
+ CAM_ERR(CAM_CDM, "Not enough buffer");
+ rc = -EINVAL;
+ break;
+ }
CAM_DBG(CAM_CDM,
"hdl=%x vaddr=%pK offset=%d cmdlen=%d:%zu",
cdm_cmd->cmd[i].bl_addr.mem_handle,
diff --git a/drivers/media/platform/msm/camera_v3/cam_core/cam_context.c b/drivers/media/platform/msm/camera_v3/cam_core/cam_context.c
index d4f9b72f99f3..5d48369125cc 100644
--- a/drivers/media/platform/msm/camera_v3/cam_core/cam_context.c
+++ b/drivers/media/platform/msm/camera_v3/cam_core/cam_context.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -173,6 +173,7 @@ int cam_context_handle_crm_apply_req(struct cam_context *ctx,
return -EINVAL;
}
+ mutex_lock(&ctx->ctx_mutex);
if (ctx->state_machine[ctx->state].crm_ops.apply_req) {
rc = ctx->state_machine[ctx->state].crm_ops.apply_req(ctx,
apply);
@@ -181,6 +182,7 @@ int cam_context_handle_crm_apply_req(struct cam_context *ctx,
ctx->dev_hdl, ctx->state);
rc = -EPROTO;
}
+ mutex_unlock(&ctx->ctx_mutex);
return rc;
}
@@ -456,6 +458,7 @@ int cam_context_handle_start_dev(struct cam_context *ctx,
}
mutex_lock(&ctx->ctx_mutex);
+ ctx->last_flush_req = 0;
if (ctx->state_machine[ctx->state].ioctl_ops.start_dev)
rc = ctx->state_machine[ctx->state].ioctl_ops.start_dev(
ctx, cmd);
diff --git a/drivers/media/platform/msm/camera_v3/cam_core/cam_context_utils.c b/drivers/media/platform/msm/camera_v3/cam_core/cam_context_utils.c
index d98b900bc07a..f579ad30eebf 100644
--- a/drivers/media/platform/msm/camera_v3/cam_core/cam_context_utils.c
+++ b/drivers/media/platform/msm/camera_v3/cam_core/cam_context_utils.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -303,6 +303,12 @@ int32_t cam_context_config_dev_to_hw(
return rc;
}
+ if ((len < sizeof(struct cam_packet)) ||
+ (cmd->offset >= (len - sizeof(struct cam_packet)))) {
+ CAM_ERR(CAM_CTXT, "Not enough buf");
+ return -EINVAL;
+
+ }
packet = (struct cam_packet *) ((uint8_t *)packet_addr +
(uint32_t)cmd->offset);
@@ -333,6 +339,7 @@ int32_t cam_context_prepare_dev_to_hw(struct cam_context *ctx,
uintptr_t packet_addr;
struct cam_packet *packet;
size_t len = 0;
+ size_t remain_len = 0;
int32_t i = 0, j = 0;
if (!ctx || !cmd) {
@@ -381,6 +388,14 @@ int32_t cam_context_prepare_dev_to_hw(struct cam_context *ctx,
goto free_req;
}
+ remain_len = len;
+ if ((len < sizeof(struct cam_packet)) ||
+ ((size_t)cmd->offset >= len - sizeof(struct cam_packet))) {
+ CAM_ERR(CAM_CTXT, "invalid buff length: %zu or offset", len);
+ return -EINVAL;
+ }
+
+ remain_len -= (size_t)cmd->offset;
packet = (struct cam_packet *) ((uint8_t *)packet_addr +
(uint32_t)cmd->offset);
@@ -398,6 +413,7 @@ int32_t cam_context_prepare_dev_to_hw(struct cam_context *ctx,
/* preprocess the configuration */
memset(&cfg, 0, sizeof(cfg));
cfg.packet = packet;
+ cfg.remain_len = remain_len;
cfg.ctxt_to_hw_map = ctx->ctxt_to_hw_map;
cfg.max_hw_update_entries = CAM_CTX_CFG_MAX;
cfg.num_hw_update_entries = req->num_hw_update_entries;
diff --git a/drivers/media/platform/msm/camera_v3/cam_core/cam_hw_mgr_intf.h b/drivers/media/platform/msm/camera_v3/cam_core/cam_hw_mgr_intf.h
index fd30f115cc0c..c3d1c2eff4e9 100644
--- a/drivers/media/platform/msm/camera_v3/cam_core/cam_hw_mgr_intf.h
+++ b/drivers/media/platform/msm/camera_v3/cam_core/cam_hw_mgr_intf.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -153,6 +153,7 @@ struct cam_hw_mgr_dump_pf_data {
* struct cam_hw_prepare_update_args - Payload for prepare command
*
* @packet: CSL packet from user mode driver
+ * @remain_len Remaining length of CPU buffer after config offset
* @ctxt_to_hw_map: HW context from the acquire
* @max_hw_update_entries: Maximum hardware update entries supported
* @hw_update_entries: Actual hardware update configuration (returned)
@@ -169,6 +170,7 @@ struct cam_hw_mgr_dump_pf_data {
*/
struct cam_hw_prepare_update_args {
struct cam_packet *packet;
+ size_t remain_len;
void *ctxt_to_hw_map;
uint32_t max_hw_update_entries;
struct cam_hw_update_entry *hw_update_entries;
diff --git a/drivers/media/platform/msm/camera_v3/cam_cpas/cam_cpas_hw.c b/drivers/media/platform/msm/camera_v3/cam_cpas/cam_cpas_hw.c
index 2a91f03ecdc8..017e810e07c0 100644
--- a/drivers/media/platform/msm/camera_v3/cam_cpas/cam_cpas_hw.c
+++ b/drivers/media/platform/msm/camera_v3/cam_cpas/cam_cpas_hw.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -313,6 +313,9 @@ static int cam_cpas_util_axi_setup(struct cam_cpas *cpas_core,
goto mnoc_node_get_fail;
}
axi_port->axi_port_mnoc_node = axi_port_mnoc_node;
+ axi_port->ib_bw_voting_needed =
+ of_property_read_bool(axi_port_node,
+ "ib-bw-voting-needed");
rc = cam_cpas_util_register_bus_client(soc_info,
axi_port_mnoc_node, &axi_port->mnoc_bus);
@@ -662,12 +665,19 @@ static int cam_cpas_util_apply_client_axi_vote(
axi_port->camnoc_bus.src, axi_port->camnoc_bus.dst,
camnoc_bw, mnoc_bw);
- rc = cam_cpas_util_vote_bus_client_bw(&axi_port->mnoc_bus,
- mnoc_bw, mnoc_bw, false);
+ if (axi_port->ib_bw_voting_needed)
+ rc = cam_cpas_util_vote_bus_client_bw(&axi_port->mnoc_bus,
+ mnoc_bw, mnoc_bw, false);
+ else
+ rc = cam_cpas_util_vote_bus_client_bw(&axi_port->mnoc_bus,
+ mnoc_bw, 0, false);
+
if (rc) {
CAM_ERR(CAM_CPAS,
"Failed in mnoc vote ab[%llu] ib[%llu] rc=%d",
- mnoc_bw, mnoc_bw, rc);
+ mnoc_bw,
+ (axi_port->ib_bw_voting_needed ? mnoc_bw : 0),
+ rc);
goto unlock_axi_port;
}
diff --git a/drivers/media/platform/msm/camera_v3/cam_cpas/cam_cpas_hw.h b/drivers/media/platform/msm/camera_v3/cam_cpas/cam_cpas_hw.h
index f93d036ecfcf..8e016191edb2 100644
--- a/drivers/media/platform/msm/camera_v3/cam_cpas/cam_cpas_hw.h
+++ b/drivers/media/platform/msm/camera_v3/cam_cpas/cam_cpas_hw.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -149,6 +149,7 @@ struct cam_cpas_bus_client {
* @camnoc_bus: CAMNOC bus client info for this port
* @mnoc_bus: MNOC bus client info for this port
* @axi_port_name: Name of this AXI port
+ * @ib_bw_voting_needed: if this port can update ib bw dynamically
* @axi_port_node: Node representing this AXI Port
* @axi_port_mnoc_node: Node representing mnoc in this AXI Port
* @axi_port_camnoc_node: Node representing camnoc in this AXI Port
@@ -161,6 +162,7 @@ struct cam_cpas_axi_port {
struct cam_cpas_bus_client camnoc_bus;
struct cam_cpas_bus_client mnoc_bus;
const char *axi_port_name;
+ bool ib_bw_voting_needed;
struct device_node *axi_port_node;
struct device_node *axi_port_mnoc_node;
struct device_node *axi_port_camnoc_node;
diff --git a/drivers/media/platform/msm/camera_v3/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c b/drivers/media/platform/msm/camera_v3/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c
index ec0a906cb99a..8403d4dbe533 100644
--- a/drivers/media/platform/msm/camera_v3/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c
+++ b/drivers/media/platform/msm/camera_v3/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -30,7 +30,8 @@
static struct cam_fd_hw_mgr g_fd_hw_mgr;
-static int cam_fd_mgr_util_packet_validate(struct cam_packet *packet)
+static int cam_fd_mgr_util_packet_validate(struct cam_packet *packet,
+ size_t remain_len)
{
struct cam_cmd_buf_desc *cmd_desc = NULL;
int i, rc;
@@ -50,7 +51,7 @@ static int cam_fd_mgr_util_packet_validate(struct cam_packet *packet)
packet->patch_offset, packet->num_patches,
packet->kmd_cmd_buf_offset, packet->kmd_cmd_buf_index);
- if (cam_packet_util_validate_packet(packet)) {
+ if (cam_packet_util_validate_packet(packet, remain_len)) {
CAM_ERR(CAM_FD, "invalid packet:%d %d %d %d %d",
packet->kmd_cmd_buf_index,
packet->num_cmd_buf, packet->cmd_buf_offset,
@@ -162,8 +163,10 @@ static int cam_fd_mgr_util_put_frame_req(
mutex_lock(&g_fd_hw_mgr.frame_req_mutex);
req_ptr = *frame_req;
- if (req_ptr)
+ if (req_ptr) {
+ list_del_init(&req_ptr->list);
list_add_tail(&req_ptr->list, src_list);
+ }
*frame_req = NULL;
mutex_unlock(&g_fd_hw_mgr.frame_req_mutex);
@@ -608,7 +611,13 @@ static int cam_fd_mgr_util_prepare_io_buf_info(int32_t iommu_hdl,
rc);
return rc;
}
-
+ if (io_cfg[i].offsets[plane] >= size) {
+ CAM_ERR(CAM_FD,
+ "Invalid cpu buf %d %d %d",
+ io_cfg[i].direction,
+ io_cfg[i].resource_type, plane);
+ return -EINVAL;
+ }
cpu_addr[plane] += io_cfg[i].offsets[plane];
}
@@ -1444,6 +1453,16 @@ unlock_dev_flush_ctx:
for (i = 0; i < flush_args->num_req_pending; i++) {
flush_req = (struct cam_fd_mgr_frame_request *)
flush_args->flush_req_pending[i];
+ CAM_DBG(CAM_FD, "flush pending req %llu",
+ flush_req->request_id);
+ cam_fd_mgr_util_put_frame_req(&hw_mgr->frame_free_list,
+ &flush_req);
+ }
+
+ for (i = 0; i < flush_args->num_req_active; i++) {
+ flush_req = (struct cam_fd_mgr_frame_request *)
+ flush_args->flush_req_active[i];
+ CAM_DBG(CAM_FD, "flush active req %llu", flush_req->request_id);
cam_fd_mgr_util_put_frame_req(&hw_mgr->frame_free_list,
&flush_req);
}
@@ -1559,7 +1578,8 @@ static int cam_fd_mgr_hw_prepare_update(void *hw_mgr_priv,
goto error;
}
- rc = cam_fd_mgr_util_packet_validate(prepare->packet);
+ rc = cam_fd_mgr_util_packet_validate(prepare->packet,
+ prepare->remain_len);
if (rc) {
CAM_ERR(CAM_FD, "Error in packet validation %d", rc);
goto error;
diff --git a/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/bps_hw/bps_core.c b/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/bps_hw/bps_core.c
index b969c92ccbc8..a330cff293d6 100644
--- a/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/bps_hw/bps_core.c
+++ b/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/bps_hw/bps_core.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -226,6 +226,13 @@ static int cam_bps_cmd_reset(struct cam_hw_soc_info *soc_info,
bool reset_bps_top_fail = false;
CAM_DBG(CAM_ICP, "CAM_ICP_BPS_CMD_RESET");
+
+ if (!core_info->clk_enable || !core_info->cpas_start) {
+ CAM_ERR(CAM_ICP, "BPS reset failed. clk_en %d cpas_start %d",
+ core_info->clk_enable, core_info->cpas_start);
+ return -EINVAL;
+ }
+
/* Reset BPS CDM core*/
cam_io_w_mb((uint32_t)0xF,
soc_info->reg_map[0].mem_base + BPS_CDM_RST_CMD);
diff --git a/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c b/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c
index 73e42de3fa03..f5d547af8c15 100644
--- a/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c
+++ b/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -3936,6 +3936,9 @@ static int cam_icp_mgr_prepare_hw_update(void *hw_mgr_priv,
packet = prepare_args->packet;
+ if (cam_packet_util_validate_packet(packet, prepare_args->remain_len))
+ return -EINVAL;
+
rc = cam_icp_mgr_pkt_validation(packet);
if (rc) {
mutex_unlock(&ctx_data->ctx_mutex);
diff --git a/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/ipe_hw/ipe_core.c b/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/ipe_hw/ipe_core.c
index 142fcdc6017d..1f71c7d4cd36 100644
--- a/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/ipe_hw/ipe_core.c
+++ b/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/ipe_hw/ipe_core.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -222,6 +222,12 @@ static int cam_ipe_cmd_reset(struct cam_hw_soc_info *soc_info,
bool reset_ipe_top_fail = false;
CAM_DBG(CAM_ICP, "CAM_ICP_IPE_CMD_RESET");
+ if (!core_info->clk_enable || !core_info->cpas_start) {
+ CAM_ERR(CAM_HFI, "IPE reset failed. clk_en %d cpas_start %d",
+ core_info->clk_enable, core_info->cpas_start);
+ return -EINVAL;
+ }
+
/* IPE CDM core reset*/
cam_io_w_mb((uint32_t)0xF,
soc_info->reg_map[0].mem_base + IPE_CDM_RST_CMD);
diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/cam_isp_context.c b/drivers/media/platform/msm/camera_v3/cam_isp/cam_isp_context.c
index 113e1a8d5298..e5bf1d5dff9b 100644
--- a/drivers/media/platform/msm/camera_v3/cam_isp/cam_isp_context.c
+++ b/drivers/media/platform/msm/camera_v3/cam_isp/cam_isp_context.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -139,6 +139,8 @@ static void cam_isp_ctx_dump_req(struct cam_isp_ctx_req *req_isp)
size_t len = 0;
uint32_t *buf_addr;
uint32_t *buf_start, *buf_end;
+ size_t remain_len = 0;
+ bool need_put = false;
for (i = 0; i < req_isp->num_cfg; i++) {
rc = cam_packet_util_get_cmd_mem_addr(
@@ -148,16 +150,27 @@ static void cam_isp_ctx_dump_req(struct cam_isp_ctx_req *req_isp)
"Failed to get_cmd_mem_addr, rc=%d",
rc);
} else {
+ if (req_isp->cfg[i].offset >= len) {
+ CAM_ERR(CAM_ISP, "Invalid offset");
+ need_put = true;
+ goto put;
+ }
+ remain_len = len - req_isp->cfg[i].offset;
+
+ if (req_isp->cfg[i].len > remain_len) {
+ CAM_ERR(CAM_ISP, "Invalid offset");
+ need_put = true;
+ }
+put:
+ if (need_put) {
+ need_put = false;
+ continue;
+ }
+
buf_start = (uint32_t *)((uint8_t *) buf_addr +
req_isp->cfg[i].offset);
buf_end = (uint32_t *)((uint8_t *) buf_start +
req_isp->cfg[i].len - 1);
- if (len < (buf_end - buf_start + 1)) {
- CAM_DBG(CAM_ISP,
- "Invalid len %zu, buf_start-end=%d",
- len, (buf_end - buf_start + 1));
- continue;
- }
cam_cdm_util_dump_cmd_buf(buf_start, buf_end);
}
}
@@ -427,10 +440,11 @@ static int __cam_isp_ctx_handle_buf_done_in_activated_state(
if (!req_isp->bubble_detected) {
CAM_INFO(CAM_ISP,
- "Sync with success: req %lld res 0x%x fd 0x%x",
+ "Sync with success: req %lld res 0x%x fd 0x%x, ctx %u",
req->request_id,
req_isp->fence_map_out[j].resource_handle,
- req_isp->fence_map_out[j].sync_id);
+ req_isp->fence_map_out[j].sync_id,
+ ctx->ctx_id);
rc = cam_sync_signal(req_isp->fence_map_out[j].sync_id,
CAM_SYNC_STATE_SIGNALED_SUCCESS);
@@ -438,11 +452,12 @@ static int __cam_isp_ctx_handle_buf_done_in_activated_state(
CAM_DBG(CAM_ISP, "Sync failed with rc = %d",
rc);
} else if (!req_isp->bubble_report) {
- CAM_INFO(CAM_ISP,
- "Sync with failure: req %lld res 0x%x fd 0x%x",
+ CAM_ERR(CAM_ISP,
+ "Sync with failure: req %lld res 0x%x fd 0x%x, ctx %u",
req->request_id,
req_isp->fence_map_out[j].resource_handle,
- req_isp->fence_map_out[j].sync_id);
+ req_isp->fence_map_out[j].sync_id,
+ ctx->ctx_id);
rc = cam_sync_signal(req_isp->fence_map_out[j].sync_id,
CAM_SYNC_STATE_SIGNALED_ERROR);
@@ -463,9 +478,9 @@ static int __cam_isp_ctx_handle_buf_done_in_activated_state(
continue;
}
- CAM_DBG(CAM_ISP, "req %lld, reset sync id 0x%x",
+ CAM_DBG(CAM_ISP, "req %lld, reset sync id 0x%x ctx %u",
req->request_id,
- req_isp->fence_map_out[j].sync_id);
+ req_isp->fence_map_out[j].sync_id, ctx->ctx_id);
if (!rc) {
req_isp->num_acked++;
req_isp->fence_map_out[j].sync_id = -1;
@@ -475,9 +490,9 @@ static int __cam_isp_ctx_handle_buf_done_in_activated_state(
if (req_isp->num_acked > req_isp->num_fence_map_out) {
/* Should not happen */
CAM_ERR(CAM_ISP,
- "WARNING: req_id %lld num_acked %d > map_out %d",
+ "WARNING: req_id %lld num_acked %d > map_out %d, ctx %u",
req->request_id, req_isp->num_acked,
- req_isp->num_fence_map_out);
+ req_isp->num_fence_map_out, ctx->ctx_id);
WARN_ON(req_isp->num_acked > req_isp->num_fence_map_out);
}
@@ -493,15 +508,15 @@ static int __cam_isp_ctx_handle_buf_done_in_activated_state(
list_add(&req->list, &ctx->pending_req_list);
CAM_DBG(CAM_REQ,
- "Move active request %lld to pending list(cnt = %d) [bubble recovery]",
- req->request_id, ctx_isp->active_req_cnt);
+ "Move active request %lld to pending list(cnt = %d) [bubble recovery], ctx %u",
+ req->request_id, ctx_isp->active_req_cnt, ctx->ctx_id);
} else {
list_del_init(&req->list);
list_add_tail(&req->list, &ctx->free_req_list);
CAM_DBG(CAM_REQ,
- "Move active request %lld to free list(cnt = %d) [all fences done]",
- req->request_id, ctx_isp->active_req_cnt);
+ "Move active request %lld to free list(cnt = %d) [all fences done], ctx %u",
+ req->request_id, ctx_isp->active_req_cnt, ctx->ctx_id);
}
end:
@@ -602,14 +617,15 @@ static int __cam_isp_ctx_reg_upd_in_activated_state(
if (req_isp->num_fence_map_out != 0) {
list_add_tail(&req->list, &ctx->active_req_list);
ctx_isp->active_req_cnt++;
- CAM_DBG(CAM_REQ, "move request %lld to active list(cnt = %d)",
- req->request_id, ctx_isp->active_req_cnt);
+ CAM_DBG(CAM_REQ,
+ "move request %lld to active list(cnt = %d), ctx %u",
+ req->request_id, ctx_isp->active_req_cnt, ctx->ctx_id);
} else {
/* no io config, so the request is completed. */
list_add_tail(&req->list, &ctx->free_req_list);
CAM_DBG(CAM_ISP,
- "move active request %lld to free list(cnt = %d)",
- req->request_id, ctx_isp->active_req_cnt);
+ "move active request %lld to free list(cnt = %d), ctx %u",
+ req->request_id, ctx_isp->active_req_cnt, ctx->ctx_id);
}
/*
@@ -650,8 +666,8 @@ static int __cam_isp_ctx_notify_sof_in_activated_state(
notify.trigger = CAM_TRIGGER_POINT_SOF;
ctx->ctx_crm_intf->notify_trigger(&notify);
- CAM_DBG(CAM_ISP, "Notify CRM SOF frame %lld",
- ctx_isp->frame_id);
+ CAM_DBG(CAM_ISP, "Notify CRM SOF frame %lld ctx %u",
+ ctx_isp->frame_id, ctx->ctx_id);
}
list_for_each_entry(req, &ctx->active_req_list, list) {
@@ -668,7 +684,9 @@ static int __cam_isp_ctx_notify_sof_in_activated_state(
__cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id,
CAM_REQ_MGR_SOF_EVENT_SUCCESS);
} else {
- CAM_ERR_RATE_LIMIT(CAM_ISP, "Can not notify SOF to CRM");
+ CAM_ERR_RATE_LIMIT(CAM_ISP,
+ "Can not notify SOF to CRM for ctx %u",
+ ctx->ctx_id);
rc = -EFAULT;
}
@@ -693,10 +711,11 @@ static int __cam_isp_ctx_notify_eof_in_activated_state(
notify.trigger = CAM_TRIGGER_POINT_EOF;
ctx->ctx_crm_intf->notify_trigger(&notify);
- CAM_DBG(CAM_ISP, "Notify CRM EOF frame %lld\n",
- ctx_isp->frame_id);
+ CAM_DBG(CAM_ISP, "Notify CRM EOF frame %lld ctx %u",
+ ctx_isp->frame_id, ctx->ctx_id);
} else {
- CAM_ERR(CAM_ISP, "Can not notify EOF to CRM");
+ CAM_ERR(CAM_ISP, "Can not notify EOF to CRM for ctx %u",
+ ctx->ctx_id);
rc = -EFAULT;
}
@@ -733,8 +752,8 @@ static int __cam_isp_ctx_sof_in_activated_state(
ctx_isp->boot_timestamp = sof_event_data->boot_time;
__cam_isp_ctx_update_state_monitor_array(ctx_isp,
CAM_ISP_STATE_CHANGE_TRIGGER_SOF, req->request_id);
- CAM_DBG(CAM_ISP, "frame id: %lld time stamp:0x%llx",
- ctx_isp->frame_id, ctx_isp->sof_timestamp_val);
+ CAM_DBG(CAM_ISP, "frame id: %lld time stamp:0x%llx, ctx %u",
+ ctx_isp->frame_id, ctx_isp->sof_timestamp_val, ctx->ctx_id);
CAM_INFO(CAM_ISP, "state = %s IRQ is SOF frame_id = %lld",
substate_name[ctx_isp->substate_activated], ctx_isp->frame_id);
@@ -820,8 +839,8 @@ static int __cam_isp_ctx_epoch_in_applied(struct cam_isp_context *ctx_isp,
notify.req_id = req->request_id;
notify.error = CRM_KMD_ERR_BUBBLE;
ctx->ctx_crm_intf->notify_err(&notify);
- CAM_DBG(CAM_ISP, "Notify CRM about Bubble frame %lld",
- ctx_isp->frame_id);
+ CAM_DBG(CAM_ISP, "Notify CRM about Bubble frame %lld, ctx %u",
+ ctx_isp->frame_id, ctx->ctx_id);
} else {
req_isp->bubble_report = 0;
}
@@ -830,8 +849,8 @@ static int __cam_isp_ctx_epoch_in_applied(struct cam_isp_context *ctx_isp,
* Always move the request to active list. Let buf done
* function handles the rest.
*/
- CAM_DBG(CAM_REQ, "move request %lld to active list(cnt = %d)",
- req->request_id, ctx_isp->active_req_cnt);
+ CAM_DBG(CAM_REQ, "move request %lld to active list(cnt = %d), ctx %u",
+ req->request_id, ctx_isp->active_req_cnt, ctx->ctx_id);
ctx_isp->active_req_cnt++;
list_del_init(&req->list);
list_add_tail(&req->list, &ctx->active_req_list);
@@ -882,7 +901,7 @@ static int __cam_isp_ctx_sof_in_epoch(struct cam_isp_context *ctx_isp,
struct cam_isp_hw_sof_event_data *sof_event_data = evt_data;
struct cam_ctx_request *req;
- CAM_INFO(CAM_ISP, "SURESH: state = %s IRQ is SOF frame_id = %lld",
+ CAM_INFO(CAM_ISP, "state = %s IRQ is SOF frame_id = %lld",
substate_name[ctx_isp->substate_activated], ctx_isp->frame_id);
if (!evt_data) {
@@ -979,8 +998,8 @@ static int __cam_isp_ctx_epoch_in_bubble_applied(
notify.error = CRM_KMD_ERR_BUBBLE;
ctx->ctx_crm_intf->notify_err(&notify);
CAM_DBG(CAM_REQ,
- "Notify CRM about Bubble req_id %llu frame %lld",
- req->request_id, ctx_isp->frame_id);
+ "Notify CRM about Bubble req_id %llu frame %lld, ctx %u",
+ req->request_id, ctx_isp->frame_id, ctx->ctx_id);
} else {
req_isp->bubble_report = 0;
}
@@ -989,7 +1008,7 @@ static int __cam_isp_ctx_epoch_in_bubble_applied(
* Always move the request to active list. Let buf done
* function handles the rest.
*/
- CAM_DBG(CAM_ISP, "move request %lld to active list(cnt = %d)",
+ CAM_DBG(CAM_ISP, "move request %lld to active list(cnt = %d) ctx %u",
req->request_id, ctx_isp->active_req_cnt);
ctx_isp->active_req_cnt++;
list_del_init(&req->list);
@@ -1050,6 +1069,7 @@ static int __cam_isp_ctx_handle_error(struct cam_isp_context *ctx_isp,
struct cam_req_mgr_error_notify notify;
uint64_t error_request_id = 0;
struct cam_hw_fence_map_entry *fence_map_out = NULL;
+ struct cam_req_mgr_message req_msg;
struct cam_context *ctx = ctx_isp->base;
struct cam_isp_hw_error_event_data *error_event_data =
@@ -1096,9 +1116,11 @@ static int __cam_isp_ctx_handle_error(struct cam_isp_context *ctx_isp,
for (i = 0; i < req_isp->num_fence_map_out; i++) {
fence_map_out =
&req_isp->fence_map_out[i];
- CAM_ERR(CAM_ISP, "req %llu, Sync fd %x",
+ CAM_ERR(CAM_ISP,
+ "req %llu, Sync fd 0x%x ctx %u",
req->request_id,
- req_isp->fence_map_out[i].sync_id);
+ req_isp->fence_map_out[i].sync_id,
+ ctx->ctx_id);
if (req_isp->fence_map_out[i].sync_id != -1) {
rc = cam_sync_signal(
fence_map_out->sync_id,
@@ -1125,9 +1147,11 @@ static int __cam_isp_ctx_handle_error(struct cam_isp_context *ctx_isp,
for (i = 0; i < req_isp->num_fence_map_out; i++) {
fence_map_out =
&req_isp->fence_map_out[i];
- CAM_ERR(CAM_ISP, "req %llu, Sync fd %x",
+ CAM_ERR(CAM_ISP,
+ "req %llu, Sync fd 0x%x ctx %u",
req->request_id,
- req_isp->fence_map_out[i].sync_id);
+ req_isp->fence_map_out[i].sync_id,
+ ctx->ctx_id);
if (req_isp->fence_map_out[i].sync_id != -1) {
rc = cam_sync_signal(
fence_map_out->sync_id,
@@ -1214,14 +1238,40 @@ end:
notify.error = CRM_KMD_ERR_FATAL;
}
- CAM_WARN(CAM_ISP, "Notify CRM: req %lld, frame %lld\n",
- error_request_id, ctx_isp->frame_id);
+ CAM_WARN(CAM_ISP, "Notify CRM: req %lld, frame %lld ctx %u",
+ error_request_id, ctx_isp->frame_id, ctx->ctx_id);
ctx->ctx_crm_intf->notify_err(&notify);
+
+ /*
+ * Need to send error occurred in KMD
+ * This will help UMD to take necessary action
+ * and to dump relevant info
+ */
+
+ if (notify.error == CRM_KMD_ERR_OVERFLOW) {
+ req_msg.session_hdl = ctx_isp->base->session_hdl;
+ req_msg.u.err_msg.device_hdl = ctx_isp->base->dev_hdl;
+ req_msg.u.err_msg.error_type =
+ CAM_REQ_MGR_ERROR_TYPE_RECOVERY;
+ req_msg.u.err_msg.link_hdl = ctx_isp->base->link_hdl;
+ req_msg.u.err_msg.request_id = error_request_id;
+ req_msg.u.err_msg.resource_size = 0x0;
+
+ if (cam_req_mgr_notify_message(&req_msg,
+ V4L_EVENT_CAM_REQ_MGR_ERROR,
+ V4L_EVENT_CAM_REQ_MGR_EVENT))
+ CAM_ERR(CAM_ISP,
+ "Error in notifying the error time for req id:%lld ctx %u",
+ ctx_isp->last_applied_req_id,
+ ctx->ctx_id);
+ }
ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_HW_ERROR;
CAM_INFO(CAM_ISP, "state changed to %s", substate_name[ctx_isp->substate_activated]);
} else {
- CAM_ERR_RATE_LIMIT(CAM_ISP, "Can not notify ERRROR to CRM");
+ CAM_ERR_RATE_LIMIT(CAM_ISP,
+ "Can not notify ERRROR to CRM for ctx %u",
+ ctx->ctx_id);
rc = -EFAULT;
}
@@ -1230,6 +1280,236 @@ end:
return rc;
}
+static int __cam_isp_ctx_fs2_sof_in_sof_state(
+ struct cam_isp_context *ctx_isp, void *evt_data)
+{
+ int rc = 0;
+ struct cam_isp_hw_sof_event_data *sof_event_data = evt_data;
+ struct cam_ctx_request *req;
+ struct cam_context *ctx = ctx_isp->base;
+ struct cam_req_mgr_trigger_notify notify;
+ uint64_t request_id = 0;
+
+
+ req = list_last_entry(&ctx->pending_req_list,
+ struct cam_ctx_request, list);
+
+ if (!evt_data) {
+ CAM_ERR(CAM_ISP, "in valid sof event data");
+ return -EINVAL;
+ }
+
+ ctx_isp->frame_id++;
+ ctx_isp->sof_timestamp_val = sof_event_data->timestamp;
+ ctx_isp->boot_timestamp = sof_event_data->boot_time;
+ __cam_isp_ctx_update_state_monitor_array(ctx_isp,
+ CAM_ISP_STATE_CHANGE_TRIGGER_SOF, req->request_id);
+ CAM_DBG(CAM_ISP, "frame id: %lld time stamp:0x%llx",
+ ctx_isp->frame_id, ctx_isp->sof_timestamp_val);
+
+ if (!(list_empty(&ctx->wait_req_list)))
+ goto end;
+
+ if (ctx->ctx_crm_intf && ctx->ctx_crm_intf->notify_trigger &&
+ ctx_isp->active_req_cnt <= 2) {
+ if (ctx_isp->subscribe_event & CAM_TRIGGER_POINT_SOF) {
+ notify.link_hdl = ctx->link_hdl;
+ notify.dev_hdl = ctx->dev_hdl;
+ notify.frame_id = ctx_isp->frame_id;
+ notify.trigger = CAM_TRIGGER_POINT_SOF;
+
+ ctx->ctx_crm_intf->notify_trigger(&notify);
+ CAM_DBG(CAM_ISP, "Notify CRM SOF frame %lld",
+ ctx_isp->frame_id);
+ }
+
+ list_for_each_entry(req, &ctx->active_req_list, list) {
+ if (req->request_id > ctx_isp->reported_req_id) {
+ request_id = req->request_id;
+ ctx_isp->reported_req_id = request_id;
+ break;
+ }
+ }
+
+ __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id,
+ CAM_REQ_MGR_SOF_EVENT_SUCCESS);
+ } else {
+ CAM_ERR_RATE_LIMIT(CAM_ISP, "Can not notify SOF to CRM");
+ rc = -EFAULT;
+ }
+
+end:
+ return rc;
+}
+
+static int __cam_isp_ctx_fs2_buf_done(struct cam_isp_context *ctx_isp,
+ void *evt_data)
+{
+ int rc = 0;
+ struct cam_isp_hw_done_event_data *done =
+ (struct cam_isp_hw_done_event_data *) evt_data;
+ struct cam_context *ctx = ctx_isp->base;
+ int prev_active_req_cnt = 0;
+ int curr_req_id = 0;
+ struct cam_ctx_request *req;
+
+ prev_active_req_cnt = ctx_isp->active_req_cnt;
+ req = list_first_entry(&ctx->active_req_list,
+ struct cam_ctx_request, list);
+ if (req)
+ curr_req_id = req->request_id;
+
+ rc = __cam_isp_ctx_handle_buf_done_in_activated_state(ctx_isp, done, 0);
+
+ if (prev_active_req_cnt == ctx_isp->active_req_cnt + 1) {
+ if (list_empty(&ctx->wait_req_list) &&
+ list_empty(&ctx->active_req_list)) {
+ CAM_DBG(CAM_ISP, "No request, move to SOF");
+ ctx_isp->substate_activated =
+ CAM_ISP_CTX_ACTIVATED_SOF;
+ if (ctx_isp->reported_req_id < curr_req_id) {
+ ctx_isp->reported_req_id = curr_req_id;
+ __cam_isp_ctx_send_sof_timestamp(ctx_isp,
+ curr_req_id,
+ CAM_REQ_MGR_SOF_EVENT_SUCCESS);
+ }
+ }
+ }
+
+ return rc;
+}
+
+static int __cam_isp_ctx_fs2_buf_done_in_epoch(struct cam_isp_context *ctx_isp,
+ void *evt_data)
+{
+ int rc = 0;
+
+ rc = __cam_isp_ctx_fs2_buf_done(ctx_isp, evt_data);
+ return rc;
+}
+
+static int __cam_isp_ctx_fs2_buf_done_in_applied(
+ struct cam_isp_context *ctx_isp,
+ void *evt_data)
+{
+ int rc = 0;
+
+ rc = __cam_isp_ctx_fs2_buf_done(ctx_isp, evt_data);
+ return rc;
+}
+
+static int __cam_isp_ctx_fs2_reg_upd_in_sof(struct cam_isp_context *ctx_isp,
+ void *evt_data)
+{
+ int rc = 0;
+ struct cam_ctx_request *req = NULL;
+ struct cam_isp_ctx_req *req_isp;
+ struct cam_context *ctx = ctx_isp->base;
+
+ if (ctx->state != CAM_CTX_ACTIVATED && ctx_isp->frame_id > 1) {
+ CAM_DBG(CAM_ISP, "invalid RUP");
+ goto end;
+ }
+
+ /*
+ * This is for the first update. The initial setting will
+ * cause the reg_upd in the first frame.
+ */
+ if (!list_empty(&ctx->wait_req_list)) {
+ req = list_first_entry(&ctx->wait_req_list,
+ struct cam_ctx_request, list);
+ list_del_init(&req->list);
+ req_isp = (struct cam_isp_ctx_req *) req->req_priv;
+ if (req_isp->num_fence_map_out == req_isp->num_acked)
+ list_add_tail(&req->list, &ctx->free_req_list);
+ else
+ CAM_ERR(CAM_ISP,
+ "receive rup in unexpected state");
+ }
+ if (req != NULL) {
+ __cam_isp_ctx_update_state_monitor_array(ctx_isp,
+ CAM_ISP_STATE_CHANGE_TRIGGER_REG_UPDATE,
+ req->request_id);
+ }
+end:
+ return rc;
+}
+
+static int __cam_isp_ctx_fs2_reg_upd_in_applied_state(
+ struct cam_isp_context *ctx_isp, void *evt_data)
+{
+ int rc = 0;
+ struct cam_ctx_request *req = NULL;
+ struct cam_context *ctx = ctx_isp->base;
+ struct cam_isp_ctx_req *req_isp;
+ struct cam_req_mgr_trigger_notify notify;
+ uint64_t request_id = 0;
+
+ if (list_empty(&ctx->wait_req_list)) {
+ CAM_ERR(CAM_ISP, "Reg upd ack with no waiting request");
+ goto end;
+ }
+ req = list_first_entry(&ctx->wait_req_list,
+ struct cam_ctx_request, list);
+ list_del_init(&req->list);
+
+ req_isp = (struct cam_isp_ctx_req *) req->req_priv;
+ if (req_isp->num_fence_map_out != 0) {
+ list_add_tail(&req->list, &ctx->active_req_list);
+ ctx_isp->active_req_cnt++;
+ CAM_DBG(CAM_REQ, "move request %lld to active list(cnt = %d)",
+ req->request_id, ctx_isp->active_req_cnt);
+ } else {
+ /* no io config, so the request is completed. */
+ list_add_tail(&req->list, &ctx->free_req_list);
+ }
+
+ /*
+ * This function only called directly from applied and bubble applied
+ * state so change substate here.
+ */
+ ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_EPOCH;
+ if (req_isp->num_fence_map_out != 1)
+ goto end;
+
+ if (ctx->ctx_crm_intf && ctx->ctx_crm_intf->notify_trigger &&
+ ctx_isp->active_req_cnt <= 2) {
+ list_for_each_entry(req, &ctx->active_req_list, list) {
+ if (req->request_id > ctx_isp->reported_req_id) {
+ request_id = req->request_id;
+ ctx_isp->reported_req_id = request_id;
+ break;
+ }
+ }
+
+ __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id,
+ CAM_REQ_MGR_SOF_EVENT_SUCCESS);
+
+ if (ctx_isp->subscribe_event & CAM_TRIGGER_POINT_SOF) {
+ notify.link_hdl = ctx->link_hdl;
+ notify.dev_hdl = ctx->dev_hdl;
+ notify.frame_id = ctx_isp->frame_id;
+ notify.trigger = CAM_TRIGGER_POINT_SOF;
+
+ ctx->ctx_crm_intf->notify_trigger(&notify);
+ CAM_DBG(CAM_ISP, "Notify CRM SOF frame %lld",
+ ctx_isp->frame_id);
+ }
+ } else {
+ CAM_ERR_RATE_LIMIT(CAM_ISP, "Can not notify SOF to CRM");
+ rc = -EFAULT;
+ }
+
+ CAM_DBG(CAM_ISP, "next substate %d", ctx_isp->substate_activated);
+end:
+ if (req != NULL && !rc) {
+ __cam_isp_ctx_update_state_monitor_array(ctx_isp,
+ CAM_ISP_STATE_CHANGE_TRIGGER_EPOCH,
+ req->request_id);
+ }
+ return rc;
+}
+
static struct cam_isp_ctx_irq_ops
cam_isp_ctx_activated_state_machine_irq[CAM_ISP_CTX_ACTIVATED_MAX] = {
/* SOF */
@@ -1303,6 +1583,79 @@ static struct cam_isp_ctx_irq_ops
},
};
+static struct cam_isp_ctx_irq_ops
+ cam_isp_ctx_fs2_state_machine_irq[CAM_ISP_CTX_ACTIVATED_MAX] = {
+ /* SOF */
+ {
+ .irq_ops = {
+ __cam_isp_ctx_handle_error,
+ __cam_isp_ctx_fs2_sof_in_sof_state,
+ __cam_isp_ctx_fs2_reg_upd_in_sof,
+ __cam_isp_ctx_fs2_sof_in_sof_state,
+ __cam_isp_ctx_notify_eof_in_activated_state,
+ NULL,
+ },
+ },
+ /* APPLIED */
+ {
+ .irq_ops = {
+ __cam_isp_ctx_handle_error,
+ __cam_isp_ctx_sof_in_activated_state,
+ __cam_isp_ctx_fs2_reg_upd_in_applied_state,
+ __cam_isp_ctx_epoch_in_applied,
+ __cam_isp_ctx_notify_eof_in_activated_state,
+ __cam_isp_ctx_fs2_buf_done_in_applied,
+ },
+ },
+ /* EPOCH */
+ {
+ .irq_ops = {
+ __cam_isp_ctx_handle_error,
+ __cam_isp_ctx_sof_in_epoch,
+ __cam_isp_ctx_reg_upd_in_epoch_state,
+ __cam_isp_ctx_notify_sof_in_activated_state,
+ __cam_isp_ctx_notify_eof_in_activated_state,
+ __cam_isp_ctx_fs2_buf_done_in_epoch,
+ },
+ },
+ /* BUBBLE */
+ {
+ .irq_ops = {
+ __cam_isp_ctx_handle_error,
+ __cam_isp_ctx_sof_in_activated_state,
+ NULL,
+ __cam_isp_ctx_notify_sof_in_activated_state,
+ __cam_isp_ctx_notify_eof_in_activated_state,
+ __cam_isp_ctx_buf_done_in_bubble,
+ },
+ },
+ /* Bubble Applied */
+ {
+ .irq_ops = {
+ __cam_isp_ctx_handle_error,
+ __cam_isp_ctx_sof_in_activated_state,
+ __cam_isp_ctx_reg_upd_in_activated_state,
+ __cam_isp_ctx_epoch_in_bubble_applied,
+ NULL,
+ __cam_isp_ctx_buf_done_in_bubble_applied,
+ },
+ },
+ /* HW ERROR */
+ {
+ .irq_ops = {
+ NULL,
+ __cam_isp_ctx_sof_in_activated_state,
+ __cam_isp_ctx_reg_upd_in_hw_error,
+ NULL,
+ NULL,
+ NULL,
+ },
+ },
+ /* HALT */
+ {
+ },
+};
+
static int __cam_isp_ctx_apply_req_in_activated_state(
struct cam_context *ctx, struct cam_req_mgr_apply_request *apply,
uint32_t next_state)
@@ -1347,15 +1700,16 @@ static int __cam_isp_ctx_apply_req_in_activated_state(
goto end;
}
- CAM_DBG(CAM_REQ, "Apply request %lld in substate %d", req->request_id,
- ctx_isp->substate_activated);
+ CAM_DBG(CAM_REQ, "Apply request %lld in substate %d ctx %u",
+ req->request_id, ctx_isp->substate_activated, ctx->ctx_id);
req_isp = (struct cam_isp_ctx_req *) req->req_priv;
if (ctx_isp->active_req_cnt >= 2) {
CAM_ERR_RATE_LIMIT(CAM_ISP,
- "Reject apply request (id %lld) due to congestion(cnt = %d)",
+ "Reject apply request (id %lld) due to congestion(cnt = %d) ctx %u",
req->request_id,
- ctx_isp->active_req_cnt);
+ ctx_isp->active_req_cnt,
+ ctx->ctx_id);
spin_lock_bh(&ctx->lock);
if (!list_empty(&ctx->active_req_list))
@@ -1664,6 +2018,58 @@ static struct cam_ctx_ops
},
};
+static struct cam_ctx_ops
+ cam_isp_ctx_fs2_state_machine[CAM_ISP_CTX_ACTIVATED_MAX] = {
+ /* SOF */
+ {
+ .ioctl_ops = {},
+ .crm_ops = {
+ .apply_req = __cam_isp_ctx_apply_req_in_sof,
+ },
+ .irq_ops = NULL,
+ },
+ /* APPLIED */
+ {
+ .ioctl_ops = {},
+ .crm_ops = {},
+ .irq_ops = NULL,
+ },
+ /* EPOCH */
+ {
+ .ioctl_ops = {},
+ .crm_ops = {
+ .apply_req = __cam_isp_ctx_apply_req_in_epoch,
+ },
+ .irq_ops = NULL,
+ },
+ /* BUBBLE */
+ {
+ .ioctl_ops = {},
+ .crm_ops = {
+ .apply_req = __cam_isp_ctx_apply_req_in_bubble,
+ },
+ .irq_ops = NULL,
+ },
+ /* Bubble Applied */
+ {
+ .ioctl_ops = {},
+ .crm_ops = {},
+ .irq_ops = NULL,
+ },
+ /* HW ERROR */
+ {
+ .ioctl_ops = {},
+ .crm_ops = {},
+ .irq_ops = NULL,
+ },
+ /* HALT */
+ {
+ .ioctl_ops = {},
+ .crm_ops = {},
+ .irq_ops = NULL,
+ },
+};
+
static int __cam_isp_ctx_rdi_only_sof_in_top_state(
struct cam_isp_context *ctx_isp, void *evt_data)
{
@@ -2244,6 +2650,7 @@ static int __cam_isp_ctx_config_dev_in_top_state(
uintptr_t packet_addr;
struct cam_packet *packet;
size_t len = 0;
+ size_t remain_len = 0;
struct cam_hw_prepare_update_args cfg;
struct cam_req_mgr_add_request add_req;
struct cam_isp_context *ctx_isp =
@@ -2278,6 +2685,14 @@ static int __cam_isp_ctx_config_dev_in_top_state(
goto free_req;
}
+ remain_len = len;
+ if ((len < sizeof(struct cam_packet)) ||
+ ((size_t)cmd->offset >= len - sizeof(struct cam_packet))) {
+ CAM_ERR(CAM_ISP, "invalid buff length: %zu or offset", len);
+ return -EINVAL;
+ }
+
+ remain_len -= (size_t)cmd->offset;
packet = (struct cam_packet *)(packet_addr + (uint32_t)cmd->offset);
CAM_DBG(CAM_ISP, "pack_handle %llx", cmd->packet_handle);
CAM_DBG(CAM_ISP, "packet address is 0x%zx", packet_addr);
@@ -2302,6 +2717,7 @@ static int __cam_isp_ctx_config_dev_in_top_state(
/* preprocess the configuration */
memset(&cfg, 0, sizeof(cfg));
cfg.packet = packet;
+ cfg.remain_len = remain_len;
cfg.ctxt_to_hw_map = ctx_isp->hw_ctx;
cfg.max_hw_update_entries = CAM_ISP_CTX_CFG_MAX;
cfg.hw_update_entries = req_isp->cfg;
@@ -2476,7 +2892,7 @@ static int __cam_isp_ctx_acquire_dev_in_available(struct cam_context *ctx,
/* Query the context has rdi only resource */
hw_cmd_args.ctxt_to_hw_map = param.ctxt_to_hw_map;
hw_cmd_args.cmd_type = CAM_HW_MGR_CMD_INTERNAL;
- isp_hw_cmd_args.cmd_type = CAM_ISP_HW_MGR_CMD_IS_RDI_ONLY_CONTEXT;
+ isp_hw_cmd_args.cmd_type = CAM_ISP_HW_MGR_CMD_CTX_TYPE;
hw_cmd_args.u.internal_args = (void *)&isp_hw_cmd_args;
rc = ctx->hw_mgr_intf->hw_cmd(ctx->hw_mgr_intf->hw_mgr_priv,
&hw_cmd_args);
@@ -2485,7 +2901,7 @@ static int __cam_isp_ctx_acquire_dev_in_available(struct cam_context *ctx,
goto free_hw;
}
- if (isp_hw_cmd_args.u.is_rdi_only_context) {
+ if (isp_hw_cmd_args.u.ctx_type == CAM_ISP_CTX_RDI) {
/*
* this context has rdi only resource assign rdi only
* state machine
@@ -2496,6 +2912,13 @@ static int __cam_isp_ctx_acquire_dev_in_available(struct cam_context *ctx,
cam_isp_ctx_rdi_only_activated_state_machine_irq;
ctx_isp->substate_machine =
cam_isp_ctx_rdi_only_activated_state_machine;
+ ctx_isp->rdi_only_context = true;
+ } else if (isp_hw_cmd_args.u.ctx_type == CAM_ISP_CTX_FS2) {
+ CAM_DBG(CAM_ISP, "FS2 Session has PIX ,RD and RDI");
+ ctx_isp->substate_machine_irq =
+ cam_isp_ctx_fs2_state_machine_irq;
+ ctx_isp->substate_machine =
+ cam_isp_ctx_fs2_state_machine;
} else {
CAM_DBG(CAM_ISP, "Session has PIX or PIX and RDI resources");
ctx_isp->substate_machine_irq =
@@ -2504,7 +2927,6 @@ static int __cam_isp_ctx_acquire_dev_in_available(struct cam_context *ctx,
cam_isp_ctx_activated_state_machine;
}
- ctx_isp->rdi_only_context = isp_hw_cmd_args.u.is_rdi_only_context;
ctx_isp->hw_ctx = param.ctxt_to_hw_map;
ctx_isp->hw_acquired = true;
ctx_isp->split_acquire = false;
@@ -2622,7 +3044,7 @@ static int __cam_isp_ctx_acquire_hw_v1(struct cam_context *ctx,
/* Query the context has rdi only resource */
hw_cmd_args.ctxt_to_hw_map = param.ctxt_to_hw_map;
hw_cmd_args.cmd_type = CAM_HW_MGR_CMD_INTERNAL;
- isp_hw_cmd_args.cmd_type = CAM_ISP_HW_MGR_CMD_IS_RDI_ONLY_CONTEXT;
+ isp_hw_cmd_args.cmd_type = CAM_ISP_HW_MGR_CMD_CTX_TYPE;
hw_cmd_args.u.internal_args = (void *)&isp_hw_cmd_args;
rc = ctx->hw_mgr_intf->hw_cmd(ctx->hw_mgr_intf->hw_mgr_priv,
&hw_cmd_args);
@@ -2631,7 +3053,7 @@ static int __cam_isp_ctx_acquire_hw_v1(struct cam_context *ctx,
goto free_hw;
}
- if (isp_hw_cmd_args.u.is_rdi_only_context) {
+ if (isp_hw_cmd_args.u.ctx_type == CAM_ISP_CTX_RDI) {
/*
* this context has rdi only resource assign rdi only
* state machine
@@ -2642,6 +3064,13 @@ static int __cam_isp_ctx_acquire_hw_v1(struct cam_context *ctx,
cam_isp_ctx_rdi_only_activated_state_machine_irq;
ctx_isp->substate_machine =
cam_isp_ctx_rdi_only_activated_state_machine;
+ ctx_isp->rdi_only_context = true;
+ } else if (isp_hw_cmd_args.u.ctx_type == CAM_ISP_CTX_FS2) {
+ CAM_DBG(CAM_ISP, "FS2 Session has PIX ,RD and RDI");
+ ctx_isp->substate_machine_irq =
+ cam_isp_ctx_fs2_state_machine_irq;
+ ctx_isp->substate_machine =
+ cam_isp_ctx_fs2_state_machine;
} else {
CAM_DBG(CAM_ISP, "Session has PIX or PIX and RDI resources");
ctx_isp->substate_machine_irq =
@@ -2650,16 +3079,14 @@ static int __cam_isp_ctx_acquire_hw_v1(struct cam_context *ctx,
cam_isp_ctx_activated_state_machine;
}
- ctx_isp->rdi_only_context = isp_hw_cmd_args.u.is_rdi_only_context;
ctx_isp->hw_ctx = param.ctxt_to_hw_map;
ctx_isp->hw_acquired = true;
ctx->ctxt_to_hw_map = param.ctxt_to_hw_map;
trace_cam_context_state("ISP", ctx);
CAM_DBG(CAM_ISP,
- "Acquire success on session_hdl 0x%xs RDI only %d ctx %u",
- ctx->session_hdl,
- (isp_hw_cmd_args.u.is_rdi_only_context ? 1 : 0), ctx->ctx_id);
+ "Acquire success on session_hdl 0x%xs ctx_type %d ctx_id %u",
+ ctx->session_hdl, isp_hw_cmd_args.u.ctx_type, ctx->ctx_id);
kfree(acquire_hw_info);
return rc;
diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c
index a6c96bd8929c..8957e6b1eaf5 100644
--- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c
+++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -1620,6 +1620,14 @@ static int cam_ife_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args)
/* acquire HW resources */
for (i = 0; i < acquire_hw_info->num_inputs; i++) {
+
+ if (in_port->num_out_res > CAM_IFE_HW_OUT_RES_MAX) {
+ CAM_ERR(CAM_ISP, "too many output res %d",
+ in_port->num_out_res);
+ rc = -EINVAL;
+ goto free_res;
+ }
+
in_port_length = sizeof(struct cam_isp_in_port_info) +
(in_port->num_out_res - 1) *
sizeof(struct cam_isp_out_port_info);
@@ -3131,6 +3139,7 @@ static int cam_isp_packet_generic_blob_handler(void *user_data,
CAM_ERR(CAM_ISP, "Clock Update Failed");
}
break;
+
default:
CAM_WARN(CAM_ISP, "Invalid blob type %d", blob_type);
break;
@@ -3166,7 +3175,8 @@ static int cam_ife_mgr_prepare_hw_update(void *hw_mgr_priv,
ctx = (struct cam_ife_hw_mgr_ctx *) prepare->ctxt_to_hw_map;
hw_mgr = (struct cam_ife_hw_mgr *)hw_mgr_priv;
- rc = cam_packet_util_validate_packet(prepare->packet);
+ rc = cam_packet_util_validate_packet(prepare->packet,
+ prepare->remain_len);
if (rc)
return rc;
@@ -3434,12 +3444,6 @@ static int cam_ife_mgr_cmd(void *hw_mgr_priv, void *cmd_args)
hw_cmd_args->u.internal_args;
switch (isp_hw_cmd_args->cmd_type) {
- case CAM_ISP_HW_MGR_CMD_IS_RDI_ONLY_CONTEXT:
- if (ctx->is_rdi_only_context)
- isp_hw_cmd_args->u.is_rdi_only_context = 1;
- else
- isp_hw_cmd_args->u.is_rdi_only_context = 0;
- break;
case CAM_ISP_HW_MGR_CMD_PAUSE_HW:
cam_ife_mgr_pause_hw(ctx);
break;
@@ -3450,6 +3454,14 @@ static int cam_ife_mgr_cmd(void *hw_mgr_priv, void *cmd_args)
cam_ife_mgr_sof_irq_debug(ctx,
isp_hw_cmd_args->u.sof_irq_enable);
break;
+ case CAM_ISP_HW_MGR_CMD_CTX_TYPE:
+ if (ctx->is_fe_enable)
+ isp_hw_cmd_args->u.ctx_type = CAM_ISP_CTX_FS2;
+ else if (ctx->is_rdi_only_context)
+ isp_hw_cmd_args->u.ctx_type = CAM_ISP_CTX_RDI;
+ else
+ isp_hw_cmd_args->u.ctx_type = CAM_ISP_CTX_PIX;
+ break;
default:
CAM_ERR(CAM_ISP, "Invalid HW mgr command:0x%x",
hw_cmd_args->cmd_type);
@@ -3861,16 +3873,17 @@ static int cam_ife_hw_mgr_handle_camif_error(
error_status = cam_ife_hw_mgr_get_err_type(ife_hwr_mgr_ctx,
evt_payload);
- if (atomic_read(&ife_hwr_mgr_ctx->overflow_pending))
- return error_status;
+ if (atomic_read(&ife_hwr_mgr_ctx->overflow_pending)) {
+ rc = error_status;
+ goto end;
+ }
switch (error_status) {
case CAM_ISP_HW_ERROR_OVERFLOW:
case CAM_ISP_HW_ERROR_P2I_ERROR:
case CAM_ISP_HW_ERROR_VIOLATION:
CAM_ERR(CAM_ISP, "Enter: error_type (%d)", error_status);
- rc = -EFAULT;
-
+ rc = error_status;
if (g_ife_hw_mgr.debug_cfg.enable_recovery)
error_event_data.recovery_enabled = true;
@@ -3897,6 +3910,7 @@ static int cam_ife_hw_mgr_handle_camif_error(
break;
}
+end:
return rc;
}
@@ -3999,7 +4013,8 @@ static int cam_ife_hw_mgr_handle_reg_update(
rup_status = hw_res->bottom_half_handler(
hw_res, evt_payload);
- if (!ife_hwr_mgr_ctx->is_rdi_only_context)
+ if (ife_hwr_mgr_ctx->is_rdi_only_context == 0 &&
+ ife_hwr_mgr_ctx->is_fe_enable == false)
continue;
if (atomic_read(&ife_hwr_mgr_ctx->overflow_pending))
@@ -4341,7 +4356,8 @@ static int cam_ife_hw_mgr_handle_sof(
hw_res, evt_payload);
/* check if it is rdi only context */
- if (ife_hw_mgr_ctx->is_rdi_only_context) {
+ if (ife_hw_mgr_ctx->is_fe_enable ||
+ ife_hw_mgr_ctx->is_rdi_only_context) {
if (!sof_status && !sof_sent) {
cam_ife_mgr_cmd_get_sof_timestamp(
ife_hw_mgr_ctx,
@@ -4352,7 +4368,7 @@ static int cam_ife_hw_mgr_handle_sof(
ife_hw_mgr_ctx->common.cb_priv,
CAM_ISP_HW_EVENT_SOF,
&sof_done_event_data);
- CAM_DBG(CAM_ISP, "sof_status = %d",
+ CAM_DBG(CAM_ISP, "RDI sof_status = %d",
sof_status);
sof_sent = true;
diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h
index cf1e425558f3..d8d318dc61bc 100644
--- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h
+++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -26,6 +26,7 @@ enum cam_ife_hw_mgr_res_type {
CAM_IFE_HW_MGR_RES_CID,
CAM_IFE_HW_MGR_RES_CSID,
CAM_IFE_HW_MGR_RES_IFE_SRC,
+ CAM_IFE_HW_MGR_RES_IFE_IN_RD,
CAM_IFE_HW_MGR_RES_IFE_OUT,
};
@@ -108,6 +109,7 @@ struct cam_ife_hw_mgr_debug {
* one.
* @res_list_csid: CSID resource list
* @res_list_ife_src: IFE input resource list
+ * @res_list_ife_in_rd IFE input resource list for read path
* @res_list_ife_out: IFE output resoruces array
* @free_res_list: Free resources list for the branch node
* @res_pool: memory storage for the free resource list
@@ -128,6 +130,7 @@ struct cam_ife_hw_mgr_debug {
* @is_rdi_only_context flag to specify the context has only rdi resource
* @config_done_complete indicator for configuration complete
* @init_done indicate whether init hw is done
+* @is_fe_enable indicate whether fetch engine\read path is enabled
*/
struct cam_ife_hw_mgr_ctx {
struct list_head list;
@@ -141,6 +144,7 @@ struct cam_ife_hw_mgr_ctx {
struct list_head res_list_ife_cid;
struct list_head res_list_ife_csid;
struct list_head res_list_ife_src;
+ struct list_head res_list_ife_in_rd;
struct cam_ife_hw_mgr_res res_list_ife_out[
CAM_IFE_HW_OUT_RES_MAX];
@@ -162,6 +166,7 @@ struct cam_ife_hw_mgr_ctx {
uint32_t is_rdi_only_context;
struct completion config_done_complete;
bool init_done;
+ bool is_fe_enable;
};
/**
diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c
index cd1d024148ff..5a04044cd7e5 100644
--- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c
+++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -105,7 +105,7 @@ static int cam_isp_update_dual_config(
struct cam_isp_hw_dual_isp_update_args dual_isp_update_args;
uint32_t outport_id;
uint32_t ports_plane_idx;
- size_t len = 0;
+ size_t len = 0, remain_len = 0;
uint32_t *cpu_addr;
uint32_t i, j;
@@ -117,9 +117,22 @@ static int cam_isp_update_dual_config(
if (rc)
return rc;
+ if ((len < sizeof(struct cam_isp_dual_config)) ||
+ (cmd_desc->offset >=
+ (len - sizeof(struct cam_isp_dual_config)))) {
+ CAM_ERR(CAM_UTIL, "not enough buffer provided");
+ return -EINVAL;
+ }
+ remain_len = len - cmd_desc->offset;
cpu_addr += (cmd_desc->offset / 4);
dual_config = (struct cam_isp_dual_config *)cpu_addr;
+ if ((dual_config->num_ports *
+ sizeof(struct cam_isp_dual_stripe_config)) >
+ (remain_len - offsetof(struct cam_isp_dual_config, stripes))) {
+ CAM_ERR(CAM_UTIL, "not enough buffer for all the dual configs");
+ return -EINVAL;
+ }
for (i = 0; i < dual_config->num_ports; i++) {
if (i >= CAM_ISP_IFE_OUT_RES_MAX) {
diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h
index 1a0f1ecab7b6..fad1d28b9a06 100644
--- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h
+++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -199,20 +199,28 @@ enum cam_isp_hw_mgr_command {
CAM_ISP_HW_MGR_CMD_PAUSE_HW,
CAM_ISP_HW_MGR_CMD_RESUME_HW,
CAM_ISP_HW_MGR_CMD_SOF_DEBUG,
+ CAM_ISP_HW_MGR_CMD_CTX_TYPE,
CAM_ISP_HW_MGR_CMD_MAX,
};
+enum cam_isp_ctx_type {
+ CAM_ISP_CTX_FS2 = 1,
+ CAM_ISP_CTX_RDI,
+ CAM_ISP_CTX_PIX,
+ CAM_ISP_CTX_MAX,
+};
/**
* struct cam_isp_hw_cmd_args - Payload for hw manager command
*
* @cmd_type HW command type
- * @get_context Get context type information
+ * @sof_irq_enable To debug if SOF irq is enabled
+ * @ctx_type RDI_ONLY, PIX and RDI, or FS2
*/
struct cam_isp_hw_cmd_args {
- uint32_t cmd_type;
+ uint32_t cmd_type;
union {
- uint32_t is_rdi_only_context;
uint32_t sof_irq_enable;
+ uint32_t ctx_type;
} u;
};
diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid170.h b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid170.h
index 85fec0f15dcd..876337945c8b 100644
--- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid170.h
+++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid170.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -273,6 +273,7 @@ static struct cam_ife_csid_common_reg_offset
.num_rdis = 3,
.num_pix = 1,
.num_ppp = 0,
+ .csid_reg_rst_stb = 1,
.csid_rst_stb = 0x1e,
.csid_rst_stb_sw_all = 0x1f,
.path_rst_stb_all = 0x7f,
diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c
index f3a15558bb1b..5c33469097ab 100644
--- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c
+++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -418,8 +418,23 @@ static int cam_ife_csid_global_reset(struct cam_ife_csid_hw *csid_hw)
cam_io_w_mb(0x2, soc_info->reg_map[0].mem_base +
csid_reg->rdi_reg[i]->csid_rdi_cfg0_addr);
- /* perform the top CSID HW and SW registers reset */
- cam_io_w_mb(csid_reg->cmn_reg->csid_rst_stb_sw_all,
+ /* perform the top CSID HW registers reset */
+ cam_io_w_mb(csid_reg->cmn_reg->csid_rst_stb,
+ soc_info->reg_map[0].mem_base +
+ csid_reg->cmn_reg->csid_rst_strobes_addr);
+
+ rc = readl_poll_timeout(soc_info->reg_map[0].mem_base +
+ csid_reg->cmn_reg->csid_top_irq_status_addr,
+ status, (status & 0x1) == 0x1,
+ CAM_IFE_CSID_TIMEOUT_SLEEP_US, CAM_IFE_CSID_TIMEOUT_ALL_US);
+ if (rc < 0) {
+ CAM_ERR(CAM_ISP, "CSID:%d csid_reset fail rc = %d",
+ csid_hw->hw_intf->hw_idx, rc);
+ rc = -ETIMEDOUT;
+ }
+
+ /* perform the SW registers reset */
+ cam_io_w_mb(csid_reg->cmn_reg->csid_reg_rst_stb,
soc_info->reg_map[0].mem_base +
csid_reg->cmn_reg->csid_rst_strobes_addr);
@@ -433,6 +448,7 @@ static int cam_ife_csid_global_reset(struct cam_ife_csid_hw *csid_hw)
rc = -ETIMEDOUT;
}
+ usleep_range(3000, 3010);
val = cam_io_r_mb(soc_info->reg_map[0].mem_base +
csid_reg->csi2_reg->csid_csi2_rx_irq_mask_addr);
if (val != 0)
@@ -1775,6 +1791,7 @@ static int cam_ife_csid_disable_pxl_path(
enum cam_ife_csid_halt_cmd stop_cmd)
{
int rc = 0;
+ uint32_t val = 0;
const struct cam_ife_csid_reg_offset *csid_reg;
struct cam_hw_soc_info *soc_info;
struct cam_ife_csid_path_cfg *path_data;
@@ -1835,6 +1852,17 @@ static int cam_ife_csid_disable_pxl_path(
cam_io_w_mb(0, soc_info->reg_map[0].mem_base +
pxl_reg->csid_pxl_irq_mask_addr);
+ if (path_data->sync_mode == CAM_ISP_HW_SYNC_MASTER ||
+ path_data->sync_mode == CAM_ISP_HW_SYNC_NONE) {
+ /* configure Halt */
+ val = cam_io_r_mb(soc_info->reg_map[0].mem_base +
+ pxl_reg->csid_pxl_ctrl_addr);
+ val &= ~0x3;
+ val |= stop_cmd;
+ cam_io_w_mb(val, soc_info->reg_map[0].mem_base +
+ pxl_reg->csid_pxl_ctrl_addr);
+ }
+
return rc;
}
@@ -2083,7 +2111,7 @@ static int cam_ife_csid_disable_rdi_path(
enum cam_ife_csid_halt_cmd stop_cmd)
{
int rc = 0;
- uint32_t id;
+ uint32_t id, val = 0;
const struct cam_ife_csid_reg_offset *csid_reg;
struct cam_hw_soc_info *soc_info;
@@ -2128,6 +2156,62 @@ static int cam_ife_csid_disable_rdi_path(
cam_io_w_mb(0, soc_info->reg_map[0].mem_base +
csid_reg->rdi_reg[id]->csid_rdi_irq_mask_addr);
+ /* Halt the RDI path */
+ val = cam_io_r_mb(soc_info->reg_map[0].mem_base +
+ csid_reg->rdi_reg[id]->csid_rdi_ctrl_addr);
+ val &= ~0x3;
+ val |= stop_cmd;
+ cam_io_w_mb(val, soc_info->reg_map[0].mem_base +
+ csid_reg->rdi_reg[id]->csid_rdi_ctrl_addr);
+
+ return rc;
+}
+
+static int cam_ife_csid_poll_stop_status(
+ struct cam_ife_csid_hw *csid_hw,
+ uint32_t res_mask)
+{
+ int rc = 0;
+ uint32_t csid_status_addr = 0, val = 0, res_id = 0;
+ const struct cam_ife_csid_reg_offset *csid_reg;
+ struct cam_hw_soc_info *soc_info;
+
+ csid_reg = csid_hw->csid_info->csid_reg;
+ soc_info = &csid_hw->hw_info->soc_info;
+
+ for (; res_id < CAM_IFE_PIX_PATH_RES_MAX; res_id++, res_mask >>= 1) {
+ if ((res_mask & 0x1) == 0)
+ continue;
+ val = 0;
+
+ if (res_id == CAM_IFE_PIX_PATH_RES_IPP) {
+ csid_status_addr =
+ csid_reg->ipp_reg->csid_pxl_status_addr;
+ } else if (res_id == CAM_IFE_PIX_PATH_RES_PPP) {
+ csid_status_addr =
+ csid_reg->ppp_reg->csid_pxl_status_addr;
+ } else {
+ csid_status_addr =
+ csid_reg->rdi_reg[res_id]->csid_rdi_status_addr;
+ }
+
+ CAM_DBG(CAM_ISP, "start polling CSID:%d res_id:%d",
+ csid_hw->hw_intf->hw_idx, res_id);
+
+ rc = readl_poll_timeout(soc_info->reg_map[0].mem_base +
+ csid_status_addr, val, (val & 0x1) == 0x1,
+ CAM_IFE_CSID_TIMEOUT_SLEEP_US,
+ CAM_IFE_CSID_TIMEOUT_ALL_US);
+ if (rc < 0) {
+ CAM_ERR(CAM_ISP, "CSID:%d res:%d halt failed rc %d",
+ csid_hw->hw_intf->hw_idx, res_id, rc);
+ rc = -ETIMEDOUT;
+ break;
+ }
+ CAM_DBG(CAM_ISP, "End polling CSID:%d res_id:%d",
+ csid_hw->hw_intf->hw_idx, res_id);
+ }
+
return rc;
}
@@ -2705,6 +2789,7 @@ static int cam_ife_csid_stop(void *hw_priv,
struct cam_isp_resource_node *res;
struct cam_csid_hw_stop_args *csid_stop;
uint32_t i;
+ uint32_t res_mask = 0;
if (!hw_priv || !stop_args ||
(arg_size != sizeof(struct cam_csid_hw_stop_args))) {
@@ -2736,6 +2821,7 @@ static int cam_ife_csid_stop(void *hw_priv,
rc = cam_ife_csid_tpg_stop(csid_hw, res);
break;
case CAM_ISP_RESOURCE_PIX_PATH:
+ res_mask |= (1 << res->res_id);
if (res->res_id == CAM_IFE_PIX_PATH_RES_IPP ||
res->res_id == CAM_IFE_PIX_PATH_RES_PPP)
rc = cam_ife_csid_disable_pxl_path(csid_hw,
@@ -2753,6 +2839,9 @@ static int cam_ife_csid_stop(void *hw_priv,
}
}
+ if (res_mask)
+ rc = cam_ife_csid_poll_stop_status(csid_hw, res_mask);
+
for (i = 0; i < csid_stop->num_res; i++) {
res = csid_stop->node_res[i];
res->res_state = CAM_ISP_RESOURCE_STATE_INIT_HW;
diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h
index 43fd9b03132e..e5980ab854f9 100644
--- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h
+++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -274,6 +274,7 @@ struct cam_ife_csid_common_reg_offset {
uint32_t num_rdis;
uint32_t num_pix;
uint32_t num_ppp;
+ uint32_t csid_reg_rst_stb;
uint32_t csid_rst_stb;
uint32_t csid_rst_stb_sw_all;
uint32_t path_rst_stb_all;
diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.c b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.c
index 12b7a03c6276..5490cb3fb2be 100644
--- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.c
+++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -26,6 +26,8 @@ static bool cam_vfe_cpas_cb(uint32_t client_handle, void *userdata,
switch (irq_data->irq_type) {
case CAM_CAMNOC_IRQ_IFE02_UBWC_ENCODE_ERROR:
case CAM_CAMNOC_IRQ_IFE13_UBWC_ENCODE_ERROR:
+ case CAM_CAMNOC_IRQ_IFE0_UBWC_ENCODE_ERROR:
+ case CAM_CAMNOC_IRQ_IFE1_WRITE_UBWC_ENCODE_ERROR:
CAM_ERR_RATE_LIMIT(CAM_ISP,
"IFE UBWC Encode error type=%d status=%x",
irq_data->irq_type,
@@ -115,20 +117,56 @@ int cam_vfe_init_soc_resources(struct cam_hw_soc_info *soc_info,
}
memset(&cpas_register_param, 0, sizeof(cpas_register_param));
- strlcpy(cpas_register_param.identifier, "ife",
- CAM_HW_IDENTIFIER_LENGTH);
+
cpas_register_param.cell_index = soc_info->index;
cpas_register_param.dev = soc_info->dev;
cpas_register_param.cam_cpas_client_cb = cam_vfe_cpas_cb;
cpas_register_param.userdata = soc_info;
- rc = cam_cpas_register_client(&cpas_register_param);
+
+ rc = cam_cpas_get_cpas_hw_version(&soc_private->cpas_version);
if (rc) {
- CAM_ERR(CAM_ISP, "CPAS registration failed rc=%d", rc);
- goto release_soc;
- } else {
- soc_private->cpas_handle = cpas_register_param.client_handle;
+ CAM_ERR(CAM_ISP, "Error! Invalid cpas version rc=%d", rc);
+ goto free_soc_private;
}
+ switch (soc_private->cpas_version) {
+ case CAM_CPAS_TITAN_175_V120:
+ strlcpy(cpas_register_param.identifier, "iferdi",
+ CAM_HW_IDENTIFIER_LENGTH);
+ rc = cam_cpas_register_client(&cpas_register_param);
+ if (rc) {
+ CAM_ERR(CAM_ISP, "rdi CPAS registration failed rc=%d",
+ rc);
+ goto release_soc;
+ } else {
+ soc_private->cpas_handle[0] =
+ cpas_register_param.client_handle;
+ }
+
+ strlcpy(cpas_register_param.identifier, "ifenrdi",
+ CAM_HW_IDENTIFIER_LENGTH);
+ rc = cam_cpas_register_client(&cpas_register_param);
+ if (rc) {
+ CAM_ERR(CAM_ISP, "nrdi CPAS registration failed rc=%d",
+ rc);
+ goto release_soc;
+ } else {
+ soc_private->cpas_handle[1] =
+ cpas_register_param.client_handle;
+ }
+ break;
+ default:
+ strlcpy(cpas_register_param.identifier, "ife",
+ CAM_HW_IDENTIFIER_LENGTH);
+ rc = cam_cpas_register_client(&cpas_register_param);
+ if (rc) {
+ CAM_ERR(CAM_ISP, "CPAS registration failed rc=%d", rc);
+ goto release_soc;
+ } else {
+ soc_private->cpas_handle[0] =
+ cpas_register_param.client_handle;
+ }
+ }
return rc;
release_soc:
@@ -154,10 +192,15 @@ int cam_vfe_deinit_soc_resources(struct cam_hw_soc_info *soc_info)
CAM_ERR(CAM_ISP, "Error! soc_private NULL");
return -ENODEV;
}
-
- rc = cam_cpas_unregister_client(soc_private->cpas_handle);
+ rc = cam_cpas_unregister_client(soc_private->cpas_handle[0]);
if (rc)
- CAM_ERR(CAM_ISP, "CPAS unregistration failed rc=%d", rc);
+ CAM_ERR(CAM_ISP, "CPAS0 unregistration failed rc=%d", rc);
+
+ if (!rc && soc_private->cpas_version == CAM_CPAS_TITAN_175_V120)
+ rc = cam_cpas_unregister_client(soc_private->cpas_handle[1]);
+ if (rc)
+ CAM_ERR(CAM_ISP, "CPAS1 unregistration failed rc=%d",
+ rc);
rc = cam_vfe_release_platform_resource(soc_info);
if (rc < 0)
@@ -194,13 +237,22 @@ int cam_vfe_enable_soc_resources(struct cam_hw_soc_info *soc_info)
axi_vote.compressed_bw = 10640000000L;
axi_vote.uncompressed_bw = 10640000000L;
- rc = cam_cpas_start(soc_private->cpas_handle, &ahb_vote, &axi_vote);
+ rc = cam_cpas_start(soc_private->cpas_handle[0], &ahb_vote, &axi_vote);
if (rc) {
- CAM_ERR(CAM_ISP, "Error! CPAS start failed rc=%d", rc);
+ CAM_ERR(CAM_ISP, "Error! CPAS0 start failed rc=%d", rc);
rc = -EFAULT;
goto end;
}
+ if (!rc && soc_private->cpas_version == CAM_CPAS_TITAN_175_V120)
+ rc = cam_cpas_start(soc_private->cpas_handle[1], &ahb_vote,
+ &axi_vote);
+ if (rc) {
+ CAM_ERR(CAM_ISP, "Error! CPAS1 start failed rc=%d", rc);
+ rc = -EFAULT;
+ goto end;
+ }
+
rc = cam_soc_util_enable_platform_resource(soc_info, true,
CAM_TURBO_VOTE, true);
if (rc) {
@@ -211,7 +263,9 @@ int cam_vfe_enable_soc_resources(struct cam_hw_soc_info *soc_info)
return rc;
stop_cpas:
- cam_cpas_stop(soc_private->cpas_handle);
+ cam_cpas_stop(soc_private->cpas_handle[0]);
+ if (soc_private->cpas_version == CAM_CPAS_TITAN_175_V120)
+ cam_cpas_stop(soc_private->cpas_handle[1]);
end:
return rc;
}
@@ -283,11 +337,18 @@ int cam_vfe_disable_soc_resources(struct cam_hw_soc_info *soc_info)
return rc;
}
- rc = cam_cpas_stop(soc_private->cpas_handle);
+ rc = cam_cpas_stop(soc_private->cpas_handle[0]);
if (rc) {
CAM_ERR(CAM_ISP, "Error! CPAS stop failed rc=%d", rc);
return rc;
}
+ if (!rc && soc_private->cpas_version == CAM_CPAS_TITAN_175_V120)
+ rc = cam_cpas_stop(soc_private->cpas_handle[1]);
+ if (rc) {
+ CAM_ERR(CAM_ISP, "Error! CPAS stop failed rc=%d", rc);
+ return rc;
+ }
+
return rc;
}
diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.h b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.h
index 3f862e9249f8..780bd34ab968 100644
--- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.h
+++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -18,6 +18,12 @@
#define CAM_VFE_DSP_CLK_NAME "ife_dsp_clk"
+enum cam_cpas_handle_id {
+ CAM_CPAS_HANDLE_CAMIF,
+ CAM_CPAS_HANDLE_RAW,
+ CAM_CPAS_HANDLE_MAX,
+};
+
/*
* struct cam_vfe_soc_private:
*
@@ -26,9 +32,11 @@
* @cpas_handle: Handle returned on registering with CPAS driver.
* This handle is used for all further interface
* with CPAS.
+ * @cpas_version: Has cpas version read from Hardware
*/
struct cam_vfe_soc_private {
- uint32_t cpas_handle;
+ uint32_t cpas_handle[CAM_CPAS_HANDLE_MAX];
+ uint32_t cpas_version;
struct clk *dsp_clk;
int32_t dsp_clk_index;
int32_t dsp_clk_rate;
diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c
index 95bed8d9d23c..ba0e95188b46 100644
--- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c
+++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -212,8 +212,7 @@ static int cam_vfe_camif_resource_start(
uint32_t epoch0_irq_mask;
uint32_t epoch1_irq_mask;
uint32_t computed_epoch_line_cfg;
- uint32_t camera_hw_version = 0;
- int rc = 0;
+ struct cam_vfe_soc_private *soc_private;
if (!camif_res) {
CAM_ERR(CAM_ISP, "Error! Invalid input arguments");
@@ -228,6 +227,13 @@ static int cam_vfe_camif_resource_start(
rsrc_data = (struct cam_vfe_mux_camif_data *)camif_res->res_priv;
+ soc_private = rsrc_data->soc_info->soc_private;
+
+ if (!soc_private) {
+ CAM_ERR(CAM_ISP, "Error! soc_private NULL");
+ return -ENODEV;
+ }
+
/*config vfe core*/
val = (rsrc_data->pix_pattern <<
rsrc_data->reg_data->pixel_pattern_shift);
@@ -253,16 +259,8 @@ static int cam_vfe_camif_resource_start(
rsrc_data->common_reg->module_ctrl[
CAM_VFE_TOP_VER2_MODULE_STATS]->cgc_ovd);
- /* get the HW version */
- rc = cam_cpas_get_cpas_hw_version(&camera_hw_version);
-
- if (rc) {
- CAM_ERR(CAM_ISP, "Couldn't find HW version. rc: %d", rc);
- return rc;
- }
-
/* epoch config */
- switch (camera_hw_version) {
+ switch (soc_private->cpas_version) {
case CAM_CPAS_TITAN_170_V100:
case CAM_CPAS_TITAN_170_V110:
case CAM_CPAS_TITAN_170_V120:
@@ -316,27 +314,16 @@ static int cam_vfe_camif_resource_start(
}
static int cam_vfe_camif_reg_dump(
- struct cam_isp_resource_node *camif_res)
+ struct cam_vfe_mux_camif_data *camif_priv)
{
- struct cam_vfe_mux_camif_data *camif_priv;
- struct cam_vfe_soc_private *soc_private;
- int rc = 0, i;
- uint32_t val = 0;
+ uint32_t val = 0, wm_idx, offset;
+ int i = 0;
- if (!camif_res) {
- CAM_ERR(CAM_ISP, "Error! Invalid input arguments");
- return -EINVAL;
- }
-
- if ((camif_res->res_state == CAM_ISP_RESOURCE_STATE_RESERVED) ||
- (camif_res->res_state == CAM_ISP_RESOURCE_STATE_AVAILABLE))
- return 0;
-
- camif_priv = (struct cam_vfe_mux_camif_data *)camif_res->res_priv;
- soc_private = camif_priv->soc_info->soc_private;
- for (i = 0xA3C; i <= 0xA90; i += 4) {
- val = cam_io_r_mb(camif_priv->mem_base + i);
- CAM_INFO(CAM_ISP, "offset 0x%x val 0x%x", i, val);
+ for (i = 0xA3C; i <= 0xA90; i += 8) {
+ CAM_INFO(CAM_ISP,
+ "SCALING offset 0x%x val 0x%x offset 0x%x val 0x%x",
+ i, cam_io_r_mb(camif_priv->mem_base + i), i + 4,
+ cam_io_r_mb(camif_priv->mem_base + i + 4));
}
for (i = 0xE0C; i <= 0xE3C; i += 4) {
@@ -344,64 +331,96 @@ static int cam_vfe_camif_reg_dump(
CAM_INFO(CAM_ISP, "offset 0x%x val 0x%x", i, val);
}
- for (i = 0x2000; i <= 0x20B8; i += 4) {
- val = cam_io_r_mb(camif_priv->mem_base + i);
- CAM_INFO(CAM_ISP, "offset 0x%x val 0x%x", i, val);
- }
-
- for (i = 0x2500; i <= 0x255C; i += 4) {
- val = cam_io_r_mb(camif_priv->mem_base + i);
- CAM_INFO(CAM_ISP, "offset 0x%x val 0x%x", i, val);
- }
-
- for (i = 0x2600; i <= 0x265C; i += 4) {
- val = cam_io_r_mb(camif_priv->mem_base + i);
- CAM_INFO(CAM_ISP, "offset 0x%x val 0x%x", i, val);
+ for (wm_idx = 0; wm_idx <= 23; wm_idx++) {
+ offset = 0x2214 + 0x100 * wm_idx;
+ CAM_INFO(CAM_ISP,
+ "BUS_WM%u offset 0x%x val 0x%x offset 0x%x val 0x%x",
+ wm_idx, offset,
+ cam_io_r_mb(camif_priv->mem_base + offset),
+ offset + 4, cam_io_r_mb(camif_priv->mem_base +
+ offset + 4));
+ CAM_INFO(CAM_ISP,
+ "offset+8 0x%x val+8 0x%x offset+12 0x%x val+12 0x%x",
+ offset + 8,
+ cam_io_r_mb(camif_priv->mem_base + offset + 8),
+ offset + 12, cam_io_r_mb(camif_priv->mem_base +
+ offset + 12));
}
- cam_cpas_reg_read(soc_private->cpas_handle,
- CAM_CPAS_REG_CAMNOC, 0x420, true, &val);
- CAM_INFO(CAM_ISP, "IFE02_MAXWR_LOW offset 0x420 val 0x%x", val);
+ offset = 0x420;
+ val = cam_soc_util_r(camif_priv->soc_info, 1, offset);
+ CAM_INFO(CAM_ISP, "CAMNOC IFE02 MaxWR_LOW offset 0x%x value 0x%x",
+ offset, val);
- cam_cpas_reg_read(soc_private->cpas_handle,
- CAM_CPAS_REG_CAMNOC, 0x820, true, &val);
- CAM_INFO(CAM_ISP, "IFE13_MAXWR_LOW offset 0x820 val 0x%x", val);
+ offset = 0x820;
+ val = cam_soc_util_r(camif_priv->soc_info, 1, offset);
+ CAM_INFO(CAM_ISP, "CAMNOC IFE13 MaxWR_LOW offset 0x%x value 0x%x",
+ offset, val);
- return rc;
+ return 0;
}
-static int cam_vfe_camif_reg_dump_bh(struct cam_vfe_mux_camif_data *camif_priv)
+static int cam_vfe_camif_reg_dump_bh(
+ struct cam_isp_resource_node *camif_res)
{
+ struct cam_vfe_mux_camif_data *camif_priv;
+ struct cam_vfe_soc_private *soc_private;
uint32_t offset, val, wm_idx;
+ if (!camif_res) {
+ CAM_ERR(CAM_ISP, "Error! Invalid input arguments");
+ return -EINVAL;
+ }
+
+ if ((camif_res->res_state == CAM_ISP_RESOURCE_STATE_RESERVED) ||
+ (camif_res->res_state == CAM_ISP_RESOURCE_STATE_AVAILABLE))
+ return 0;
+
+ camif_priv = (struct cam_vfe_mux_camif_data *)camif_res->res_priv;
for (offset = 0x0; offset < 0x1000; offset += 0x4) {
val = cam_soc_util_r(camif_priv->soc_info, 0, offset);
- CAM_INFO(CAM_ISP, "offset 0x%x value 0x%x", offset, val);
+ CAM_DBG(CAM_ISP, "offset 0x%x value 0x%x", offset, val);
}
for (offset = 0x2000; offset <= 0x20B8; offset += 0x4) {
val = cam_soc_util_r(camif_priv->soc_info, 0, offset);
- CAM_INFO(CAM_ISP, "offset 0x%x value 0x%x", offset, val);
+ CAM_DBG(CAM_ISP, "offset 0x%x value 0x%x", offset, val);
}
for (wm_idx = 0; wm_idx <= 23; wm_idx++) {
for (offset = 0x2200 + 0x100 * wm_idx;
offset < 0x2278 + 0x100 * wm_idx; offset += 0x4) {
val = cam_soc_util_r(camif_priv->soc_info, 0, offset);
- CAM_INFO(CAM_ISP,
+ CAM_DBG(CAM_ISP,
"offset 0x%x value 0x%x", offset, val);
}
}
- offset = 0x420;
- val = cam_soc_util_r(camif_priv->soc_info, 1, offset);
- CAM_INFO(CAM_ISP, "CAMNOC IFE02 MaxWR_LOW offset 0x%x value 0x%x",
- offset, val);
-
- offset = 0x820;
- val = cam_soc_util_r(camif_priv->soc_info, 1, offset);
- CAM_INFO(CAM_ISP, "CAMNOC IFE13 MaxWR_LOW offset 0x%x value 0x%x",
- offset, val);
+ soc_private = camif_priv->soc_info->soc_private;
+ if (soc_private->cpas_version == CAM_CPAS_TITAN_175_V120) {
+ cam_cpas_reg_read(soc_private->cpas_handle[0],
+ CAM_CPAS_REG_CAMNOC, 0x3A20, true, &val);
+ CAM_DBG(CAM_ISP, "IFE0_nRDI_MAXWR_LOW offset 0x3A20 val 0x%x",
+ val);
+
+ cam_cpas_reg_read(soc_private->cpas_handle[0],
+ CAM_CPAS_REG_CAMNOC, 0x5420, true, &val);
+ CAM_DBG(CAM_ISP, "IFE1_nRDI_MAXWR_LOW offset 0x5420 val 0x%x",
+ val);
+
+ cam_cpas_reg_read(soc_private->cpas_handle[1],
+ CAM_CPAS_REG_CAMNOC, 0x3620, true, &val);
+ CAM_DBG(CAM_ISP,
+ "IFE0123_RDI_WR_MAXWR_LOW offset 0x3620 val 0x%x", val);
+ } else {
+ cam_cpas_reg_read(soc_private->cpas_handle[0],
+ CAM_CPAS_REG_CAMNOC, 0x420, true, &val);
+ CAM_DBG(CAM_ISP, "IFE02_MAXWR_LOW offset 0x420 val 0x%x", val);
+
+ cam_cpas_reg_read(soc_private->cpas_handle[0],
+ CAM_CPAS_REG_CAMNOC, 0x820, true, &val);
+ CAM_DBG(CAM_ISP, "IFE13_MAXWR_LOW offset 0x820 val 0x%x", val);
+ }
return 0;
}
@@ -483,7 +502,7 @@ static int cam_vfe_camif_process_cmd(struct cam_isp_resource_node *rsrc_node,
arg_size);
break;
case CAM_ISP_HW_CMD_GET_REG_DUMP:
- rc = cam_vfe_camif_reg_dump(rsrc_node);
+ rc = cam_vfe_camif_reg_dump_bh(rsrc_node);
break;
case CAM_ISP_HW_CMD_SOF_IRQ_DEBUG:
rc = cam_vfe_camif_sof_irq_debug(rsrc_node, cmd_args);
@@ -576,8 +595,7 @@ static int cam_vfe_camif_handle_irq_bottom_half(void *handler_priv,
if (irq_status1 & camif_priv->reg_data->error_irq_mask1) {
CAM_DBG(CAM_ISP, "Received ERROR\n");
ret = CAM_ISP_HW_ERROR_OVERFLOW;
- cam_vfe_camif_reg_dump(camif_node);
- cam_vfe_camif_reg_dump_bh(camif_node->res_priv);
+ cam_vfe_camif_reg_dump(camif_node->res_priv);
} else {
ret = CAM_ISP_HW_ERROR_NONE;
}
diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c
index f54f52af5334..83c80c1e0f69 100644
--- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c
+++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -37,11 +37,13 @@ struct cam_vfe_top_ver2_priv {
struct cam_axi_vote applied_axi_vote;
struct cam_axi_vote req_axi_vote[CAM_VFE_TOP_VER2_MUX_MAX];
unsigned long req_clk_rate[CAM_VFE_TOP_VER2_MUX_MAX];
- struct cam_axi_vote last_vote[CAM_VFE_TOP_VER2_MUX_MAX *
+ struct cam_axi_vote last_vote[CAM_CPAS_HANDLE_MAX]
+ [CAM_VFE_TOP_VER2_MUX_MAX *
CAM_VFE_DELAY_BW_REDUCTION_NUM_FRAMES];
- uint32_t last_counter;
+ uint32_t last_counter[CAM_CPAS_HANDLE_MAX];
enum cam_vfe_bw_control_action
axi_vote_control[CAM_VFE_TOP_VER2_MUX_MAX];
+ enum cam_cpas_handle_id cpashdl_type[CAM_VFE_TOP_VER2_MUX_MAX];
};
static int cam_vfe_top_mux_get_base(struct cam_vfe_top_ver2_priv *top_priv,
@@ -133,96 +135,115 @@ static int cam_vfe_top_set_axi_bw_vote(
struct cam_vfe_soc_private *soc_private =
soc_info->soc_private;
bool apply_bw_update = false;
+ enum cam_cpas_handle_id cpashdl_type;
+ struct cam_axi_vote *last_vote = NULL;
if (!soc_private) {
CAM_ERR(CAM_ISP, "Error soc_private NULL");
return -EINVAL;
}
- for (i = 0; i < CAM_VFE_TOP_VER2_MUX_MAX; i++) {
- if (top_priv->axi_vote_control[i] ==
- CAM_VFE_BW_CONTROL_INCLUDE) {
- sum.uncompressed_bw +=
+ for (cpashdl_type = 0; cpashdl_type < CAM_CPAS_HANDLE_MAX;
+ cpashdl_type++) {
+
+ if ((soc_private->cpas_version != CAM_CPAS_TITAN_175_V120)
+ && cpashdl_type)
+ continue;
+
+ sum.uncompressed_bw = sum.compressed_bw = 0;
+ to_be_applied_axi_vote.uncompressed_bw = 0;
+ to_be_applied_axi_vote.compressed_bw = 0;
+ apply_bw_update = false;
+
+ for (i = 0; i < CAM_VFE_TOP_VER2_MUX_MAX; i++) {
+ if (top_priv->axi_vote_control[i] ==
+ CAM_VFE_BW_CONTROL_INCLUDE &&
+ top_priv->cpashdl_type[i] ==
+ cpashdl_type) {
+ sum.uncompressed_bw +=
top_priv->req_axi_vote[i].uncompressed_bw;
- sum.compressed_bw +=
+ sum.compressed_bw +=
top_priv->req_axi_vote[i].compressed_bw;
+ }
}
- }
-
- CAM_DBG(CAM_ISP, "Updating BW from (%llu %llu) to (%llu %llu)",
- top_priv->applied_axi_vote.uncompressed_bw,
- top_priv->applied_axi_vote.compressed_bw,
- sum.uncompressed_bw,
- sum.compressed_bw);
-
- top_priv->last_vote[top_priv->last_counter] = sum;
- top_priv->last_counter = (top_priv->last_counter + 1) %
- (CAM_VFE_TOP_VER2_MUX_MAX *
- CAM_VFE_DELAY_BW_REDUCTION_NUM_FRAMES);
- if ((top_priv->applied_axi_vote.uncompressed_bw ==
- sum.uncompressed_bw) &&
- (top_priv->applied_axi_vote.compressed_bw ==
- sum.compressed_bw)) {
- CAM_DBG(CAM_ISP, "BW config unchanged %llu %llu",
+ CAM_DBG(CAM_ISP, "Updating BW from (%llu %llu) to (%llu %llu)",
top_priv->applied_axi_vote.uncompressed_bw,
- top_priv->applied_axi_vote.compressed_bw);
- return 0;
- }
+ top_priv->applied_axi_vote.compressed_bw,
+ sum.uncompressed_bw,
+ sum.compressed_bw);
- if (start_stop == true) {
- /* need to vote current request immediately */
- to_be_applied_axi_vote = sum;
- /* Reset everything, we can start afresh */
- memset(top_priv->last_vote, 0x0, sizeof(struct cam_axi_vote) *
- (CAM_VFE_TOP_VER2_MUX_MAX *
- CAM_VFE_DELAY_BW_REDUCTION_NUM_FRAMES));
- top_priv->last_counter = 0;
- top_priv->last_vote[top_priv->last_counter] = sum;
- top_priv->last_counter = (top_priv->last_counter + 1) %
+ last_vote = top_priv->last_vote[cpashdl_type];
+
+ last_vote[top_priv->last_counter[cpashdl_type]] = sum;
+ top_priv->last_counter[cpashdl_type] =
+ (top_priv->last_counter[cpashdl_type] + 1) %
(CAM_VFE_TOP_VER2_MUX_MAX *
CAM_VFE_DELAY_BW_REDUCTION_NUM_FRAMES);
- } else {
+
+ if ((top_priv->applied_axi_vote.uncompressed_bw ==
+ sum.uncompressed_bw) &&
+ (top_priv->applied_axi_vote.compressed_bw ==
+ sum.compressed_bw)) {
+ CAM_DBG(CAM_ISP, "BW config unchanged %llu %llu",
+ top_priv->applied_axi_vote.uncompressed_bw,
+ top_priv->applied_axi_vote.compressed_bw);
+ return 0;
+ }
+
+ if (start_stop == true) {
+ rc = cam_cpas_update_axi_vote(
+ soc_private->cpas_handle[cpashdl_type],
+ &to_be_applied_axi_vote);
+ if (!rc) {
+ top_priv->applied_axi_vote.uncompressed_bw =
+ to_be_applied_axi_vote.uncompressed_bw;
+ top_priv->applied_axi_vote.compressed_bw =
+ to_be_applied_axi_vote.compressed_bw;
+ }
+ return rc;
+ }
+
/*
- * Find max bw request in last few frames. This will the bw
- *that we want to vote to CPAS now.
+ * Find max bw request in last few frames. This is the bw
+ * that we want to vote to CPAS now.
*/
for (i = 0; i < (CAM_VFE_TOP_VER2_MUX_MAX *
CAM_VFE_DELAY_BW_REDUCTION_NUM_FRAMES); i++) {
if (to_be_applied_axi_vote.compressed_bw <
- top_priv->last_vote[i].compressed_bw)
+ last_vote[i].compressed_bw)
to_be_applied_axi_vote.compressed_bw =
- top_priv->last_vote[i].compressed_bw;
+ last_vote[i].compressed_bw;
if (to_be_applied_axi_vote.uncompressed_bw <
- top_priv->last_vote[i].uncompressed_bw)
+ last_vote[i].uncompressed_bw)
to_be_applied_axi_vote.uncompressed_bw =
- top_priv->last_vote[i].uncompressed_bw;
+ last_vote[i].uncompressed_bw;
}
- }
- if ((to_be_applied_axi_vote.uncompressed_bw !=
- top_priv->applied_axi_vote.uncompressed_bw) ||
- (to_be_applied_axi_vote.compressed_bw !=
- top_priv->applied_axi_vote.compressed_bw))
- apply_bw_update = true;
+ if ((to_be_applied_axi_vote.uncompressed_bw !=
+ top_priv->applied_axi_vote.uncompressed_bw) ||
+ (to_be_applied_axi_vote.compressed_bw !=
+ top_priv->applied_axi_vote.compressed_bw))
+ apply_bw_update = true;
- CAM_DBG(CAM_ISP, "apply_bw_update=%d", apply_bw_update);
+ CAM_DBG(CAM_ISP, "apply_bw_update=%d", apply_bw_update);
- if (apply_bw_update == true) {
- rc = cam_cpas_update_axi_vote(
- soc_private->cpas_handle,
- &to_be_applied_axi_vote);
- if (!rc) {
- top_priv->applied_axi_vote.uncompressed_bw =
+ if (apply_bw_update == true) {
+ rc = cam_cpas_update_axi_vote(
+ soc_private->cpas_handle[cpashdl_type],
+ &to_be_applied_axi_vote);
+ if (!rc) {
+ top_priv->applied_axi_vote.uncompressed_bw =
to_be_applied_axi_vote.uncompressed_bw;
- top_priv->applied_axi_vote.compressed_bw =
- to_be_applied_axi_vote.compressed_bw;
- } else {
- CAM_ERR(CAM_ISP, "BW request failed, rc=%d", rc);
+ top_priv->applied_axi_vote.compressed_bw =
+ to_be_applied_axi_vote.compressed_bw;
+ } else {
+ CAM_ERR(CAM_ISP, "BW request failed, rc=%d",
+ rc);
+ }
}
}
-
return rc;
}
@@ -459,8 +480,9 @@ int cam_vfe_top_reserve(void *device_priv,
top_priv->mux_rsrc[i].res_state ==
CAM_ISP_RESOURCE_STATE_AVAILABLE) {
- if (acquire_args->res_id == CAM_ISP_HW_VFE_IN_CAMIF) {
- rc = cam_vfe_camif_ver2_acquire_resource(
+ if (acquire_args->res_id ==
+ CAM_ISP_HW_VFE_IN_CAMIF_LITE) {
+ rc = cam_vfe_camif_lite_ver2_acquire_resource(
&top_priv->mux_rsrc[i],
args);
if (rc)
@@ -669,6 +691,7 @@ int cam_vfe_top_ver2_init(
struct cam_vfe_top_ver2_priv *top_priv = NULL;
struct cam_vfe_top_ver2_hw_info *ver2_hw_info = top_hw_info;
struct cam_vfe_top *vfe_top;
+ struct cam_vfe_soc_private *soc_private = NULL;
vfe_top = kzalloc(sizeof(struct cam_vfe_top), GFP_KERNEL);
if (!vfe_top) {
@@ -684,14 +707,22 @@ int cam_vfe_top_ver2_init(
rc = -ENOMEM;
goto free_vfe_top;
}
+
+ soc_private = soc_info->soc_private;
+ if (!soc_private) {
+ CAM_ERR(CAM_ISP, "Error! soc_private NULL");
+ rc = -ENODEV;
+ goto free_vfe_top_priv;
+ }
vfe_top->top_priv = top_priv;
top_priv->hw_clk_rate = 0;
top_priv->applied_axi_vote.compressed_bw = 0;
top_priv->applied_axi_vote.uncompressed_bw = 0;
memset(top_priv->last_vote, 0x0, sizeof(struct cam_axi_vote) *
- (CAM_VFE_TOP_VER2_MUX_MAX *
+ (CAM_VFE_TOP_VER2_MUX_MAX * CAM_CPAS_HANDLE_MAX *
CAM_VFE_DELAY_BW_REDUCTION_NUM_FRAMES));
- top_priv->last_counter = 0;
+ top_priv->last_counter[0] = 0;
+ top_priv->last_counter[1] = 0;
for (i = 0, j = 0; i < CAM_VFE_TOP_VER2_MUX_MAX; i++) {
top_priv->mux_rsrc[i].res_type = CAM_ISP_RESOURCE_VFE_IN;
@@ -707,6 +738,7 @@ int cam_vfe_top_ver2_init(
if (ver2_hw_info->mux_type[i] == CAM_VFE_CAMIF_VER_2_0) {
top_priv->mux_rsrc[i].res_id =
CAM_ISP_HW_VFE_IN_CAMIF;
+ top_priv->cpashdl_type[i] = CAM_CPAS_HANDLE_CAMIF;
rc = cam_vfe_camif_ver2_init(hw_intf, soc_info,
&ver2_hw_info->camif_hw_info,
@@ -717,6 +749,13 @@ int cam_vfe_top_ver2_init(
CAM_VFE_CAMIF_LITE_VER_2_0) {
top_priv->mux_rsrc[i].res_id =
CAM_ISP_HW_VFE_IN_CAMIF_LITE;
+ if (soc_private->cpas_version ==
+ CAM_CPAS_TITAN_175_V120)
+ top_priv->cpashdl_type[i] =
+ CAM_CPAS_HANDLE_RAW;
+ else
+ top_priv->cpashdl_type[i] =
+ CAM_CPAS_HANDLE_CAMIF;
rc = cam_vfe_camif_lite_ver2_init(hw_intf, soc_info,
&ver2_hw_info->camif_lite_hw_info,
@@ -729,6 +768,13 @@ int cam_vfe_top_ver2_init(
/* set the RDI resource id */
top_priv->mux_rsrc[i].res_id =
CAM_ISP_HW_VFE_IN_RDI0 + j++;
+ if (soc_private->cpas_version ==
+ CAM_CPAS_TITAN_175_V120)
+ top_priv->cpashdl_type[i] =
+ CAM_CPAS_HANDLE_RAW;
+ else
+ top_priv->cpashdl_type[i] =
+ CAM_CPAS_HANDLE_CAMIF;
rc = cam_vfe_rdi_ver2_init(hw_intf, soc_info,
&ver2_hw_info->rdi_hw_info,
@@ -776,7 +822,7 @@ deinit_resources:
top_priv->mux_rsrc[i].res_state =
CAM_ISP_RESOURCE_STATE_UNAVAILABLE;
}
-
+free_vfe_top_priv:
kfree(vfe_top->top_priv);
free_vfe_top:
kfree(vfe_top);
diff --git a/drivers/media/platform/msm/camera_v3/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c b/drivers/media/platform/msm/camera_v3/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c
index 24bb154f922c..d606e6b03519 100644
--- a/drivers/media/platform/msm/camera_v3/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c
+++ b/drivers/media/platform/msm/camera_v3/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -275,6 +275,12 @@ static int cam_jpeg_insert_cdm_change_base(
"unable to get src buf info for cmd buf: %d", rc);
return rc;
}
+
+ if (config_args->hw_update_entries[CAM_JPEG_CHBASE].offset >=
+ ch_base_len) {
+ CAM_ERR(CAM_JPEG, "Not enough buf");
+ return -EINVAL;
+ }
CAM_DBG(CAM_JPEG, "iova %pK len %zu offset %d",
(void *)iova_addr, ch_base_len,
config_args->hw_update_entries[CAM_JPEG_CHBASE].offset);
@@ -713,7 +719,7 @@ static int cam_jpeg_mgr_prepare_hw_update(void *hw_mgr_priv,
return -EINVAL;
}
- rc = cam_packet_util_validate_packet(packet);
+ rc = cam_packet_util_validate_packet(packet, prepare_args->remain_len);
if (rc) {
CAM_ERR(CAM_JPEG, "invalid packet %d", rc);
return rc;
diff --git a/drivers/media/platform/msm/camera_v3/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c b/drivers/media/platform/msm/camera_v3/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c
index 0c236462b7f5..47bf68c16c03 100644
--- a/drivers/media/platform/msm/camera_v3/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c
+++ b/drivers/media/platform/msm/camera_v3/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -83,7 +83,8 @@ static int cam_lrme_mgr_util_get_device(struct cam_lrme_hw_mgr *hw_mgr,
return 0;
}
-static int cam_lrme_mgr_util_packet_validate(struct cam_packet *packet)
+static int cam_lrme_mgr_util_packet_validate(struct cam_packet *packet,
+ size_t remain_len)
{
struct cam_cmd_buf_desc *cmd_desc = NULL;
int i, rc;
@@ -105,7 +106,7 @@ static int cam_lrme_mgr_util_packet_validate(struct cam_packet *packet)
packet->patch_offset, packet->num_patches,
packet->kmd_cmd_buf_offset, packet->kmd_cmd_buf_index);
- if (cam_packet_util_validate_packet(packet)) {
+ if (cam_packet_util_validate_packet(packet, remain_len)) {
CAM_ERR(CAM_LRME, "invalid packet:%d %d %d %d %d",
packet->kmd_cmd_buf_index,
packet->num_cmd_buf, packet->cmd_buf_offset,
@@ -186,6 +187,12 @@ static int cam_lrme_mgr_util_prepare_io_buffer(int32_t iommu_hdl,
return -ENOMEM;
}
+ if ((size_t)io_cfg[i].offsets[plane] >= size) {
+ CAM_ERR(CAM_LRME, "Invalid plane offset: %zu",
+ (size_t)io_cfg[i].offsets[plane]);
+ return -EINVAL;
+ }
+
io_addr[plane] += io_cfg[i].offsets[plane];
CAM_DBG(CAM_LRME, "IO Address[%d][%d] : %llu",
@@ -841,7 +848,7 @@ static int cam_lrme_mgr_hw_prepare_update(void *hw_mgr_priv,
goto error;
}
- rc = cam_lrme_mgr_util_packet_validate(args->packet);
+ rc = cam_lrme_mgr_util_packet_validate(args->packet, args->remain_len);
if (rc) {
CAM_ERR(CAM_LRME, "Error in packet validation %d", rc);
goto error;
diff --git a/drivers/media/platform/msm/camera_v3/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c b/drivers/media/platform/msm/camera_v3/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c
index 8cb1c9c28e7a..7ebdb94cd482 100644
--- a/drivers/media/platform/msm/camera_v3/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c
+++ b/drivers/media/platform/msm/camera_v3/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -736,6 +736,11 @@ int cam_lrme_hw_process_irq(void *priv, void *data)
mutex_lock(&lrme_hw->hw_mutex);
+ if (lrme_hw->hw_state == CAM_HW_STATE_POWER_DOWN) {
+ CAM_DBG(CAM_LRME, "LRME HW is in off state");
+ goto end;
+ }
+
if (top_irq_status & (1 << 3)) {
CAM_DBG(CAM_LRME, "Error");
rc = cam_lrme_hw_util_process_err(lrme_hw);
diff --git a/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_req_mgr_core.h b/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_req_mgr_core.h
index b7222237473b..a4ba987da1f0 100644
--- a/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_req_mgr_core.h
+++ b/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_req_mgr_core.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -317,6 +317,7 @@ struct cam_req_mgr_connected_device {
* frame in sync link as well.
* @open_req_cnt : Counter to keep track of open requests that are yet
* to be serviced in the kernel.
+ * @last_flush_id : Last request to flush
*
*/
struct cam_req_mgr_core_link {
@@ -341,6 +342,7 @@ struct cam_req_mgr_core_link {
bool frame_skip_flag;
bool sync_link_sof_skip;
int32_t open_req_cnt;
+ uint32_t last_flush_id;
};
/**
diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_actuator/cam_actuator_core.c b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_actuator/cam_actuator_core.c
index b2a7dc0784f4..224763925a0f 100644
--- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_actuator/cam_actuator_core.c
+++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_actuator/cam_actuator_core.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -17,6 +17,7 @@
#include "cam_trace.h"
#include "cam_res_mgr_api.h"
#include "cam_common_util.h"
+#include "cam_packet_util.h"
int32_t cam_actuator_construct_default_power_setting(
struct cam_sensor_power_ctrl_t *power_info)
@@ -214,12 +215,12 @@ static int32_t cam_actuator_i2c_modes_util(
}
int32_t cam_actuator_slaveInfo_pkt_parser(struct cam_actuator_ctrl_t *a_ctrl,
- uint32_t *cmd_buf)
+ uint32_t *cmd_buf, size_t len)
{
int32_t rc = 0;
struct cam_cmd_i2c_info *i2c_info;
- if (!a_ctrl || !cmd_buf) {
+ if (!a_ctrl || !cmd_buf || (len < sizeof(struct cam_cmd_i2c_info))) {
CAM_ERR(CAM_ACTUATOR, "Invalid Args");
return -EINVAL;
}
@@ -413,9 +414,11 @@ int32_t cam_actuator_i2c_pkt_parse(struct cam_actuator_ctrl_t *a_ctrl,
int32_t i = 0;
uint32_t total_cmd_buf_in_bytes = 0;
size_t len_of_buff = 0;
+ size_t remain_len = 0;
uint32_t *offset = NULL;
uint32_t *cmd_buf = NULL;
uintptr_t generic_ptr;
+ uintptr_t generic_pkt_ptr;
struct common_header *cmm_hdr = NULL;
struct cam_control *ioctl_ctrl = NULL;
struct cam_packet *csl_packet = NULL;
@@ -442,23 +445,34 @@ int32_t cam_actuator_i2c_pkt_parse(struct cam_actuator_ctrl_t *a_ctrl,
sizeof(config)))
return -EFAULT;
rc = cam_mem_get_cpu_buf(config.packet_handle,
- &generic_ptr, &len_of_buff);
+ &generic_pkt_ptr, &len_of_buff);
if (rc < 0) {
CAM_ERR(CAM_ACTUATOR, "Error in converting command Handle %d",
rc);
return rc;
}
- if (config.offset > len_of_buff) {
+ remain_len = len_of_buff;
+ if ((sizeof(struct cam_packet) > len_of_buff) ||
+ ((size_t)config.offset >= len_of_buff -
+ sizeof(struct cam_packet))) {
CAM_ERR(CAM_ACTUATOR,
- "offset is out of bounds: offset: %lld len: %zu",
- config.offset, len_of_buff);
+ "Inval cam_packet strut size: %zu, len_of_buff: %zu",
+ sizeof(struct cam_packet), len_of_buff);
return -EINVAL;
}
- csl_packet =
- (struct cam_packet *)(generic_ptr + (uint32_t)config.offset);
- CAM_DBG(CAM_ACTUATOR, "Pkt opcode: %d", csl_packet->header.op_code);
+ remain_len -= (size_t)config.offset;
+ csl_packet = (struct cam_packet *)
+ (generic_pkt_ptr + (uint32_t)config.offset);
+
+ if (cam_packet_util_validate_packet(csl_packet,
+ remain_len)) {
+ CAM_ERR(CAM_ACTUATOR, "Invalid packet params");
+ return -EINVAL;
+ }
+
+ CAM_DBG(CAM_ACTUATOR, "Pkt opcode: %d", csl_packet->header.op_code);
if ((csl_packet->header.op_code & 0xFFFFFF) !=
CAM_ACTUATOR_PACKET_OPCODE_INIT &&
@@ -467,7 +481,7 @@ int32_t cam_actuator_i2c_pkt_parse(struct cam_actuator_ctrl_t *a_ctrl,
CAM_DBG(CAM_ACTUATOR,
"reject request %lld, last request to flush %lld",
csl_packet->header.request_id, a_ctrl->last_flush_req);
- return -EINVAL;
+ rc = -EINVAL;
}
if (csl_packet->header.request_id > a_ctrl->last_flush_req)
@@ -495,6 +509,14 @@ int32_t cam_actuator_i2c_pkt_parse(struct cam_actuator_ctrl_t *a_ctrl,
CAM_ERR(CAM_ACTUATOR, "invalid cmd buf");
return -EINVAL;
}
+ if ((len_of_buff < sizeof(struct common_header)) ||
+ (cmd_desc[i].offset > (len_of_buff -
+ sizeof(struct common_header)))) {
+ CAM_ERR(CAM_ACTUATOR,
+ "Invalid length for sensor cmd");
+ return -EINVAL;
+ }
+ remain_len = len_of_buff - cmd_desc[i].offset;
cmd_buf += cmd_desc[i].offset / sizeof(uint32_t);
cmm_hdr = (struct common_header *)cmd_buf;
@@ -503,7 +525,7 @@ int32_t cam_actuator_i2c_pkt_parse(struct cam_actuator_ctrl_t *a_ctrl,
CAM_DBG(CAM_ACTUATOR,
"Received slave info buffer");
rc = cam_actuator_slaveInfo_pkt_parser(
- a_ctrl, cmd_buf);
+ a_ctrl, cmd_buf, remain_len);
if (rc < 0) {
CAM_ERR(CAM_ACTUATOR,
"Failed to parse slave info: %d", rc);
@@ -517,7 +539,7 @@ int32_t cam_actuator_i2c_pkt_parse(struct cam_actuator_ctrl_t *a_ctrl,
rc = cam_sensor_update_power_settings(
cmd_buf,
total_cmd_buf_in_bytes,
- power_info);
+ power_info, remain_len);
if (rc) {
CAM_ERR(CAM_ACTUATOR,
"Failed:parse power settings: %d",
@@ -642,9 +664,12 @@ int32_t cam_actuator_i2c_pkt_parse(struct cam_actuator_ctrl_t *a_ctrl,
a_ctrl->cam_act_state);
return -EINVAL;
}
-
cam_actuator_update_req_mgr(a_ctrl, csl_packet);
break;
+ default:
+ CAM_ERR(CAM_ACTUATOR, "Wrong Opcode: %d",
+ csl_packet->header.op_code & 0xFFFFFF);
+ return -EINVAL;
}
return rc;
diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_actuator/cam_actuator_dev.c b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_actuator/cam_actuator_dev.c
index 26d73a446a5b..228ccb8a39b3 100644
--- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_actuator/cam_actuator_dev.c
+++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_actuator/cam_actuator_dev.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -216,9 +216,7 @@ static int32_t cam_actuator_driver_i2c_probe(struct i2c_client *client,
cam_actuator_establish_link;
a_ctrl->bridge_intf.ops.apply_req =
cam_actuator_apply_request;
-
- v4l2_set_subdevdata(&(a_ctrl->v4l2_dev_str.sd), a_ctrl);
-
+ a_ctrl->last_flush_req = 0;
a_ctrl->cam_act_state = CAM_ACTUATOR_INIT;
return rc;
@@ -245,19 +243,24 @@ static int32_t cam_actuator_platform_remove(struct platform_device *pdev)
return 0;
}
+ CAM_INFO(CAM_ACTUATOR, "platform remove invoked");
+ mutex_lock(&(a_ctrl->actuator_mutex));
+ cam_actuator_shutdown(a_ctrl);
+ mutex_unlock(&(a_ctrl->actuator_mutex));
+ cam_unregister_subdev(&(a_ctrl->v4l2_dev_str));
+
soc_private =
(struct cam_actuator_soc_private *)a_ctrl->soc_info.soc_private;
power_info = &soc_private->power_info;
kfree(a_ctrl->io_master_info.cci_client);
a_ctrl->io_master_info.cci_client = NULL;
- kfree(power_info->power_setting);
- kfree(power_info->power_down_setting);
- power_info->power_setting = NULL;
- power_info->power_down_setting = NULL;
kfree(a_ctrl->soc_info.soc_private);
+ a_ctrl->soc_info.soc_private = NULL;
kfree(a_ctrl->i2c_data.per_frame);
a_ctrl->i2c_data.per_frame = NULL;
+ v4l2_set_subdevdata(&a_ctrl->v4l2_dev_str.sd, NULL);
+ platform_set_drvdata(pdev, NULL);
devm_kfree(&pdev->dev, a_ctrl);
return rc;
@@ -265,7 +268,6 @@ static int32_t cam_actuator_platform_remove(struct platform_device *pdev)
static int32_t cam_actuator_driver_i2c_remove(struct i2c_client *client)
{
- int32_t rc = 0;
struct cam_actuator_ctrl_t *a_ctrl =
i2c_get_clientdata(client);
struct cam_actuator_soc_private *soc_private;
@@ -277,6 +279,11 @@ static int32_t cam_actuator_driver_i2c_remove(struct i2c_client *client)
return -EINVAL;
}
+ CAM_INFO(CAM_ACTUATOR, "i2c remove invoked");
+ mutex_lock(&(a_ctrl->actuator_mutex));
+ cam_actuator_shutdown(a_ctrl);
+ mutex_unlock(&(a_ctrl->actuator_mutex));
+ cam_unregister_subdev(&(a_ctrl->v4l2_dev_str));
soc_private =
(struct cam_actuator_soc_private *)a_ctrl->soc_info.soc_private;
power_info = &soc_private->power_info;
@@ -284,14 +291,11 @@ static int32_t cam_actuator_driver_i2c_remove(struct i2c_client *client)
/*Free Allocated Mem */
kfree(a_ctrl->i2c_data.per_frame);
a_ctrl->i2c_data.per_frame = NULL;
- kfree(power_info->power_setting);
- kfree(power_info->power_down_setting);
- kfree(a_ctrl->soc_info.soc_private);
- power_info->power_setting = NULL;
- power_info->power_down_setting = NULL;
a_ctrl->soc_info.soc_private = NULL;
+ v4l2_set_subdevdata(&a_ctrl->v4l2_dev_str.sd, NULL);
kfree(a_ctrl);
- return rc;
+
+ return 0;
}
static const struct of_device_id cam_actuator_driver_dt_match[] = {
@@ -376,7 +380,6 @@ static int32_t cam_actuator_driver_platform_probe(
a_ctrl->last_flush_req = 0;
platform_set_drvdata(pdev, a_ctrl);
- v4l2_set_subdevdata(&a_ctrl->v4l2_dev_str.sd, a_ctrl);
a_ctrl->cam_act_state = CAM_ACTUATOR_INIT;
return rc;
diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_csiphy/cam_csiphy_core.c b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_csiphy/cam_csiphy_core.c
index 9894b217ac2c..c7dc5dad6da9 100644
--- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_csiphy/cam_csiphy_core.c
+++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_csiphy/cam_csiphy_core.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -15,6 +15,7 @@
#include "cam_csiphy_dev.h"
#include "cam_csiphy_soc.h"
#include "cam_common_util.h"
+#include "cam_packet_util.h"
#include <soc/qcom/scm.h>
#include <cam_mem_mgr.h>
@@ -159,11 +160,13 @@ int32_t cam_cmd_buf_parser(struct csiphy_device *csiphy_dev,
{
int32_t rc = 0;
uintptr_t generic_ptr;
+ uintptr_t generic_pkt_ptr;
struct cam_packet *csl_packet = NULL;
struct cam_cmd_buf_desc *cmd_desc = NULL;
uint32_t *cmd_buf = NULL;
struct cam_csiphy_info *cam_cmd_csiphy_info = NULL;
size_t len;
+ size_t remain_len;
if (!cfg_dev || !csiphy_dev) {
CAM_ERR(CAM_CSIPHY, "Invalid Args");
@@ -171,21 +174,30 @@ int32_t cam_cmd_buf_parser(struct csiphy_device *csiphy_dev,
}
rc = cam_mem_get_cpu_buf((int32_t) cfg_dev->packet_handle,
- &generic_ptr, &len);
+ &generic_pkt_ptr, &len);
if (rc < 0) {
CAM_ERR(CAM_CSIPHY, "Failed to get packet Mem address: %d", rc);
return rc;
}
- if (cfg_dev->offset > len) {
+ remain_len = len;
+ if ((sizeof(struct cam_packet) > len) ||
+ ((size_t)cfg_dev->offset >= len - sizeof(struct cam_packet))) {
CAM_ERR(CAM_CSIPHY,
- "offset is out of bounds: offset: %lld len: %zu",
- cfg_dev->offset, len);
+ "Inval cam_packet strut size: %zu, len_of_buff: %zu",
+ sizeof(struct cam_packet), len);
return -EINVAL;
}
+ remain_len -= (size_t)cfg_dev->offset;
csl_packet = (struct cam_packet *)
- (generic_ptr + (uint32_t)cfg_dev->offset);
+ (generic_pkt_ptr + (uint32_t)cfg_dev->offset);
+
+ if (cam_packet_util_validate_packet(csl_packet,
+ remain_len)) {
+ CAM_ERR(CAM_CSIPHY, "Invalid packet params");
+ return -EINVAL;
+ }
cmd_desc = (struct cam_cmd_buf_desc *)
((uint32_t *)&csl_packet->payload +
@@ -199,6 +211,13 @@ int32_t cam_cmd_buf_parser(struct csiphy_device *csiphy_dev,
return rc;
}
+ if ((len < sizeof(struct cam_csiphy_info)) ||
+ (cmd_desc->offset > (len - sizeof(struct cam_csiphy_info)))) {
+ CAM_ERR(CAM_CSIPHY,
+ "Not enough buffer provided for cam_cisphy_info");
+ return -EINVAL;
+ }
+
cmd_buf = (uint32_t *)generic_ptr;
cmd_buf += cmd_desc->offset / 4;
cam_cmd_csiphy_info = (struct cam_csiphy_info *)cmd_buf;
@@ -567,6 +586,14 @@ int32_t cam_csiphy_core_cfg(void *phy_dev,
struct cam_create_dev_hdl bridge_params;
+ if (csiphy_dev->csiphy_state == CAM_CSIPHY_START) {
+ CAM_ERR(CAM_CSIPHY,
+ "Not in right state to acquire : %d",
+ csiphy_dev->csiphy_state);
+ rc = -EINVAL;
+ goto release_mutex;
+ }
+
rc = copy_from_user(&csiphy_acq_dev,
u64_to_user_ptr(cmd->handle),
sizeof(csiphy_acq_dev));
@@ -826,6 +853,7 @@ int32_t cam_csiphy_core_cfg(void *phy_dev,
if (rc < 0) {
csiphy_dev->csiphy_info.secure_mode[offset] =
CAM_SECURE_MODE_NON_SECURE;
+ cam_cpas_stop(csiphy_dev->cpas_handle);
goto release_mutex;
}
}
diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c
index 32bb34bb257b..972b0a549f30 100644
--- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c
+++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -165,7 +165,6 @@ static int32_t cam_csiphy_platform_probe(struct platform_device *pdev)
}
platform_set_drvdata(pdev, &(new_csiphy_dev->v4l2_dev_str.sd));
- v4l2_set_subdevdata(&(new_csiphy_dev->v4l2_dev_str.sd), new_csiphy_dev);
new_csiphy_dev->bridge_intf.device_hdl[0] = -1;
new_csiphy_dev->bridge_intf.device_hdl[1] = -1;
@@ -211,9 +210,17 @@ static int32_t cam_csiphy_device_remove(struct platform_device *pdev)
struct csiphy_device *csiphy_dev =
v4l2_get_subdevdata(subdev);
+ CAM_INFO(CAM_CSIPHY, "device remove invoked");
cam_cpas_unregister_client(csiphy_dev->cpas_handle);
cam_csiphy_soc_release(csiphy_dev);
+ mutex_lock(&csiphy_dev->mutex);
+ cam_csiphy_shutdown(csiphy_dev);
+ mutex_unlock(&csiphy_dev->mutex);
+ cam_unregister_subdev(&(csiphy_dev->v4l2_dev_str));
kfree(csiphy_dev->ctrl_reg);
+ csiphy_dev->ctrl_reg = NULL;
+ platform_set_drvdata(pdev, NULL);
+ v4l2_set_subdevdata(&(csiphy_dev->v4l2_dev_str.sd), NULL);
devm_kfree(&pdev->dev, csiphy_dev);
return 0;
diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_eeprom/cam_eeprom_core.c b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_eeprom/cam_eeprom_core.c
index 7d7c1a2977e5..23f5c955b533 100644
--- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_eeprom/cam_eeprom_core.c
+++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_eeprom/cam_eeprom_core.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -18,6 +18,7 @@
#include "cam_eeprom_soc.h"
#include "cam_debug_util.h"
#include "cam_common_util.h"
+#include "cam_packet_util.h"
/**
* cam_eeprom_read_memory() - read map data into buffer
@@ -413,7 +414,7 @@ static int32_t cam_eeprom_update_slaveInfo(struct cam_eeprom_ctrl_t *e_ctrl,
static int32_t cam_eeprom_parse_memory_map(
struct cam_eeprom_memory_block_t *data,
void *cmd_buf, int cmd_length, uint16_t *cmd_length_bytes,
- int *num_map)
+ int *num_map, size_t remain_buf_len)
{
int32_t rc = 0;
int32_t cnt = 0;
@@ -427,8 +428,21 @@ static int32_t cam_eeprom_parse_memory_map(
struct cam_cmd_i2c_continuous_rd *i2c_cont_rd = NULL;
struct cam_cmd_conditional_wait *i2c_poll = NULL;
struct cam_cmd_unconditional_wait *i2c_uncond_wait = NULL;
+ size_t validate_size = 0;
generic_op_code = cmm_hdr->third_byte;
+
+ if (cmm_hdr->cmd_type == CAMERA_SENSOR_CMD_TYPE_I2C_RNDM_WR)
+ validate_size = sizeof(struct cam_cmd_i2c_random_wr);
+ else if (cmm_hdr->cmd_type == CAMERA_SENSOR_CMD_TYPE_I2C_CONT_RD)
+ validate_size = sizeof(struct cam_cmd_i2c_continuous_rd);
+ else if (cmm_hdr->cmd_type == CAMERA_SENSOR_CMD_TYPE_WAIT)
+ validate_size = sizeof(struct cam_cmd_unconditional_wait);
+
+ if (remain_buf_len < validate_size) {
+ CAM_ERR(CAM_EEPROM, "not enough buffer");
+ return -EINVAL;
+ }
switch (cmm_hdr->cmd_type) {
case CAMERA_SENSOR_CMD_TYPE_I2C_RNDM_WR:
i2c_random_wr = (struct cam_cmd_i2c_random_wr *)cmd_buf;
@@ -535,6 +549,7 @@ static int32_t cam_eeprom_init_pkt_parser(struct cam_eeprom_ctrl_t *e_ctrl,
uint32_t *cmd_buf = NULL;
uintptr_t generic_pkt_addr;
size_t pkt_len = 0;
+ size_t remain_len = 0;
uint32_t total_cmd_buf_in_bytes = 0;
uint32_t processed_cmd_buf_in_bytes = 0;
struct common_header *cmm_hdr = NULL;
@@ -577,13 +592,36 @@ static int32_t cam_eeprom_init_pkt_parser(struct cam_eeprom_ctrl_t *e_ctrl,
CAM_ERR(CAM_EEPROM, "invalid cmd buf");
return -EINVAL;
}
+
+ if ((pkt_len < sizeof(struct common_header)) ||
+ (cmd_desc[i].offset > (pkt_len -
+ sizeof(struct common_header)))) {
+ CAM_ERR(CAM_EEPROM, "Not enough buffer");
+ return -EINVAL;
+ }
+ remain_len = pkt_len - cmd_desc[i].offset;
cmd_buf += cmd_desc[i].offset / sizeof(uint32_t);
+
+ if (total_cmd_buf_in_bytes > remain_len) {
+ CAM_ERR(CAM_EEPROM, "Not enough buffer for command");
+ return -EINVAL;
+ }
/* Loop through multiple cmd formats in one cmd buffer */
while (processed_cmd_buf_in_bytes < total_cmd_buf_in_bytes) {
+ if ((remain_len - processed_cmd_buf_in_bytes) <
+ sizeof(struct common_header)) {
+ CAM_ERR(CAM_EEPROM, "Not enough buf");
+ return -EINVAL;
+ }
cmm_hdr = (struct common_header *)cmd_buf;
switch (cmm_hdr->cmd_type) {
case CAMERA_SENSOR_CMD_TYPE_I2C_INFO:
i2c_info = (struct cam_cmd_i2c_info *)cmd_buf;
+ if ((remain_len - processed_cmd_buf_in_bytes) <
+ sizeof(struct cam_cmd_i2c_info)) {
+ CAM_ERR(CAM_EEPROM, "Not enough buf");
+ return -EINVAL;
+ }
/* Configure the following map slave address */
map[num_map + 1].saddr = i2c_info->slave_addr;
rc = cam_eeprom_update_slaveInfo(e_ctrl,
@@ -599,7 +637,9 @@ static int32_t cam_eeprom_init_pkt_parser(struct cam_eeprom_ctrl_t *e_ctrl,
case CAMERA_SENSOR_CMD_TYPE_PWR_DOWN:
cmd_length_in_bytes = total_cmd_buf_in_bytes;
rc = cam_sensor_update_power_settings(cmd_buf,
- cmd_length_in_bytes, power_info);
+ cmd_length_in_bytes, power_info,
+ (remain_len -
+ processed_cmd_buf_in_bytes));
processed_cmd_buf_in_bytes +=
cmd_length_in_bytes;
cmd_buf += cmd_length_in_bytes/
@@ -616,7 +656,9 @@ static int32_t cam_eeprom_init_pkt_parser(struct cam_eeprom_ctrl_t *e_ctrl,
rc = cam_eeprom_parse_memory_map(
&e_ctrl->cal_data, cmd_buf,
total_cmd_buf_in_bytes,
- &cmd_length_in_bytes, &num_map);
+ &cmd_length_in_bytes, &num_map,
+ (remain_len -
+ processed_cmd_buf_in_bytes));
processed_cmd_buf_in_bytes +=
cmd_length_in_bytes;
cmd_buf += cmd_length_in_bytes/sizeof(uint32_t);
@@ -647,6 +689,7 @@ static int32_t cam_eeprom_get_cal_data(struct cam_eeprom_ctrl_t *e_ctrl,
uintptr_t buf_addr;
size_t buf_size;
uint8_t *read_buffer;
+ size_t remain_len = 0;
io_cfg = (struct cam_buf_io_cfg *) ((uint8_t *)
&csl_packet->payload +
@@ -660,6 +703,17 @@ static int32_t cam_eeprom_get_cal_data(struct cam_eeprom_ctrl_t *e_ctrl,
if (io_cfg->direction == CAM_BUF_OUTPUT) {
rc = cam_mem_get_cpu_buf(io_cfg->mem_handle[0],
&buf_addr, &buf_size);
+ if (rc) {
+ CAM_ERR(CAM_EEPROM, "Fail in get buffer: %d",
+ rc);
+ return rc;
+ }
+ if (buf_size <= io_cfg->offsets[0]) {
+ CAM_ERR(CAM_EEPROM, "Not enough buffer");
+ return -EINVAL;
+ }
+
+ remain_len = buf_size - io_cfg->offsets[0];
CAM_DBG(CAM_EEPROM, "buf_addr : %pK, buf_size : %zu\n",
(void *)buf_addr, buf_size);
@@ -671,7 +725,7 @@ static int32_t cam_eeprom_get_cal_data(struct cam_eeprom_ctrl_t *e_ctrl,
}
read_buffer += io_cfg->offsets[0];
- if (buf_size < e_ctrl->cal_data.num_data) {
+ if (remain_len < e_ctrl->cal_data.num_data) {
CAM_ERR(CAM_EEPROM,
"failed to copy, Invalid size");
return -EINVAL;
@@ -704,6 +758,7 @@ static int32_t cam_eeprom_pkt_parse(struct cam_eeprom_ctrl_t *e_ctrl, void *arg)
struct cam_config_dev_cmd dev_config;
uintptr_t generic_pkt_addr;
size_t pkt_len;
+ size_t remain_len = 0;
struct cam_packet *csl_packet = NULL;
struct cam_eeprom_soc_private *soc_private =
(struct cam_eeprom_soc_private *)e_ctrl->soc_info.soc_private;
@@ -723,15 +778,26 @@ static int32_t cam_eeprom_pkt_parse(struct cam_eeprom_ctrl_t *e_ctrl, void *arg)
return rc;
}
- if (dev_config.offset > pkt_len) {
+ remain_len = pkt_len;
+ if ((sizeof(struct cam_packet) > pkt_len) ||
+ ((size_t)dev_config.offset >= pkt_len -
+ sizeof(struct cam_packet))) {
CAM_ERR(CAM_EEPROM,
- "Offset is out of bound: off: %lld, %zu",
- dev_config.offset, pkt_len);
+ "Inval cam_packet strut size: %zu, len_of_buff: %zu",
+ sizeof(struct cam_packet), pkt_len);
return -EINVAL;
}
+ remain_len -= (size_t)dev_config.offset;
csl_packet = (struct cam_packet *)
- (generic_pkt_addr + (uint32_t)dev_config.offset);
+ (generic_pkt_addr + (uint32_t)dev_config.offset);
+
+ if (cam_packet_util_validate_packet(csl_packet,
+ remain_len)) {
+ CAM_ERR(CAM_EEPROM, "Invalid packet params");
+ return -EINVAL;
+ }
+
switch (csl_packet->header.op_code & 0xFFFFFF) {
case CAM_EEPROM_PACKET_OPCODE_INIT:
if (e_ctrl->userspace_probe == false) {
diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_eeprom/cam_eeprom_dev.c b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_eeprom/cam_eeprom_dev.c
index 6d8820abb7d7..cf6854c7a527 100644
--- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_eeprom/cam_eeprom_dev.c
+++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_eeprom/cam_eeprom_dev.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -219,7 +219,6 @@ static int cam_eeprom_i2c_driver_probe(struct i2c_client *client,
e_ctrl->bridge_intf.ops.get_dev_info = NULL;
e_ctrl->bridge_intf.ops.link_setup = NULL;
e_ctrl->bridge_intf.ops.apply_req = NULL;
- v4l2_set_subdevdata(&e_ctrl->v4l2_dev_str.sd, e_ctrl);
e_ctrl->cam_eeprom_state = CAM_EEPROM_INIT;
return rc;
@@ -257,13 +256,17 @@ static int cam_eeprom_i2c_driver_remove(struct i2c_client *client)
return -EINVAL;
}
+ CAM_INFO(CAM_EEPROM, "i2c driver remove invoked");
soc_info = &e_ctrl->soc_info;
for (i = 0; i < soc_info->num_clk; i++)
devm_clk_put(soc_info->dev, soc_info->clk[i]);
+ mutex_lock(&(e_ctrl->eeprom_mutex));
+ cam_eeprom_shutdown(e_ctrl);
+ mutex_unlock(&(e_ctrl->eeprom_mutex));
mutex_destroy(&(e_ctrl->eeprom_mutex));
+ cam_unregister_subdev(&(e_ctrl->v4l2_dev_str));
kfree(soc_private);
- kfree(e_ctrl->io_master_info.cci_client);
v4l2_set_subdevdata(&e_ctrl->v4l2_dev_str.sd, NULL);
kfree(e_ctrl);
@@ -388,14 +391,21 @@ static int cam_eeprom_spi_driver_remove(struct spi_device *sdev)
for (i = 0; i < soc_info->num_clk; i++)
devm_clk_put(soc_info->dev, soc_info->clk[i]);
+ mutex_lock(&(e_ctrl->eeprom_mutex));
+ cam_eeprom_shutdown(e_ctrl);
+ mutex_unlock(&(e_ctrl->eeprom_mutex));
+ mutex_destroy(&(e_ctrl->eeprom_mutex));
+ cam_unregister_subdev(&(e_ctrl->v4l2_dev_str));
kfree(e_ctrl->io_master_info.spi_client);
+ e_ctrl->io_master_info.spi_client = NULL;
soc_private =
(struct cam_eeprom_soc_private *)e_ctrl->soc_info.soc_private;
if (soc_private) {
kfree(soc_private->power_info.gpio_num_info);
+ soc_private->power_info.gpio_num_info = NULL;
kfree(soc_private);
+ soc_private = NULL;
}
- mutex_destroy(&(e_ctrl->eeprom_mutex));
v4l2_set_subdevdata(&e_ctrl->v4l2_dev_str.sd, NULL);
kfree(e_ctrl);
@@ -459,10 +469,7 @@ static int32_t cam_eeprom_platform_driver_probe(
e_ctrl->bridge_intf.ops.get_dev_info = NULL;
e_ctrl->bridge_intf.ops.link_setup = NULL;
e_ctrl->bridge_intf.ops.apply_req = NULL;
-
platform_set_drvdata(pdev, e_ctrl);
- v4l2_set_subdevdata(&e_ctrl->v4l2_dev_str.sd, e_ctrl);
-
e_ctrl->cam_eeprom_state = CAM_EEPROM_INIT;
return rc;
@@ -472,6 +479,7 @@ free_cci_client:
kfree(e_ctrl->io_master_info.cci_client);
free_e_ctrl:
kfree(e_ctrl);
+
return rc;
}
@@ -487,17 +495,23 @@ static int cam_eeprom_platform_driver_remove(struct platform_device *pdev)
return -EINVAL;
}
+ CAM_INFO(CAM_EEPROM, "Platform driver remove invoked");
soc_info = &e_ctrl->soc_info;
for (i = 0; i < soc_info->num_clk; i++)
devm_clk_put(soc_info->dev, soc_info->clk[i]);
+ mutex_lock(&(e_ctrl->eeprom_mutex));
+ cam_eeprom_shutdown(e_ctrl);
+ mutex_unlock(&(e_ctrl->eeprom_mutex));
mutex_destroy(&(e_ctrl->eeprom_mutex));
+ cam_unregister_subdev(&(e_ctrl->v4l2_dev_str));
kfree(soc_info->soc_private);
kfree(e_ctrl->io_master_info.cci_client);
platform_set_drvdata(pdev, NULL);
v4l2_set_subdevdata(&e_ctrl->v4l2_dev_str.sd, NULL);
kfree(e_ctrl);
+
return 0;
}
diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_flash/cam_flash_core.c b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_flash/cam_flash_core.c
index 5c9df8ac7abf..c6d47f617209 100644
--- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_flash/cam_flash_core.c
+++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_flash/cam_flash_core.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -16,6 +16,7 @@
#include "cam_flash_core.h"
#include "cam_res_mgr_api.h"
#include "cam_common_util.h"
+#include "cam_packet_util.h"
static int cam_flash_prepare(struct cam_flash_ctrl *flash_ctrl,
bool regulator_enable)
@@ -171,6 +172,7 @@ int cam_flash_pmic_power_ops(struct cam_flash_ctrl *fctrl,
"Enable Regulator Failed rc = %d", rc);
return rc;
}
+ fctrl->last_flush_req = 0;
}
if (!regulator_enable) {
@@ -361,6 +363,9 @@ int cam_flash_flush_request(struct cam_req_mgr_flush_request *flush)
mutex_lock(&fctrl->flash_mutex);
if (flush->type == CAM_REQ_MGR_FLUSH_TYPE_ALL) {
+ fctrl->last_flush_req = flush->req_id;
+ CAM_DBG(CAM_FLASH, "last reqest to flush is %lld",
+ flush->req_id);
rc = fctrl->func_tbl.flush_req(fctrl, FLUSH_ALL, 0);
if (rc) {
CAM_ERR(CAM_FLASH, "FLUSH_TYPE_ALL failed rc: %d", rc);
@@ -591,11 +596,15 @@ static int cam_flash_pmic_delete_req(struct cam_flash_ctrl *fctrl,
}
static int32_t cam_flash_slaveInfo_pkt_parser(struct cam_flash_ctrl *fctrl,
- uint32_t *cmd_buf)
+ uint32_t *cmd_buf, size_t len)
{
int32_t rc = 0;
struct cam_cmd_i2c_info *i2c_info = (struct cam_cmd_i2c_info *)cmd_buf;
+ if (len < sizeof(struct cam_cmd_i2c_info)) {
+ CAM_ERR(CAM_FLASH, "Not enough buffer");
+ return -EINVAL;
+ }
if (fctrl->io_master_info.master_type == CCI_MASTER) {
fctrl->io_master_info.cci_client->cci_i2c_master =
fctrl->cci_i2c_master;
@@ -870,6 +879,7 @@ int cam_flash_i2c_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg)
uint32_t *offset = NULL;
uint32_t frm_offset = 0;
size_t len_of_buffer;
+ size_t remain_len;
struct cam_flash_init *flash_init = NULL;
struct common_header *cmn_hdr = NULL;
struct cam_control *ioctl_ctrl = NULL;
@@ -901,15 +911,39 @@ int cam_flash_i2c_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg)
return rc;
}
- if (config.offset > len_of_buffer) {
+ remain_len = len_of_buffer;
+ if ((sizeof(struct cam_packet) > len_of_buffer) ||
+ ((size_t)config.offset >= len_of_buffer -
+ sizeof(struct cam_packet))) {
CAM_ERR(CAM_FLASH,
- "offset is out of bounds: offset: %lld len: %zu",
- config.offset, len_of_buffer);
+ "Inval cam_packet strut size: %zu, len_of_buff: %zu",
+ sizeof(struct cam_packet), len_of_buffer);
return -EINVAL;
}
+ remain_len -= (size_t)config.offset;
/* Add offset to the flash csl header */
csl_packet = (struct cam_packet *)(generic_ptr + config.offset);
+
+ if (cam_packet_util_validate_packet(csl_packet,
+ remain_len)) {
+ CAM_ERR(CAM_FLASH, "Invalid packet params");
+ return -EINVAL;
+ }
+
+ if ((csl_packet->header.op_code & 0xFFFFFF) !=
+ CAM_FLASH_PACKET_OPCODE_INIT &&
+ csl_packet->header.request_id <= fctrl->last_flush_req
+ && fctrl->last_flush_req != 0) {
+ CAM_DBG(CAM_FLASH,
+ "reject request %lld, last request to flush %lld",
+ csl_packet->header.request_id, fctrl->last_flush_req);
+ return -EINVAL;
+ }
+
+ if (csl_packet->header.request_id > fctrl->last_flush_req)
+ fctrl->last_flush_req = 0;
+
switch (csl_packet->header.op_code & 0xFFFFFF) {
case CAM_FLASH_PACKET_OPCODE_INIT: {
/* INIT packet*/
@@ -934,6 +968,15 @@ int cam_flash_i2c_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg)
CAM_ERR(CAM_FLASH, "invalid cmd buf");
return -EINVAL;
}
+
+ if ((len_of_buffer < sizeof(struct common_header)) ||
+ (cmd_desc[i].offset >
+ (len_of_buffer -
+ sizeof(struct common_header)))) {
+ CAM_ERR(CAM_FLASH, "invalid cmd buf length");
+ return -EINVAL;
+ }
+ remain_len = len_of_buffer - cmd_desc[i].offset;
cmd_buf += cmd_desc[i].offset / sizeof(uint32_t);
cmn_hdr = (struct common_header *)cmd_buf;
@@ -944,6 +987,12 @@ int cam_flash_i2c_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg)
total_cmd_buf_in_bytes);
switch (cmn_hdr->cmd_type) {
case CAMERA_SENSOR_FLASH_CMD_TYPE_INIT_INFO:
+ if (len_of_buffer <
+ sizeof(struct cam_flash_init)) {
+ CAM_ERR(CAM_FLASH, "Not enough buffer");
+ return -EINVAL;
+ }
+
flash_init = (struct cam_flash_init *)cmd_buf;
fctrl->flash_type = flash_init->flash_type;
cmd_length_in_bytes =
@@ -955,7 +1004,7 @@ int cam_flash_i2c_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg)
break;
case CAMERA_SENSOR_CMD_TYPE_I2C_INFO:
rc = cam_flash_slaveInfo_pkt_parser(
- fctrl, cmd_buf);
+ fctrl, cmd_buf, remain_len);
if (rc < 0) {
CAM_ERR(CAM_FLASH,
"Failed parsing slave info: rc: %d",
@@ -978,7 +1027,7 @@ int cam_flash_i2c_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg)
rc = cam_sensor_update_power_settings(
cmd_buf,
total_cmd_buf_in_bytes,
- &fctrl->power_info);
+ &fctrl->power_info, remain_len);
processed_cmd_buf_in_bytes +=
cmd_length_in_bytes;
cmd_buf += cmd_length_in_bytes/
@@ -1171,11 +1220,12 @@ update_req_mgr:
int cam_flash_pmic_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg)
{
int rc = 0, i = 0;
- uintptr_t generic_ptr;
+ uintptr_t generic_ptr, cmd_buf_ptr;
uint32_t *cmd_buf = NULL;
uint32_t *offset = NULL;
uint32_t frm_offset = 0;
size_t len_of_buffer;
+ size_t remain_len;
struct cam_control *ioctl_ctrl = NULL;
struct cam_packet *csl_packet = NULL;
struct cam_cmd_buf_desc *cmd_desc = NULL;
@@ -1187,11 +1237,16 @@ int cam_flash_pmic_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg)
struct cam_flash_set_on_off *flash_operation_info = NULL;
struct cam_flash_query_curr *flash_query_info = NULL;
struct cam_flash_frame_setting *flash_data = NULL;
+ struct cam_flash_private_soc *soc_private = NULL;
if (!fctrl || !arg) {
CAM_ERR(CAM_FLASH, "fctrl/arg is NULL");
return -EINVAL;
}
+
+ soc_private = (struct cam_flash_private_soc *)
+ fctrl->soc_info.soc_private;
+
/* getting CSL Packet */
ioctl_ctrl = (struct cam_control *)arg;
@@ -1206,20 +1261,42 @@ int cam_flash_pmic_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg)
rc = cam_mem_get_cpu_buf(config.packet_handle,
&generic_ptr, &len_of_buffer);
if (rc) {
- CAM_ERR(CAM_FLASH, "Failed in getting the buffer : %d", rc);
+ CAM_ERR(CAM_FLASH, "Failed in getting the packet: %d", rc);
return rc;
}
- if (config.offset > len_of_buffer) {
+ remain_len = len_of_buffer;
+ if ((sizeof(struct cam_packet) > len_of_buffer) ||
+ ((size_t)config.offset >= len_of_buffer -
+ sizeof(struct cam_packet))) {
CAM_ERR(CAM_FLASH,
- "offset is out of bounds: offset: %lld len: %zu",
- config.offset, len_of_buffer);
+ "Inval cam_packet strut size: %zu, len_of_buff: %zu",
+ sizeof(struct cam_packet), len_of_buffer);
return -EINVAL;
}
+ remain_len -= (size_t)config.offset;
/* Add offset to the flash csl header */
- csl_packet =
- (struct cam_packet *)(generic_ptr + (uint32_t)config.offset);
+ csl_packet = (struct cam_packet *)(generic_ptr + config.offset);
+
+ if (cam_packet_util_validate_packet(csl_packet,
+ remain_len)) {
+ CAM_ERR(CAM_FLASH, "Invalid packet params");
+ return -EINVAL;
+ }
+
+ if ((csl_packet->header.op_code & 0xFFFFFF) !=
+ CAM_FLASH_PACKET_OPCODE_INIT &&
+ csl_packet->header.request_id <= fctrl->last_flush_req
+ && fctrl->last_flush_req != 0) {
+ CAM_DBG(CAM_FLASH,
+ "reject request %lld, last request to flush %lld",
+ csl_packet->header.request_id, fctrl->last_flush_req);
+ return -EINVAL;
+ }
+
+ if (csl_packet->header.request_id > fctrl->last_flush_req)
+ fctrl->last_flush_req = 0;
switch (csl_packet->header.op_code & 0xFFFFFF) {
case CAM_FLASH_PACKET_OPCODE_INIT: {
@@ -1228,8 +1305,19 @@ int cam_flash_pmic_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg)
csl_packet->cmd_buf_offset);
cmd_desc = (struct cam_cmd_buf_desc *)(offset);
rc = cam_mem_get_cpu_buf(cmd_desc->mem_handle,
- &generic_ptr, &len_of_buffer);
- cmd_buf = (uint32_t *)((uint8_t *)generic_ptr +
+ &cmd_buf_ptr, &len_of_buffer);
+ if (rc) {
+ CAM_ERR(CAM_FLASH, "Fail in get buffer: %d", rc);
+ return rc;
+ }
+ if ((len_of_buffer < sizeof(struct cam_flash_init)) ||
+ (cmd_desc->offset >
+ (len_of_buffer - sizeof(struct cam_flash_init)))) {
+ CAM_ERR(CAM_FLASH, "Not enough buffer");
+ return -EINVAL;
+ }
+ remain_len = len_of_buffer - cmd_desc->offset;
+ cmd_buf = (uint32_t *)((uint8_t *)cmd_buf_ptr +
cmd_desc->offset);
cam_flash_info = (struct cam_flash_init *)cmd_buf;
@@ -1258,8 +1346,23 @@ int cam_flash_pmic_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg)
case CAMERA_SENSOR_FLASH_CMD_TYPE_INIT_FIRE: {
CAM_DBG(CAM_FLASH, "INIT_FIRE Operation");
+ if (remain_len < sizeof(struct cam_flash_set_on_off)) {
+ CAM_ERR(CAM_FLASH, "Not enough buffer");
+ return -EINVAL;
+ }
+
flash_operation_info =
(struct cam_flash_set_on_off *) cmd_buf;
+ if (!flash_operation_info) {
+ CAM_ERR(CAM_FLASH,
+ "flash_operation_info Null");
+ return -EINVAL;
+ }
+ if (flash_operation_info->count >
+ CAM_FLASH_MAX_LED_TRIGGERS) {
+ CAM_ERR(CAM_FLASH, "led count out of limit");
+ return -EINVAL;
+ }
fctrl->nrt_info.cmn_attr.count =
flash_operation_info->count;
fctrl->nrt_info.cmn_attr.request_id = 0;
@@ -1306,10 +1409,23 @@ int cam_flash_pmic_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg)
flash_data->cmn_attr.is_settings_valid = true;
cmd_desc = (struct cam_cmd_buf_desc *)(offset);
rc = cam_mem_get_cpu_buf(cmd_desc->mem_handle,
- &generic_ptr, &len_of_buffer);
- cmd_buf = (uint32_t *)((uint8_t *)generic_ptr +
- cmd_desc->offset);
+ &cmd_buf_ptr, &len_of_buffer);
+ if (rc) {
+ CAM_ERR(CAM_FLASH, "Fail in get buffer: 0x%x",
+ cmd_desc->mem_handle);
+ return rc;
+ }
+ if ((len_of_buffer < sizeof(struct common_header)) ||
+ (cmd_desc->offset >
+ (len_of_buffer - sizeof(struct common_header)))) {
+ CAM_ERR(CAM_FLASH, "not enough buffer");
+ return -EINVAL;
+ }
+ remain_len = len_of_buffer - cmd_desc->offset;
+
+ cmd_buf = (uint32_t *)((uint8_t *)cmd_buf_ptr +
+ cmd_desc->offset);
if (!cmd_buf)
return -EINVAL;
@@ -1325,7 +1441,11 @@ int cam_flash_pmic_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg)
CAM_WARN(CAM_FLASH,
"Rxed Flash fire ops without linking");
flash_data->cmn_attr.is_settings_valid = false;
- return 0;
+ return -EINVAL;
+ }
+ if (remain_len < sizeof(struct cam_flash_set_on_off)) {
+ CAM_ERR(CAM_FLASH, "Not enough buffer");
+ return -EINVAL;
}
flash_operation_info =
@@ -1335,6 +1455,11 @@ int cam_flash_pmic_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg)
"flash_operation_info Null");
return -EINVAL;
}
+ if (flash_operation_info->count >
+ CAM_FLASH_MAX_LED_TRIGGERS) {
+ CAM_ERR(CAM_FLASH, "led count out of limit");
+ return -EINVAL;
+ }
flash_data->opcode = flash_operation_info->opcode;
flash_data->cmn_attr.count =
@@ -1360,16 +1485,43 @@ int cam_flash_pmic_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg)
fctrl->nrt_info.cmn_attr.is_settings_valid = true;
cmd_desc = (struct cam_cmd_buf_desc *)(offset);
rc = cam_mem_get_cpu_buf(cmd_desc->mem_handle,
- &generic_ptr, &len_of_buffer);
- cmd_buf = (uint32_t *)((uint8_t *)generic_ptr +
+ &cmd_buf_ptr, &len_of_buffer);
+ if (rc) {
+ CAM_ERR(CAM_FLASH, "Fail in get buffer: %d", rc);
+ return rc;
+ }
+
+ if ((len_of_buffer < sizeof(struct common_header)) ||
+ (cmd_desc->offset >
+ (len_of_buffer - sizeof(struct common_header)))) {
+ CAM_ERR(CAM_FLASH, "Not enough buffer");
+ return -EINVAL;
+ }
+ remain_len = len_of_buffer - cmd_desc->offset;
+ cmd_buf = (uint32_t *)((uint8_t *)cmd_buf_ptr +
cmd_desc->offset);
cmn_hdr = (struct common_header *)cmd_buf;
switch (cmn_hdr->cmd_type) {
case CAMERA_SENSOR_FLASH_CMD_TYPE_WIDGET: {
CAM_DBG(CAM_FLASH, "Widget Flash Operation");
+ if (remain_len < sizeof(struct cam_flash_set_on_off)) {
+ CAM_ERR(CAM_FLASH, "Not enough buffer");
+ return -EINVAL;
+ }
flash_operation_info =
(struct cam_flash_set_on_off *) cmd_buf;
+ if (!flash_operation_info) {
+ CAM_ERR(CAM_FLASH,
+ "flash_operation_info Null");
+ return -EINVAL;
+ }
+ if (flash_operation_info->count >
+ CAM_FLASH_MAX_LED_TRIGGERS) {
+ CAM_ERR(CAM_FLASH, "led count out of limit");
+ return -EINVAL;
+ }
+
fctrl->nrt_info.cmn_attr.count =
flash_operation_info->count;
fctrl->nrt_info.cmn_attr.request_id = 0;
@@ -1408,7 +1560,22 @@ int cam_flash_pmic_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg)
}
case CAMERA_SENSOR_FLASH_CMD_TYPE_RER: {
rc = 0;
+ if (remain_len < sizeof(struct cam_flash_set_rer)) {
+ CAM_ERR(CAM_FLASH, "Not enough buffer");
+ return -EINVAL;
+ }
flash_rer_info = (struct cam_flash_set_rer *)cmd_buf;
+ if (!flash_rer_info) {
+ CAM_ERR(CAM_FLASH,
+ "flash_rer_info Null");
+ return -EINVAL;
+ }
+ if (flash_rer_info->count >
+ CAM_FLASH_MAX_LED_TRIGGERS) {
+ CAM_ERR(CAM_FLASH, "led count out of limit");
+ return -EINVAL;
+ }
+
fctrl->nrt_info.cmn_attr.cmd_type =
CAMERA_SENSOR_FLASH_CMD_TYPE_RER;
fctrl->nrt_info.opcode = flash_rer_info->opcode;
@@ -1425,7 +1592,6 @@ int cam_flash_pmic_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg)
fctrl->nrt_info.led_current_ma[i] =
flash_rer_info->led_current_ma[i];
-
rc = fctrl->func_tbl.apply_setting(fctrl, 0);
if (rc)
CAM_ERR(CAM_FLASH, "apply_setting failed: %d",
@@ -1448,7 +1614,7 @@ int cam_flash_pmic_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg)
"Rxed NOP packets without linking");
fctrl->per_frame[frm_offset].cmn_attr.is_settings_valid
= false;
- return 0;
+ return -EINVAL;
}
fctrl->per_frame[frm_offset].cmn_attr.is_settings_valid = false;
@@ -1463,6 +1629,7 @@ int cam_flash_pmic_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg)
(csl_packet->header.op_code & 0xFFFFFF));
return -EINVAL;
}
+
update_req_mgr:
if (((csl_packet->header.op_code & 0xFFFFF) ==
CAM_PKT_NOP_OPCODE) ||
@@ -1534,6 +1701,7 @@ int cam_flash_release_dev(struct cam_flash_ctrl *fctrl)
fctrl->bridge_intf.device_hdl = -1;
fctrl->bridge_intf.link_hdl = -1;
fctrl->bridge_intf.session_hdl = -1;
+ fctrl->last_flush_req = 0;
}
return rc;
diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_flash/cam_flash_dev.c b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_flash/cam_flash_dev.c
index f5177d6796b5..55b79abd4e1d 100644
--- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_flash/cam_flash_dev.c
+++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_flash/cam_flash_dev.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -319,6 +319,14 @@ static int cam_flash_platform_remove(struct platform_device *pdev)
}
devm_kfree(&pdev->dev, fctrl);
+ CAM_INFO(CAM_FLASH, "Platform remove invoked");
+ mutex_lock(&fctrl->flash_mutex);
+ cam_flash_shutdown(fctrl);
+ mutex_unlock(&fctrl->flash_mutex);
+ cam_unregister_subdev(&(fctrl->v4l2_dev_str));
+ platform_set_drvdata(pdev, NULL);
+ v4l2_set_subdevdata(&fctrl->v4l2_dev_str.sd, NULL);
+ kfree(fctrl);
return 0;
}
@@ -332,6 +340,8 @@ static int32_t cam_flash_i2c_driver_remove(struct i2c_client *client)
CAM_ERR(CAM_FLASH, "Flash device is NULL");
return -EINVAL;
}
+
+ CAM_INFO(CAM_FLASH, "i2c driver remove invoked");
/*Free Allocated Mem */
kfree(fctrl->i2c_data.per_frame);
fctrl->i2c_data.per_frame = NULL;
@@ -483,6 +493,7 @@ static int32_t cam_flash_platform_probe(struct platform_device *pdev)
fctrl->bridge_intf.ops.link_setup = cam_flash_establish_link;
fctrl->bridge_intf.ops.apply_req = cam_flash_apply_request;
fctrl->bridge_intf.ops.flush_req = cam_flash_flush_request;
+ fctrl->last_flush_req = 0;
mutex_init(&(fctrl->flash_mutex));
@@ -569,6 +580,7 @@ static int32_t cam_flash_i2c_driver_probe(struct i2c_client *client,
fctrl->bridge_intf.ops.link_setup = cam_flash_establish_link;
fctrl->bridge_intf.ops.apply_req = cam_flash_apply_request;
fctrl->bridge_intf.ops.flush_req = cam_flash_flush_request;
+ fctrl->last_flush_req = 0;
mutex_init(&(fctrl->flash_mutex));
fctrl->flash_state = CAM_FLASH_STATE_INIT;
diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_flash/cam_flash_dev.h b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_flash/cam_flash_dev.h
index 8e5deef871e5..774cb2d2fdbd 100644
--- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_flash/cam_flash_dev.h
+++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_flash/cam_flash_dev.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -180,6 +180,7 @@ struct cam_flash_func_tbl {
* @cci_i2c_master : I2C structure
* @io_master_info : Information about the communication master
* @i2c_data : I2C register settings
+ * @last_flush_req : last request to flush
*/
struct cam_flash_ctrl {
struct cam_hw_soc_info soc_info;
@@ -205,6 +206,7 @@ struct cam_flash_ctrl {
enum cci_i2c_master_t cci_i2c_master;
struct camera_io_master io_master_info;
struct i2c_data_settings i2c_data;
+ uint32_t last_flush_req;
};
int cam_flash_pmic_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg);
diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_ois/cam_ois_core.c b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_ois/cam_ois_core.c
index b8ebc15e7fd5..a59962191d6e 100644
--- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_ois/cam_ois_core.c
+++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_ois/cam_ois_core.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -19,6 +19,7 @@
#include "cam_debug_util.h"
#include "cam_res_mgr_api.h"
#include "cam_common_util.h"
+#include "cam_packet_util.h"
int32_t cam_ois_construct_default_power_setting(
struct cam_sensor_power_ctrl_t *power_info)
@@ -256,12 +257,12 @@ static int cam_ois_apply_settings(struct cam_ois_ctrl_t *o_ctrl,
}
static int cam_ois_slaveInfo_pkt_parser(struct cam_ois_ctrl_t *o_ctrl,
- uint32_t *cmd_buf)
+ uint32_t *cmd_buf, size_t len)
{
int32_t rc = 0;
struct cam_cmd_ois_info *ois_info;
- if (!o_ctrl || !cmd_buf) {
+ if (!o_ctrl || !cmd_buf || len < sizeof(struct cam_cmd_ois_info)) {
CAM_ERR(CAM_OIS, "Invalid Args");
return -EINVAL;
}
@@ -274,7 +275,8 @@ static int cam_ois_slaveInfo_pkt_parser(struct cam_ois_ctrl_t *o_ctrl,
ois_info->slave_addr >> 1;
o_ctrl->ois_fw_flag = ois_info->ois_fw_flag;
o_ctrl->is_ois_calib = ois_info->is_ois_calib;
- memcpy(o_ctrl->ois_name, ois_info->ois_name, 32);
+ memcpy(o_ctrl->ois_name, ois_info->ois_name, OIS_NAME_LEN);
+ o_ctrl->ois_name[OIS_NAME_LEN - 1] = '\0';
o_ctrl->io_master_info.cci_client->retries = 3;
o_ctrl->io_master_info.cci_client->id_map = 0;
memcpy(&(o_ctrl->opcode), &(ois_info->opcode),
@@ -433,6 +435,7 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg)
struct cam_cmd_buf_desc *cmd_desc = NULL;
uintptr_t generic_pkt_addr;
size_t pkt_len;
+ size_t remain_len = 0;
struct cam_packet *csl_packet = NULL;
size_t len_of_buff = 0;
uint32_t *offset = NULL, *cmd_buf;
@@ -453,15 +456,26 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg)
return rc;
}
- if (dev_config.offset > pkt_len) {
+ remain_len = pkt_len;
+ if ((sizeof(struct cam_packet) > pkt_len) ||
+ ((size_t)dev_config.offset >= pkt_len -
+ sizeof(struct cam_packet))) {
CAM_ERR(CAM_OIS,
- "offset is out of bound: off: %lld len: %zu",
- dev_config.offset, pkt_len);
+ "Inval cam_packet strut size: %zu, len_of_buff: %zu",
+ sizeof(struct cam_packet), pkt_len);
return -EINVAL;
}
+ remain_len -= (size_t)dev_config.offset;
csl_packet = (struct cam_packet *)
(generic_pkt_addr + (uint32_t)dev_config.offset);
+
+ if (cam_packet_util_validate_packet(csl_packet,
+ remain_len)) {
+ CAM_ERR(CAM_OIS, "Invalid packet params");
+ return -EINVAL;
+ }
+
switch (csl_packet->header.op_code & 0xFFFFFF) {
case CAM_OIS_PACKET_OPCODE_INIT:
offset = (uint32_t *)&csl_packet->payload;
@@ -477,7 +491,8 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg)
rc = cam_mem_get_cpu_buf(cmd_desc[i].mem_handle,
&generic_ptr, &len_of_buff);
if (rc < 0) {
- CAM_ERR(CAM_OIS, "Failed to get cpu buf");
+ CAM_ERR(CAM_OIS, "Failed to get cpu buf : 0x%x",
+ cmd_desc[i].mem_handle);
return rc;
}
cmd_buf = (uint32_t *)generic_ptr;
@@ -485,13 +500,22 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg)
CAM_ERR(CAM_OIS, "invalid cmd buf");
return -EINVAL;
}
+
+ if ((len_of_buff < sizeof(struct common_header)) ||
+ (cmd_desc[i].offset > (len_of_buff -
+ sizeof(struct common_header)))) {
+ CAM_ERR(CAM_OIS,
+ "Invalid length for sensor cmd");
+ return -EINVAL;
+ }
+ remain_len = len_of_buff - cmd_desc[i].offset;
cmd_buf += cmd_desc[i].offset / sizeof(uint32_t);
cmm_hdr = (struct common_header *)cmd_buf;
switch (cmm_hdr->cmd_type) {
case CAMERA_SENSOR_CMD_TYPE_I2C_INFO:
rc = cam_ois_slaveInfo_pkt_parser(
- o_ctrl, cmd_buf);
+ o_ctrl, cmd_buf, remain_len);
if (rc < 0) {
CAM_ERR(CAM_OIS,
"Failed in parsing slave info");
@@ -505,7 +529,7 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg)
rc = cam_sensor_update_power_settings(
cmd_buf,
total_cmd_buf_in_bytes,
- power_info);
+ power_info, remain_len);
if (rc) {
CAM_ERR(CAM_OIS,
"Failed: parse power settings");
@@ -625,9 +649,10 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg)
}
rc = delete_request(i2c_reg_settings);
- if (rc < 0)
+ if (rc < 0) {
CAM_ERR(CAM_OIS,
"Fail deleting Mode data: rc: %d", rc);
+ }
break;
default:
break;
diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_ois/cam_ois_core.h b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_ois/cam_ois_core.h
index d6f0ec564508..06022ababf4e 100644
--- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_ois/cam_ois_core.h
+++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_ois/cam_ois_core.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -16,6 +16,8 @@
#include <linux/dma-contiguous.h>
#include "cam_ois_dev.h"
+#define OIS_NAME_LEN 32
+
/**
* @power_info: power setting info to control the power
*
diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_ois/cam_ois_dev.c b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_ois/cam_ois_dev.c
index 5d16a4e54d04..db583340dad4 100644
--- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_ois/cam_ois_dev.c
+++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_ois/cam_ois_dev.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -229,20 +229,23 @@ static int cam_ois_i2c_driver_remove(struct i2c_client *client)
return -EINVAL;
}
+ CAM_INFO(CAM_OIS, "i2c driver remove invoked");
soc_info = &o_ctrl->soc_info;
for (i = 0; i < soc_info->num_clk; i++)
devm_clk_put(soc_info->dev, soc_info->clk[i]);
+ mutex_lock(&(o_ctrl->ois_mutex));
+ cam_ois_shutdown(o_ctrl);
+ mutex_unlock(&(o_ctrl->ois_mutex));
+ cam_unregister_subdev(&(o_ctrl->v4l2_dev_str));
+
soc_private =
(struct cam_ois_soc_private *)soc_info->soc_private;
power_info = &soc_private->power_info;
- kfree(power_info->power_setting);
- kfree(power_info->power_down_setting);
- power_info->power_setting = NULL;
- power_info->power_down_setting = NULL;
kfree(o_ctrl->soc_info.soc_private);
+ v4l2_set_subdevdata(&o_ctrl->v4l2_dev_str.sd, NULL);
kfree(o_ctrl);
return 0;
@@ -303,8 +306,6 @@ static int32_t cam_ois_platform_driver_probe(
o_ctrl->bridge_intf.device_hdl = -1;
platform_set_drvdata(pdev, o_ctrl);
- v4l2_set_subdevdata(&o_ctrl->v4l2_dev_str.sd, o_ctrl);
-
o_ctrl->cam_ois_state = CAM_OIS_INIT;
return rc;
@@ -333,21 +334,26 @@ static int cam_ois_platform_driver_remove(struct platform_device *pdev)
return -EINVAL;
}
+ CAM_INFO(CAM_OIS, "platform driver remove invoked");
soc_info = &o_ctrl->soc_info;
for (i = 0; i < soc_info->num_clk; i++)
devm_clk_put(soc_info->dev, soc_info->clk[i]);
+ mutex_lock(&(o_ctrl->ois_mutex));
+ cam_ois_shutdown(o_ctrl);
+ mutex_unlock(&(o_ctrl->ois_mutex));
+ cam_unregister_subdev(&(o_ctrl->v4l2_dev_str));
+
soc_private =
(struct cam_ois_soc_private *)o_ctrl->soc_info.soc_private;
power_info = &soc_private->power_info;
- kfree(power_info->power_setting);
- kfree(power_info->power_down_setting);
- power_info->power_setting = NULL;
- power_info->power_down_setting = NULL;
kfree(o_ctrl->soc_info.soc_private);
kfree(o_ctrl->io_master_info.cci_client);
+ platform_set_drvdata(pdev, NULL);
+ v4l2_set_subdevdata(&o_ctrl->v4l2_dev_str.sd, NULL);
kfree(o_ctrl);
+
return 0;
}
diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_sensor/cam_sensor_core.c b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_sensor/cam_sensor_core.c
index 2117cc1f9587..79e79be5ad2f 100644
--- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_sensor/cam_sensor_core.c
+++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_sensor/cam_sensor_core.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -17,6 +17,8 @@
#include "cam_soc_util.h"
#include "cam_trace.h"
#include "cam_common_util.h"
+#include "cam_packet_util.h"
+
static void cam_sensor_update_req_mgr(
struct cam_sensor_ctrl_t *s_ctrl,
@@ -94,6 +96,7 @@ static int32_t cam_sensor_i2c_pkt_parse(struct cam_sensor_ctrl_t *s_ctrl,
struct cam_cmd_buf_desc *cmd_desc = NULL;
struct i2c_settings_array *i2c_reg_settings = NULL;
size_t len_of_buff = 0;
+ size_t remain_len = 0;
uint32_t *offset = NULL;
struct cam_config_dev_cmd config;
struct i2c_data_settings *i2c_data = NULL;
@@ -115,17 +118,29 @@ static int32_t cam_sensor_i2c_pkt_parse(struct cam_sensor_ctrl_t *s_ctrl,
&generic_ptr,
&len_of_buff);
if (rc < 0) {
- CAM_ERR(CAM_SENSOR, "Failed in getting the buffer: %d", rc);
+ CAM_ERR(CAM_SENSOR, "Failed in getting the packet: %d", rc);
return rc;
}
+ remain_len = len_of_buff;
+ if ((sizeof(struct cam_packet) > len_of_buff) ||
+ ((size_t)config.offset >= len_of_buff -
+ sizeof(struct cam_packet))) {
+ CAM_ERR(CAM_SENSOR,
+ "Inval cam_packet strut size: %zu, len_of_buff: %zu",
+ sizeof(struct cam_packet), len_of_buff);
+ return -EINVAL;
+ }
+
+ remain_len -= (size_t)config.offset;
csl_packet = (struct cam_packet *)(generic_ptr +
(uint32_t)config.offset);
- if (config.offset > len_of_buff) {
- CAM_ERR(CAM_SENSOR,
- "offset is out of bounds: off: %lld len: %zu",
- config.offset, len_of_buff);
+
+ if (cam_packet_util_validate_packet(csl_packet,
+ remain_len)) {
+ CAM_ERR(CAM_SENSOR, "Invalid packet params");
return -EINVAL;
+
}
if ((csl_packet->header.op_code & 0xFFFFFF) !=
@@ -359,7 +374,7 @@ int32_t cam_sensor_update_slave_info(struct cam_cmd_probe *probe_info,
int32_t cam_handle_cmd_buffers_for_probe(void *cmd_buf,
struct cam_sensor_ctrl_t *s_ctrl,
- int32_t cmd_buf_num, int cmd_buf_length)
+ int32_t cmd_buf_num, uint32_t cmd_buf_length, size_t remain_len)
{
int32_t rc = 0;
@@ -368,6 +383,13 @@ int32_t cam_handle_cmd_buffers_for_probe(void *cmd_buf,
struct cam_cmd_i2c_info *i2c_info = NULL;
struct cam_cmd_probe *probe_info;
+ if (remain_len <
+ (sizeof(struct cam_cmd_i2c_info) +
+ sizeof(struct cam_cmd_probe))) {
+ CAM_ERR(CAM_SENSOR,
+ "not enough buffer for cam_cmd_i2c_info");
+ return -EINVAL;
+ }
i2c_info = (struct cam_cmd_i2c_info *)cmd_buf;
rc = cam_sensor_update_i2c_info(i2c_info, s_ctrl);
if (rc < 0) {
@@ -386,7 +408,8 @@ int32_t cam_handle_cmd_buffers_for_probe(void *cmd_buf,
break;
case 1: {
rc = cam_sensor_update_power_settings(cmd_buf,
- cmd_buf_length, &s_ctrl->sensordata->power_info);
+ cmd_buf_length, &s_ctrl->sensordata->power_info,
+ remain_len);
if (rc < 0) {
CAM_ERR(CAM_SENSOR,
"Failed in updating power settings");
@@ -407,10 +430,11 @@ int32_t cam_handle_mem_ptr(uint64_t handle, struct cam_sensor_ctrl_t *s_ctrl)
uint32_t *cmd_buf;
void *ptr;
size_t len;
- struct cam_packet *pkt;
- struct cam_cmd_buf_desc *cmd_desc;
+ struct cam_packet *pkt = NULL;
+ struct cam_cmd_buf_desc *cmd_desc = NULL;
uintptr_t cmd_buf1 = 0;
uintptr_t packet = 0;
+ size_t remain_len = 0;
rc = cam_mem_get_cpu_buf(handle,
&packet, &len);
@@ -418,7 +442,19 @@ int32_t cam_handle_mem_ptr(uint64_t handle, struct cam_sensor_ctrl_t *s_ctrl)
CAM_ERR(CAM_SENSOR, "Failed to get the command Buffer");
return -EINVAL;
}
+
pkt = (struct cam_packet *)packet;
+ if (pkt == NULL) {
+ CAM_ERR(CAM_SENSOR, "packet pos is invalid");
+ return -EINVAL;
+ }
+
+ if ((len < sizeof(struct cam_packet)) ||
+ (pkt->cmd_buf_offset >= (len - sizeof(struct cam_packet)))) {
+ CAM_ERR(CAM_SENSOR, "Not enough buf provided");
+ return -EINVAL;
+ }
+
cmd_desc = (struct cam_cmd_buf_desc *)
((uint32_t *)&pkt->payload + pkt->cmd_buf_offset/4);
if (cmd_desc == NULL) {
@@ -430,6 +466,7 @@ int32_t cam_handle_mem_ptr(uint64_t handle, struct cam_sensor_ctrl_t *s_ctrl)
pkt->num_cmd_buf);
return -EINVAL;
}
+
for (i = 0; i < pkt->num_cmd_buf; i++) {
if (!(cmd_desc[i].length))
continue;
@@ -440,12 +477,23 @@ int32_t cam_handle_mem_ptr(uint64_t handle, struct cam_sensor_ctrl_t *s_ctrl)
"Failed to parse the command Buffer Header");
return -EINVAL;
}
+ if (cmd_desc[i].offset >= len) {
+ CAM_ERR(CAM_SENSOR,
+ "offset past length of buffer");
+ return -EINVAL;
+ }
+ remain_len = len - cmd_desc[i].offset;
+ if (cmd_desc[i].length > remain_len) {
+ CAM_ERR(CAM_SENSOR,
+ "Not enough buffer provided for cmd");
+ return -EINVAL;
+ }
cmd_buf = (uint32_t *)cmd_buf1;
cmd_buf += cmd_desc[i].offset/4;
ptr = (void *) cmd_buf;
rc = cam_handle_cmd_buffers_for_probe(ptr, s_ctrl,
- i, cmd_desc[i].length);
+ i, cmd_desc[i].length, remain_len);
if (rc < 0) {
CAM_ERR(CAM_SENSOR,
"Failed to parse the command Buffer Header");
@@ -507,11 +555,13 @@ void cam_sensor_shutdown(struct cam_sensor_ctrl_t *s_ctrl)
cam_sensor_release_stream_rsc(s_ctrl);
cam_sensor_release_per_frame_resource(s_ctrl);
- cam_sensor_power_down(s_ctrl);
+
+ if (s_ctrl->sensor_state != CAM_SENSOR_INIT)
+ cam_sensor_power_down(s_ctrl);
rc = cam_destroy_device_hdl(s_ctrl->bridge_intf.device_hdl);
if (rc < 0)
- CAM_ERR(CAM_SENSOR, " failed destroying dhdl");
+ CAM_ERR(CAM_SENSOR, "dhdl already destroyed: rc = %d", rc);
s_ctrl->bridge_intf.device_hdl = -1;
s_ctrl->bridge_intf.link_hdl = -1;
s_ctrl->bridge_intf.session_hdl = -1;
@@ -843,7 +893,7 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl,
case CAM_CONFIG_DEV: {
rc = cam_sensor_i2c_pkt_parse(s_ctrl, arg);
if (rc < 0) {
- CAM_ERR(CAM_SENSOR, "Failed CCI Config: %d", rc);
+ CAM_ERR(CAM_SENSOR, "Failed i2c pkt parse: %d", rc);
goto release_mutex;
}
if (s_ctrl->i2c_data.init_settings.is_settings_valid &&
@@ -1215,7 +1265,6 @@ int32_t cam_sensor_flush_request(struct cam_req_mgr_flush_request *flush_req)
return -EINVAL;
}
- mutex_lock(&(s_ctrl->cam_sensor_mutex));
if (flush_req->type == CAM_REQ_MGR_FLUSH_TYPE_ALL) {
s_ctrl->last_flush_req = flush_req->req_id;
CAM_DBG(CAM_SENSOR, "last reqest to flush is %lld",
@@ -1230,7 +1279,9 @@ int32_t cam_sensor_flush_request(struct cam_req_mgr_flush_request *flush_req)
continue;
if (i2c_set->is_settings_valid == 1) {
+ mutex_lock(&(s_ctrl->cam_sensor_mutex));
rc = delete_request(i2c_set);
+ mutex_unlock(&(s_ctrl->cam_sensor_mutex));
if (rc < 0)
CAM_ERR(CAM_SENSOR,
"delete request: %lld rc: %d",
@@ -1249,6 +1300,5 @@ int32_t cam_sensor_flush_request(struct cam_req_mgr_flush_request *flush_req)
CAM_DBG(CAM_SENSOR,
"Flush request id:%lld not found in the pending list",
flush_req->req_id);
- mutex_unlock(&(s_ctrl->cam_sensor_mutex));
return rc;
}
diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_sensor/cam_sensor_dev.c b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_sensor/cam_sensor_dev.c
index 8dcb6c73312f..5c5c97099d43 100644
--- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_sensor/cam_sensor_dev.c
+++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_sensor/cam_sensor_dev.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -199,7 +199,7 @@ static int32_t cam_sensor_driver_i2c_probe(struct i2c_client *client,
s_ctrl->bridge_intf.ops.flush_req = cam_sensor_flush_request;
s_ctrl->sensordata->power_info.dev = soc_info->dev;
- v4l2_set_subdevdata(&(s_ctrl->v4l2_dev_str.sd), s_ctrl);
+
return rc;
unreg_subdev:
cam_unregister_subdev(&(s_ctrl->v4l2_dev_str));
@@ -220,11 +220,18 @@ static int cam_sensor_platform_remove(struct platform_device *pdev)
return 0;
}
+ CAM_INFO(CAM_SENSOR, "platform remove invoked");
+ mutex_lock(&(s_ctrl->cam_sensor_mutex));
+ cam_sensor_shutdown(s_ctrl);
+ mutex_unlock(&(s_ctrl->cam_sensor_mutex));
+ cam_unregister_subdev(&(s_ctrl->v4l2_dev_str));
soc_info = &s_ctrl->soc_info;
for (i = 0; i < soc_info->num_clk; i++)
devm_clk_put(soc_info->dev, soc_info->clk[i]);
kfree(s_ctrl->i2c_data.per_frame);
+ platform_set_drvdata(pdev, NULL);
+ v4l2_set_subdevdata(&(s_ctrl->v4l2_dev_str.sd), NULL);
devm_kfree(&pdev->dev, s_ctrl);
return 0;
@@ -241,11 +248,17 @@ static int cam_sensor_driver_i2c_remove(struct i2c_client *client)
return 0;
}
+ CAM_INFO(CAM_SENSOR, "i2c remove invoked");
+ mutex_lock(&(s_ctrl->cam_sensor_mutex));
+ cam_sensor_shutdown(s_ctrl);
+ mutex_unlock(&(s_ctrl->cam_sensor_mutex));
+ cam_unregister_subdev(&(s_ctrl->v4l2_dev_str));
soc_info = &s_ctrl->soc_info;
for (i = 0; i < soc_info->num_clk; i++)
devm_clk_put(soc_info->dev, soc_info->clk[i]);
kfree(s_ctrl->i2c_data.per_frame);
+ v4l2_set_subdevdata(&(s_ctrl->v4l2_dev_str.sd), NULL);
kfree(s_ctrl);
return 0;
@@ -323,8 +336,6 @@ static int32_t cam_sensor_driver_platform_probe(
s_ctrl->sensordata->power_info.dev = &pdev->dev;
platform_set_drvdata(pdev, s_ctrl);
- v4l2_set_subdevdata(&(s_ctrl->v4l2_dev_str.sd), s_ctrl);
-
s_ctrl->sensor_state = CAM_SENSOR_INIT;
return rc;
diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c
index 713bcaa8643a..b062520221fe 100644
--- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c
+++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -298,6 +298,8 @@ int cam_sensor_i2c_command_parser(
size_t len_of_buff = 0;
uintptr_t generic_ptr;
uint16_t cmd_length_in_bytes = 0;
+ size_t remain_len = 0;
+ size_t tot_size = 0;
for (i = 0; i < num_cmd_buffers; i++) {
uint32_t *cmd_buf = NULL;
@@ -319,16 +321,34 @@ int cam_sensor_i2c_command_parser(
rc = cam_mem_get_cpu_buf(cmd_desc[i].mem_handle,
&generic_ptr, &len_of_buff);
- cmd_buf = (uint32_t *)generic_ptr;
if (rc < 0) {
CAM_ERR(CAM_SENSOR,
"cmd hdl failed:%d, Err: %d, Buffer_len: %zd",
cmd_desc[i].mem_handle, rc, len_of_buff);
return rc;
}
+
+ remain_len = len_of_buff;
+ if ((len_of_buff < sizeof(struct common_header)) ||
+ (cmd_desc[i].offset >
+ (len_of_buff - sizeof(struct common_header)))) {
+ CAM_ERR(CAM_SENSOR, "buffer provided too small");
+ return -EINVAL;
+ }
+ cmd_buf = (uint32_t *)generic_ptr;
cmd_buf += cmd_desc[i].offset / sizeof(uint32_t);
+ if (remain_len < cmd_desc[i].length) {
+ CAM_ERR(CAM_SENSOR, "buffer provided too small");
+ return -EINVAL;
+ }
+
while (byte_cnt < cmd_desc[i].length) {
+ if ((remain_len - byte_cnt) <
+ sizeof(struct common_header)) {
+ CAM_ERR(CAM_SENSOR, "Not enough buffer");
+ return -EINVAL;
+ }
cmm_hdr = (struct common_header *)cmd_buf;
generic_op_code = cmm_hdr->third_byte;
switch (cmm_hdr->cmd_type) {
@@ -338,6 +358,22 @@ int cam_sensor_i2c_command_parser(
*cam_cmd_i2c_random_wr =
(struct cam_cmd_i2c_random_wr *)cmd_buf;
+ if ((remain_len - byte_cnt) <
+ sizeof(struct cam_cmd_i2c_random_wr)) {
+ CAM_ERR(CAM_SENSOR,
+ "Not enough buffer provided");
+ return -EINVAL;
+ }
+ tot_size = sizeof(struct i2c_rdwr_header) +
+ (sizeof(struct i2c_random_wr_payload) *
+ cam_cmd_i2c_random_wr->header.count);
+
+ if (tot_size > (remain_len - byte_cnt)) {
+ CAM_ERR(CAM_SENSOR,
+ "Not enough buffer provided");
+ return -EINVAL;
+ }
+
rc = cam_sensor_handle_random_write(
cam_cmd_i2c_random_wr,
i2c_reg_settings,
@@ -345,7 +381,7 @@ int cam_sensor_i2c_command_parser(
if (rc < 0) {
CAM_ERR(CAM_SENSOR,
"Failed in random write %d", rc);
- return rc;
+ return -EINVAL;
}
cmd_buf += cmd_length_in_bytes /
@@ -360,6 +396,24 @@ int cam_sensor_i2c_command_parser(
(struct cam_cmd_i2c_continuous_wr *)
cmd_buf;
+ if ((remain_len - byte_cnt) <
+ sizeof(struct cam_cmd_i2c_continuous_wr)) {
+ CAM_ERR(CAM_SENSOR,
+ "Not enough buffer provided");
+ return -EINVAL;
+ }
+
+ tot_size = sizeof(struct i2c_rdwr_header) +
+ sizeof(cam_cmd_i2c_continuous_wr->reg_addr) +
+ (sizeof(struct cam_cmd_read) *
+ cam_cmd_i2c_continuous_wr->header.count);
+
+ if (tot_size > (remain_len - byte_cnt)) {
+ CAM_ERR(CAM_SENSOR,
+ "Not enough buffer provided");
+ return -EINVAL;
+ }
+
rc = cam_sensor_handle_continuous_write(
cam_cmd_i2c_continuous_wr,
i2c_reg_settings,
@@ -376,11 +430,16 @@ int cam_sensor_i2c_command_parser(
break;
}
case CAMERA_SENSOR_CMD_TYPE_WAIT: {
+ if ((remain_len - byte_cnt) <
+ sizeof(struct cam_cmd_unconditional_wait)) {
+ CAM_ERR(CAM_SENSOR,
+ "Not enough buffer space");
+ return -EINVAL;
+ }
if (generic_op_code ==
CAMERA_SENSOR_WAIT_OP_HW_UCND ||
generic_op_code ==
CAMERA_SENSOR_WAIT_OP_SW_UCND) {
-
rc = cam_sensor_handle_delay(
&cmd_buf, generic_op_code,
i2c_reg_settings, j, &byte_cnt,
@@ -412,12 +471,18 @@ int cam_sensor_i2c_command_parser(
break;
}
case CAMERA_SENSOR_CMD_TYPE_I2C_INFO: {
+ if (remain_len - byte_cnt <
+ sizeof(struct cam_cmd_i2c_info)) {
+ CAM_ERR(CAM_SENSOR,
+ "Not enough buffer space");
+ return -EINVAL;
+ }
rc = cam_sensor_handle_slave_info(
io_master, cmd_buf);
if (rc) {
CAM_ERR(CAM_SENSOR,
- "Handle slave info failed with rc: %d",
- rc);
+ "Handle slave info failed with rc: %d",
+ rc);
return rc;
}
cmd_length_in_bytes =
@@ -750,8 +815,32 @@ int cam_sensor_util_request_gpio_table(
return rc;
}
+
+static int32_t cam_sensor_validate(void *ptr, size_t remain_buf)
+{
+ struct common_header *cmm_hdr = (struct common_header *)ptr;
+ size_t validate_size = 0;
+
+ if (remain_buf < sizeof(struct common_header))
+ return -EINVAL;
+
+ if (cmm_hdr->cmd_type == CAMERA_SENSOR_CMD_TYPE_PWR_UP ||
+ cmm_hdr->cmd_type == CAMERA_SENSOR_CMD_TYPE_PWR_DOWN)
+ validate_size = sizeof(struct cam_cmd_power);
+ else if (cmm_hdr->cmd_type == CAMERA_SENSOR_CMD_TYPE_WAIT)
+ validate_size = sizeof(struct cam_cmd_unconditional_wait);
+
+ if (remain_buf < validate_size) {
+ CAM_ERR(CAM_SENSOR, "Invalid cmd_buf len %zu min %zu",
+ remain_buf, validate_size);
+ return -EINVAL;
+ }
+ return 0;
+}
+
int32_t cam_sensor_update_power_settings(void *cmd_buf,
- int cmd_length, struct cam_sensor_power_ctrl_t *power_info)
+ uint32_t cmd_length, struct cam_sensor_power_ctrl_t *power_info,
+ size_t cmd_buf_len)
{
int32_t rc = 0, tot_size = 0, last_cmd_type = 0;
int32_t i = 0, pwr_up = 0, pwr_down = 0;
@@ -760,7 +849,8 @@ int32_t cam_sensor_update_power_settings(void *cmd_buf,
struct cam_cmd_power *pwr_cmd = (struct cam_cmd_power *)cmd_buf;
struct common_header *cmm_hdr = (struct common_header *)cmd_buf;
- if (!pwr_cmd || !cmd_length) {
+ if (!pwr_cmd || !cmd_length || cmd_buf_len < (size_t)cmd_length ||
+ cam_sensor_validate(cmd_buf, cmd_buf_len)) {
CAM_ERR(CAM_SENSOR, "Invalid Args: pwr_cmd %pK, cmd_length: %d",
pwr_cmd, cmd_length);
return -EINVAL;
@@ -787,16 +877,29 @@ int32_t cam_sensor_update_power_settings(void *cmd_buf,
}
while (tot_size < cmd_length) {
+ if (cam_sensor_validate(ptr, (cmd_length - tot_size))) {
+ rc = -EINVAL;
+ goto free_power_settings;
+ }
if (cmm_hdr->cmd_type ==
CAMERA_SENSOR_CMD_TYPE_PWR_UP) {
struct cam_cmd_power *pwr_cmd =
(struct cam_cmd_power *)ptr;
+ if ((U16_MAX - power_info->power_setting_size) <
+ pwr_cmd->count) {
+ CAM_ERR(CAM_SENSOR, "ERR: Overflow occurs");
+ rc = -EINVAL;
+ goto free_power_settings;
+ }
+
power_info->power_setting_size += pwr_cmd->count;
- if (power_info->power_setting_size > MAX_POWER_CONFIG) {
+ if ((power_info->power_setting_size > MAX_POWER_CONFIG)
+ || (pwr_cmd->count >= SENSOR_SEQ_TYPE_MAX)) {
CAM_ERR(CAM_SENSOR,
- "Invalid: power up setting size %d",
- power_info->power_setting_size);
+ "pwr_up setting size %d, pwr_cmd->count: %d",
+ power_info->power_setting_size,
+ pwr_cmd->count);
rc = -EINVAL;
goto free_power_settings;
}
@@ -891,12 +994,21 @@ int32_t cam_sensor_update_power_settings(void *cmd_buf,
scr = ptr + sizeof(struct cam_cmd_power);
tot_size = tot_size + sizeof(struct cam_cmd_power);
+ if ((U16_MAX - power_info->power_down_setting_size) <
+ pwr_cmd->count) {
+ CAM_ERR(CAM_SENSOR, "ERR: Overflow");
+ rc = -EINVAL;
+ goto free_power_settings;
+ }
+
power_info->power_down_setting_size += pwr_cmd->count;
- if (power_info->power_down_setting_size >
- MAX_POWER_CONFIG) {
+ if ((power_info->power_down_setting_size >
+ MAX_POWER_CONFIG) || (pwr_cmd->count >=
+ SENSOR_SEQ_TYPE_MAX)) {
CAM_ERR(CAM_SENSOR,
- "Invalid: power down setting size %d",
- power_info->power_down_setting_size);
+ "pwr_down_setting_size %d, pwr_cmd->count: %d",
+ power_info->power_down_setting_size,
+ pwr_cmd->count);
rc = -EINVAL;
goto free_power_settings;
}
diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_sensor_utils/cam_sensor_util.h b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_sensor_utils/cam_sensor_util.h
index 583ddb14243b..85497fda011c 100644
--- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_sensor_utils/cam_sensor_util.h
+++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_sensor_utils/cam_sensor_util.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -60,7 +60,8 @@ int msm_camera_fill_vreg_params(struct cam_hw_soc_info *soc_info,
uint16_t power_setting_size);
int32_t cam_sensor_update_power_settings(void *cmd_buf,
- int cmd_length, struct cam_sensor_power_ctrl_t *power_info);
+ uint32_t cmd_length, struct cam_sensor_power_ctrl_t *power_info,
+ size_t cmd_buf_len);
int cam_sensor_bob_pwm_mode_switch(struct cam_hw_soc_info *soc_info,
int bob_reg_idx, bool flag);
diff --git a/drivers/media/platform/msm/camera_v3/cam_utils/cam_packet_util.c b/drivers/media/platform/msm/camera_v3/cam_utils/cam_packet_util.c
index acfae3622130..d2b965078524 100644
--- a/drivers/media/platform/msm/camera_v3/cam_utils/cam_packet_util.c
+++ b/drivers/media/platform/msm/camera_v3/cam_utils/cam_packet_util.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -50,23 +50,43 @@ int cam_packet_util_validate_cmd_desc(struct cam_cmd_buf_desc *cmd_desc)
return 0;
}
-int cam_packet_util_validate_packet(struct cam_packet *packet)
+int cam_packet_util_validate_packet(struct cam_packet *packet,
+ size_t remain_len)
{
+ size_t sum_cmd_desc = 0;
+ size_t sum_io_cfgs = 0;
+ size_t sum_patch_desc = 0;
+ size_t pkt_wo_payload = 0;
+
if (!packet)
return -EINVAL;
+ if ((size_t)packet->header.size > remain_len) {
+ CAM_ERR(CAM_UTIL,
+ "Invalid packet size: %zu, CPU buf length: %zu",
+ (size_t)packet->header.size, remain_len);
+ return -EINVAL;
+ }
+
CAM_DBG(CAM_UTIL, "num cmd buf:%d num of io config:%d kmd buf index:%d",
packet->num_cmd_buf, packet->num_io_configs,
packet->kmd_cmd_buf_index);
- if ((packet->kmd_cmd_buf_index >= packet->num_cmd_buf) ||
- (!packet->header.size) ||
- (packet->cmd_buf_offset > packet->header.size) ||
- (packet->io_configs_offset > packet->header.size)) {
- CAM_ERR(CAM_UTIL, "invalid packet:%d %d %d %d %d",
- packet->kmd_cmd_buf_index,
- packet->num_cmd_buf, packet->cmd_buf_offset,
- packet->io_configs_offset, packet->header.size);
+ sum_cmd_desc = packet->num_cmd_buf * sizeof(struct cam_cmd_buf_desc);
+ sum_io_cfgs = packet->num_io_configs * sizeof(struct cam_buf_io_cfg);
+ sum_patch_desc = packet->num_patches * sizeof(struct cam_patch_desc);
+ pkt_wo_payload = offsetof(struct cam_packet, payload);
+
+ if ((!packet->header.size) ||
+ ((pkt_wo_payload + (size_t)packet->cmd_buf_offset +
+ sum_cmd_desc) > (size_t)packet->header.size) ||
+ ((pkt_wo_payload + (size_t)packet->io_configs_offset +
+ sum_io_cfgs) > (size_t)packet->header.size) ||
+ ((pkt_wo_payload + (size_t)packet->patch_offset +
+ sum_patch_desc) > (size_t)packet->header.size)) {
+ CAM_ERR(CAM_UTIL, "params not within mem len:%zu %zu %zu %zu",
+ (size_t)packet->header.size, sum_cmd_desc,
+ sum_io_cfgs, sum_patch_desc);
return -EINVAL;
}
@@ -78,6 +98,7 @@ int cam_packet_util_get_kmd_buffer(struct cam_packet *packet,
{
int rc = 0;
size_t len = 0;
+ size_t remain_len = 0;
struct cam_cmd_buf_desc *cmd_desc;
uint32_t *cpu_addr;
@@ -86,6 +107,13 @@ int cam_packet_util_get_kmd_buffer(struct cam_packet *packet,
return -EINVAL;
}
+ if ((packet->kmd_cmd_buf_index < 0) ||
+ (packet->kmd_cmd_buf_index > packet->num_cmd_buf)) {
+ CAM_ERR(CAM_UTIL, "Invalid kmd buf index: %d",
+ packet->kmd_cmd_buf_index);
+ return -EINVAL;
+ }
+
/* Take first command descriptor and add offset to it for kmd*/
cmd_desc = (struct cam_cmd_buf_desc *) ((uint8_t *)
&packet->payload + packet->cmd_buf_offset);
@@ -100,12 +128,21 @@ int cam_packet_util_get_kmd_buffer(struct cam_packet *packet,
if (rc)
return rc;
- if (len < cmd_desc->size) {
+ remain_len = len;
+ if (((size_t)cmd_desc->offset >= len) ||
+ ((size_t)cmd_desc->size >= (len - (size_t)cmd_desc->offset))) {
CAM_ERR(CAM_UTIL, "invalid memory len:%zd and cmd desc size:%d",
len, cmd_desc->size);
return -EINVAL;
}
+ remain_len -= (size_t)cmd_desc->offset;
+ if ((size_t)packet->kmd_cmd_buf_offset >= remain_len) {
+ CAM_ERR(CAM_UTIL, "Invalid kmd cmd buf offset: %zu",
+ (size_t)packet->kmd_cmd_buf_offset);
+ return -EINVAL;
+ }
+
cpu_addr += (cmd_desc->offset / 4) + (packet->kmd_cmd_buf_offset / 4);
CAM_DBG(CAM_UTIL, "total size %d, cmd size: %d, KMD buffer size: %d",
cmd_desc->size, cmd_desc->length,
@@ -128,7 +165,7 @@ int cam_packet_util_process_patches(struct cam_packet *packet,
{
struct cam_patch_desc *patch_desc = NULL;
dma_addr_t iova_addr;
- uintptr_t cpu_addr;
+ uintptr_t cpu_addr = 0;
uint32_t temp;
uint32_t *dst_cpu_addr;
uint32_t *src_buf_iova_addr;
@@ -161,7 +198,7 @@ int cam_packet_util_process_patches(struct cam_packet *packet,
rc = cam_mem_get_cpu_buf(patch_desc[i].dst_buf_hdl,
&cpu_addr, &dst_buf_len);
- if (rc < 0) {
+ if (rc < 0 || !cpu_addr || (dst_buf_len == 0)) {
CAM_ERR(CAM_UTIL, "unable to get dst buf address");
return rc;
}
@@ -171,6 +208,20 @@ int cam_packet_util_process_patches(struct cam_packet *packet,
patch_desc[i].dst_buf_hdl, patch_desc[i].dst_offset,
patch_desc[i].src_buf_hdl, patch_desc[i].src_offset);
+ if ((size_t)patch_desc[i].src_offset >= src_buf_size) {
+ CAM_ERR(CAM_UTIL,
+ "Invalid src buf patch offset");
+ return -EINVAL;
+ }
+
+ if ((dst_buf_len < sizeof(void *)) ||
+ ((dst_buf_len - sizeof(void *)) <
+ (size_t)patch_desc[i].dst_offset)) {
+ CAM_ERR(CAM_UTIL,
+ "Invalid dst buf patch offset");
+ return -EINVAL;
+ }
+
dst_cpu_addr = (uint32_t *)((uint8_t *)dst_cpu_addr +
patch_desc[i].dst_offset);
temp += patch_desc[i].src_offset;
@@ -191,8 +242,9 @@ int cam_packet_util_process_generic_cmd_buffer(
cam_packet_generic_blob_handler blob_handler_cb, void *user_data)
{
int rc;
- uintptr_t cpu_addr;
+ uintptr_t cpu_addr = 0;
size_t buf_size;
+ size_t remain_len = 0;
uint32_t *blob_ptr;
uint32_t blob_type, blob_size, blob_block_size, len_read;
@@ -215,6 +267,21 @@ int cam_packet_util_process_generic_cmd_buffer(
return rc;
}
+ remain_len = buf_size;
+ if ((buf_size < sizeof(uint32_t)) ||
+ ((size_t)cmd_buf->offset > (buf_size - sizeof(uint32_t)))) {
+ CAM_ERR(CAM_UTIL, "Invalid offset for cmd buf: %zu",
+ (size_t)cmd_buf->offset);
+ return -EINVAL;
+ }
+
+ remain_len -= (size_t)cmd_buf->offset;
+ if (remain_len < (size_t)cmd_buf->length) {
+ CAM_ERR(CAM_UTIL, "Invalid length for cmd buf: %zu",
+ (size_t)cmd_buf->length);
+ return -EINVAL;
+ }
+
blob_ptr = (uint32_t *)(((uint8_t *)cpu_addr) +
cmd_buf->offset);
diff --git a/drivers/media/platform/msm/camera_v3/cam_utils/cam_packet_util.h b/drivers/media/platform/msm/camera_v3/cam_utils/cam_packet_util.h
index b2315232262d..284f0a520aed 100644
--- a/drivers/media/platform/msm/camera_v3/cam_utils/cam_packet_util.h
+++ b/drivers/media/platform/msm/camera_v3/cam_utils/cam_packet_util.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -59,10 +59,13 @@ int cam_packet_util_get_cmd_mem_addr(int handle, uint32_t **buf_addr,
*
* @packet: Packet to be validated
*
+ * @remain_len: CPU buff length after config offset
+ *
* @return: 0 for success
* -EINVAL for Fail
*/
-int cam_packet_util_validate_packet(struct cam_packet *packet);
+int cam_packet_util_validate_packet(struct cam_packet *packet,
+ size_t remain_len);
/**
* cam_packet_util_validate_cmd_desc()
diff --git a/drivers/media/platform/msm/vidc/hfi_response_handler.c b/drivers/media/platform/msm/vidc/hfi_response_handler.c
index 0cdcbd6e0df1..eed2fa473014 100644
--- a/drivers/media/platform/msm/vidc/hfi_response_handler.c
+++ b/drivers/media/platform/msm/vidc/hfi_response_handler.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -776,6 +776,11 @@ static int hfi_fill_codec_info(u8 *data_ptr,
vidc_get_hal_codec((1 << i) & codecs);
capability->domain =
vidc_get_hal_domain(HFI_VIDEO_DOMAIN_DECODER);
+ if (codec_count == VIDC_MAX_DECODE_SESSIONS) {
+ dprintk(VIDC_ERR,
+ "Max supported decoder sessions reached");
+ break;
+ }
}
}
codecs = sys_init_done->enc_codec_supported;
@@ -787,6 +792,11 @@ static int hfi_fill_codec_info(u8 *data_ptr,
vidc_get_hal_codec((1 << i) & codecs);
capability->domain =
vidc_get_hal_domain(HFI_VIDEO_DOMAIN_ENCODER);
+ if (codec_count == VIDC_MAX_SESSIONS) {
+ dprintk(VIDC_ERR,
+ "Max supported sessions reached");
+ break;
+ }
}
}
sys_init_done->codec_count = codec_count;
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index 7c01a185d2cd..d8478fd5a903 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -327,7 +327,7 @@ static int __write_queue(struct vidc_iface_q_info *qinfo, u8 *packet,
{
struct hfi_queue_header *queue;
u32 packet_size_in_words, new_write_idx;
- u32 empty_space, read_idx;
+ u32 empty_space, read_idx, write_idx;
u32 *write_ptr;
if (!qinfo || !packet) {
@@ -350,16 +350,18 @@ static int __write_queue(struct vidc_iface_q_info *qinfo, u8 *packet,
}
packet_size_in_words = (*(u32 *)packet) >> 2;
- if (!packet_size_in_words) {
- dprintk(VIDC_ERR, "Zero packet size\n");
+ if (!packet_size_in_words || packet_size_in_words >
+ qinfo->q_array.mem_size>>2) {
+ dprintk(VIDC_ERR, "Invalid packet size\n");
return -ENODATA;
}
read_idx = queue->qhdr_read_idx;
+ write_idx = queue->qhdr_write_idx;
- empty_space = (queue->qhdr_write_idx >= read_idx) ?
- (queue->qhdr_q_size - (queue->qhdr_write_idx - read_idx)) :
- (read_idx - queue->qhdr_write_idx);
+ empty_space = (write_idx >= read_idx) ?
+ ((qinfo->q_array.mem_size>>2) - (write_idx - read_idx)) :
+ (read_idx - write_idx);
if (empty_space <= packet_size_in_words) {
queue->qhdr_tx_req = 1;
dprintk(VIDC_ERR, "Insufficient size (%d) to write (%d)\n",
@@ -369,13 +371,20 @@ static int __write_queue(struct vidc_iface_q_info *qinfo, u8 *packet,
queue->qhdr_tx_req = 0;
- new_write_idx = (queue->qhdr_write_idx + packet_size_in_words);
+ new_write_idx = write_idx + packet_size_in_words;
write_ptr = (u32 *)((qinfo->q_array.align_virtual_addr) +
- (queue->qhdr_write_idx << 2));
- if (new_write_idx < queue->qhdr_q_size) {
+ (write_idx << 2));
+ if (write_ptr < (u32 *)qinfo->q_array.align_virtual_addr ||
+ write_ptr > (u32 *)(qinfo->q_array.align_virtual_addr +
+ qinfo->q_array.mem_size)) {
+ dprintk(VIDC_ERR, "Invalid write index");
+ return -ENODATA;
+ }
+
+ if (new_write_idx < (qinfo->q_array.mem_size >> 2)) {
memcpy(write_ptr, packet, packet_size_in_words << 2);
} else {
- new_write_idx -= queue->qhdr_q_size;
+ new_write_idx -= qinfo->q_array.mem_size >> 2;
memcpy(write_ptr, packet, (packet_size_in_words -
new_write_idx) << 2);
memcpy((void *)qinfo->q_array.align_virtual_addr,
@@ -471,7 +480,8 @@ static int __read_queue(struct vidc_iface_q_info *qinfo, u8 *packet,
u32 packet_size_in_words, new_read_idx;
u32 *read_ptr;
u32 receive_request = 0;
- int rc = 0;
+ u32 read_idx, write_idx;
+ int rc = 0;
if (!qinfo || !packet || !pb_tx_req_is_set) {
dprintk(VIDC_ERR, "Invalid Params\n");
@@ -504,7 +514,10 @@ static int __read_queue(struct vidc_iface_q_info *qinfo, u8 *packet,
if (queue->qhdr_type & HFI_Q_ID_CTRL_TO_HOST_MSG_Q)
receive_request = 1;
- if (queue->qhdr_read_idx == queue->qhdr_write_idx) {
+ read_idx = queue->qhdr_read_idx;
+ write_idx = queue->qhdr_write_idx;
+
+ if (read_idx == write_idx) {
queue->qhdr_rx_req = receive_request;
/*
* mb() to ensure qhdr is updated in main memory
@@ -521,21 +534,28 @@ static int __read_queue(struct vidc_iface_q_info *qinfo, u8 *packet,
}
read_ptr = (u32 *)((qinfo->q_array.align_virtual_addr) +
- (queue->qhdr_read_idx << 2));
+ (read_idx << 2));
+ if (read_ptr < (u32 *)qinfo->q_array.align_virtual_addr ||
+ read_ptr > (u32 *)(qinfo->q_array.align_virtual_addr +
+ qinfo->q_array.mem_size - sizeof(*read_ptr))) {
+ dprintk(VIDC_ERR, "Invalid read index\n");
+ return -ENODATA;
+ }
+
packet_size_in_words = (*read_ptr) >> 2;
if (!packet_size_in_words) {
dprintk(VIDC_ERR, "Zero packet size\n");
return -ENODATA;
}
- new_read_idx = queue->qhdr_read_idx + packet_size_in_words;
- if (((packet_size_in_words << 2) <= VIDC_IFACEQ_VAR_HUGE_PKT_SIZE)
- && queue->qhdr_read_idx <= queue->qhdr_q_size) {
- if (new_read_idx < queue->qhdr_q_size) {
+ new_read_idx = read_idx + packet_size_in_words;
+ if (((packet_size_in_words << 2) <= VIDC_IFACEQ_VAR_HUGE_PKT_SIZE) &&
+ read_idx <= (qinfo->q_array.mem_size >> 2)) {
+ if (new_read_idx < (qinfo->q_array.mem_size >> 2)) {
memcpy(packet, read_ptr,
packet_size_in_words << 2);
} else {
- new_read_idx -= queue->qhdr_q_size;
+ new_read_idx -= (qinfo->q_array.mem_size >> 2);
memcpy(packet, read_ptr,
(packet_size_in_words - new_read_idx) << 2);
memcpy(packet + ((packet_size_in_words -
@@ -546,18 +566,18 @@ static int __read_queue(struct vidc_iface_q_info *qinfo, u8 *packet,
} else {
dprintk(VIDC_WARN,
"BAD packet received, read_idx: %#x, pkt_size: %d\n",
- queue->qhdr_read_idx, packet_size_in_words << 2);
+ read_idx, packet_size_in_words << 2);
dprintk(VIDC_WARN, "Dropping this packet\n");
- new_read_idx = queue->qhdr_write_idx;
+ new_read_idx = write_idx;
rc = -ENODATA;
}
- queue->qhdr_read_idx = new_read_idx;
-
- if (queue->qhdr_read_idx != queue->qhdr_write_idx)
+ if (new_read_idx != write_idx)
queue->qhdr_rx_req = 0;
else
queue->qhdr_rx_req = receive_request;
+
+ queue->qhdr_read_idx = new_read_idx;
/*
* mb() to ensure qhdr is updated in main memory
* so that venus reads the updated header values
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
index f69b98e828b6..f1fbf990daef 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_api.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -66,6 +66,9 @@
/* 16 encoder and 16 decoder sessions */
#define VIDC_MAX_SESSIONS 32
+#define VIDC_MAX_DECODE_SESSIONS 16
+#define VIDC_MAX_ENCODE_SESSIONS 16
+
enum vidc_status {
VIDC_ERR_NONE = 0x0,
diff --git a/drivers/media/platform/msm/vidc_3x/hfi_response_handler.c b/drivers/media/platform/msm/vidc_3x/hfi_response_handler.c
index ca9edc8bebd1..8eaf1fd192af 100644
--- a/drivers/media/platform/msm/vidc_3x/hfi_response_handler.c
+++ b/drivers/media/platform/msm/vidc_3x/hfi_response_handler.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -608,6 +608,11 @@ static int hfi_fill_codec_info(u8 *data_ptr,
vidc_get_hal_codec((1 << i) & codecs);
capability->domain =
vidc_get_hal_domain(HFI_VIDEO_DOMAIN_DECODER);
+ if (codec_count == VIDC_MAX_DECODE_SESSIONS) {
+ dprintk(VIDC_ERR,
+ "Max supported decoder sessions reached\n");
+ break;
+ }
}
}
codecs = sys_init_done->enc_codec_supported;
@@ -619,6 +624,11 @@ static int hfi_fill_codec_info(u8 *data_ptr,
vidc_get_hal_codec((1 << i) & codecs);
capability->domain =
vidc_get_hal_domain(HFI_VIDEO_DOMAIN_ENCODER);
+ if (codec_count == VIDC_MAX_SESSIONS) {
+ dprintk(VIDC_ERR,
+ "Max supported sessions reached\n");
+ break;
+ }
}
}
sys_init_done->codec_count = codec_count;
diff --git a/drivers/media/platform/msm/vidc_3x/msm_vidc_common.c b/drivers/media/platform/msm/vidc_3x/msm_vidc_common.c
index 22f49ce02e47..af2514c60065 100644
--- a/drivers/media/platform/msm/vidc_3x/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc_3x/msm_vidc_common.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -1638,11 +1638,11 @@ static void msm_comm_clean_notify_client(struct msm_vidc_core *core)
list_for_each_entry(inst, &core->instances, list) {
mutex_lock(&inst->lock);
inst->state = MSM_VIDC_CORE_INVALID;
- mutex_unlock(&inst->lock);
dprintk(VIDC_WARN,
"%s Send sys error for inst %pK\n", __func__, inst);
msm_vidc_queue_v4l2_event(inst,
V4L2_EVENT_MSM_VIDC_SYS_ERROR);
+ mutex_unlock(&inst->lock);
}
mutex_unlock(&core->lock);
}
diff --git a/drivers/media/platform/msm/vidc_3x/venus_hfi.c b/drivers/media/platform/msm/vidc_3x/venus_hfi.c
index 1bd6ae8959cf..2db49fa558f5 100644
--- a/drivers/media/platform/msm/vidc_3x/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc_3x/venus_hfi.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2016, 2018 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2016, 2018-2019 The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -330,7 +330,7 @@ static int __write_queue(struct vidc_iface_q_info *qinfo, u8 *packet,
{
struct hfi_queue_header *queue;
u32 packet_size_in_words, new_write_idx;
- u32 empty_space, read_idx;
+ u32 empty_space, read_idx, write_idx;
u32 *write_ptr;
if (!qinfo || !packet) {
@@ -353,16 +353,18 @@ static int __write_queue(struct vidc_iface_q_info *qinfo, u8 *packet,
}
packet_size_in_words = (*(u32 *)packet) >> 2;
- if (!packet_size_in_words) {
- dprintk(VIDC_ERR, "Zero packet size\n");
+ if (!packet_size_in_words || packet_size_in_words >
+ qinfo->q_array.mem_size>>2) {
+ dprintk(VIDC_ERR, "Invalid packet size\n");
return -ENODATA;
}
read_idx = queue->qhdr_read_idx;
+ write_idx = queue->qhdr_write_idx;
- empty_space = (queue->qhdr_write_idx >= read_idx) ?
- (queue->qhdr_q_size - (queue->qhdr_write_idx - read_idx)) :
- (read_idx - queue->qhdr_write_idx);
+ empty_space = (write_idx >= read_idx) ?
+ ((qinfo->q_array.mem_size>>2) - (write_idx - read_idx)) :
+ (read_idx - write_idx);
if (empty_space <= packet_size_in_words) {
queue->qhdr_tx_req = 1;
dprintk(VIDC_ERR, "Insufficient size (%d) to write (%d)\n",
@@ -372,13 +374,20 @@ static int __write_queue(struct vidc_iface_q_info *qinfo, u8 *packet,
queue->qhdr_tx_req = 0;
- new_write_idx = (queue->qhdr_write_idx + packet_size_in_words);
+ new_write_idx = write_idx + packet_size_in_words;
write_ptr = (u32 *)((qinfo->q_array.align_virtual_addr) +
- (queue->qhdr_write_idx << 2));
- if (new_write_idx < queue->qhdr_q_size) {
+ (write_idx << 2));
+ if (write_ptr < (u32 *)qinfo->q_array.align_virtual_addr ||
+ write_ptr > (u32 *)(qinfo->q_array.align_virtual_addr +
+ qinfo->q_array.mem_size)) {
+ dprintk(VIDC_ERR, "Invalid write index");
+ return -ENODATA;
+ }
+
+ if (new_write_idx < (qinfo->q_array.mem_size >> 2)) {
memcpy(write_ptr, packet, packet_size_in_words << 2);
} else {
- new_write_idx -= queue->qhdr_q_size;
+ new_write_idx -= qinfo->q_array.mem_size >> 2;
memcpy(write_ptr, packet, (packet_size_in_words -
new_write_idx) << 2);
memcpy((void *)qinfo->q_array.align_virtual_addr,
@@ -472,7 +481,8 @@ static int __read_queue(struct vidc_iface_q_info *qinfo, u8 *packet,
u32 packet_size_in_words, new_read_idx;
u32 *read_ptr;
u32 receive_request = 0;
- int rc = 0;
+ u32 read_idx, write_idx;
+ int rc = 0;
if (!qinfo || !packet || !pb_tx_req_is_set) {
dprintk(VIDC_ERR, "Invalid Params\n");
@@ -504,7 +514,10 @@ static int __read_queue(struct vidc_iface_q_info *qinfo, u8 *packet,
if (queue->qhdr_type & HFI_Q_ID_CTRL_TO_HOST_MSG_Q)
receive_request = 1;
- if (queue->qhdr_read_idx == queue->qhdr_write_idx) {
+ read_idx = queue->qhdr_read_idx;
+ write_idx = queue->qhdr_write_idx;
+
+ if (read_idx == write_idx) {
queue->qhdr_rx_req = receive_request;
*pb_tx_req_is_set = 0;
dprintk(VIDC_DBG,
@@ -516,21 +529,28 @@ static int __read_queue(struct vidc_iface_q_info *qinfo, u8 *packet,
}
read_ptr = (u32 *)((qinfo->q_array.align_virtual_addr) +
- (queue->qhdr_read_idx << 2));
+ (read_idx << 2));
+ if (read_ptr < (u32 *)qinfo->q_array.align_virtual_addr ||
+ read_ptr > (u32 *)(qinfo->q_array.align_virtual_addr +
+ qinfo->q_array.mem_size - sizeof(*read_ptr))) {
+ dprintk(VIDC_ERR, "Invalid read index\n");
+ return -ENODATA;
+ }
+
packet_size_in_words = (*read_ptr) >> 2;
if (!packet_size_in_words) {
dprintk(VIDC_ERR, "Zero packet size\n");
return -ENODATA;
}
- new_read_idx = queue->qhdr_read_idx + packet_size_in_words;
- if (((packet_size_in_words << 2) <= VIDC_IFACEQ_VAR_HUGE_PKT_SIZE)
- && queue->qhdr_read_idx <= queue->qhdr_q_size) {
- if (new_read_idx < queue->qhdr_q_size) {
+ new_read_idx = read_idx + packet_size_in_words;
+ if (((packet_size_in_words << 2) <= VIDC_IFACEQ_VAR_HUGE_PKT_SIZE) &&
+ read_idx <= (qinfo->q_array.mem_size >> 2)) {
+ if (new_read_idx < (qinfo->q_array.mem_size >> 2)) {
memcpy(packet, read_ptr,
packet_size_in_words << 2);
} else {
- new_read_idx -= queue->qhdr_q_size;
+ new_read_idx -= (qinfo->q_array.mem_size >> 2);
memcpy(packet, read_ptr,
(packet_size_in_words - new_read_idx) << 2);
memcpy(packet + ((packet_size_in_words -
@@ -541,19 +561,18 @@ static int __read_queue(struct vidc_iface_q_info *qinfo, u8 *packet,
} else {
dprintk(VIDC_WARN,
"BAD packet received, read_idx: %#x, pkt_size: %d\n",
- queue->qhdr_read_idx, packet_size_in_words << 2);
+ read_idx, packet_size_in_words << 2);
dprintk(VIDC_WARN, "Dropping this packet\n");
- new_read_idx = queue->qhdr_write_idx;
+ new_read_idx = write_idx;
rc = -ENODATA;
}
- queue->qhdr_read_idx = new_read_idx;
-
- if (queue->qhdr_read_idx != queue->qhdr_write_idx)
+ if (new_read_idx != write_idx)
queue->qhdr_rx_req = 0;
else
queue->qhdr_rx_req = receive_request;
+ queue->qhdr_read_idx = new_read_idx;
*pb_tx_req_is_set = (queue->qhdr_tx_req == 1) ? 1 : 0;
if (msm_vidc_debug & VIDC_PKT) {
diff --git a/drivers/media/platform/msm/vidc_3x/vidc_hfi_api.h b/drivers/media/platform/msm/vidc_3x/vidc_hfi_api.h
index 875db097d9b2..a53d0b0f4f83 100644
--- a/drivers/media/platform/msm/vidc_3x/vidc_hfi_api.h
+++ b/drivers/media/platform/msm/vidc_3x/vidc_hfi_api.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -66,6 +66,9 @@
/* 16 encoder and 16 decoder sessions */
#define VIDC_MAX_SESSIONS 32
+#define VIDC_MAX_DECODE_SESSIONS 16
+#define VIDC_MAX_ENCODE_SESSIONS 16
+
enum vidc_status {
VIDC_ERR_NONE = 0x0,
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index c0c698317d5a..07dbf1740353 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -1,7 +1,7 @@
/*
* QTI Secure Execution Environment Communicator (QSEECOM) driver
*
- * Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -143,6 +143,8 @@ static dev_t qseecom_device_no;
static DEFINE_MUTEX(qsee_bw_mutex);
static DEFINE_MUTEX(app_access_lock);
static DEFINE_MUTEX(clk_access_lock);
+static DEFINE_MUTEX(listener_access_lock);
+
struct sglist_info {
uint32_t indexAndFlags;
@@ -182,15 +184,21 @@ struct qseecom_registered_listener_list {
size_t sb_length;
struct ion_handle *ihandle; /* Retrieve phy addr */
wait_queue_head_t rcv_req_wq;
- /* rcv_req_flag: -1: not ready; 0: ready and empty; 1: received req */
+ /* rcv_req_flag: 0: ready and empty; 1: received req */
int rcv_req_flag;
int send_resp_flag;
bool listener_in_use;
/* wq for thread blocked on this listener*/
wait_queue_head_t listener_block_app_wq;
- struct sglist_info sglistinfo_ptr[MAX_ION_FD];
- uint32_t sglist_cnt;
- int abort;
+ struct sglist_info sglistinfo_ptr[MAX_ION_FD];
+ uint32_t sglist_cnt;
+ int abort;
+ bool unregister_pending;
+};
+
+struct qseecom_unregister_pending_list {
+ struct list_head list;
+ struct qseecom_dev_handle *data;
};
struct qseecom_registered_app_list {
@@ -238,7 +246,6 @@ struct qseecom_clk {
struct qseecom_control {
struct ion_client *ion_clnt; /* Ion client */
struct list_head registered_listener_list_head;
- spinlock_t registered_listener_list_lock;
struct list_head registered_app_list_head;
spinlock_t registered_app_list_lock;
@@ -284,6 +291,9 @@ struct qseecom_control {
atomic_t qseecom_state;
int is_apps_region_protected;
bool smcinvoke_support;
+
+ struct list_head unregister_lsnr_pending_list_head;
+ wait_queue_head_t register_lsnr_pending_wq;
};
struct qseecom_sec_buf_fd_info {
@@ -312,6 +322,8 @@ struct qseecom_client_handle {
struct qseecom_listener_handle {
u32 id;
+ bool unregister_pending;
+ bool release_called;
};
static struct qseecom_control qseecom;
@@ -585,13 +597,10 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
}
qseecom.smcinvoke_support = true;
smc_id = TZ_OS_REGISTER_LISTENER_SMCINVOKE_ID;
- __qseecom_reentrancy_check_if_no_app_blocked(smc_id);
ret = scm_call2(smc_id, &desc);
- if (ret) {
+ if (ret && ret != -EBUSY) {
qseecom.smcinvoke_support = false;
smc_id = TZ_OS_REGISTER_LISTENER_ID;
- __qseecom_reentrancy_check_if_no_app_blocked(
- smc_id);
ret = scm_call2(smc_id, &desc);
}
break;
@@ -604,7 +613,6 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
smc_id = TZ_OS_DEREGISTER_LISTENER_ID;
desc.arginfo = TZ_OS_DEREGISTER_LISTENER_ID_PARAM_ID;
desc.args[0] = req->listener_id;
- __qseecom_reentrancy_check_if_no_app_blocked(smc_id);
ret = scm_call2(smc_id, &desc);
break;
}
@@ -1065,42 +1073,18 @@ static int qseecom_scm_call(u32 svc_id, u32 tz_cmd_id, const void *cmd_buf,
return qseecom_scm_call2(svc_id, tz_cmd_id, cmd_buf, resp_buf);
}
-static int __qseecom_is_svc_unique(struct qseecom_dev_handle *data,
- struct qseecom_register_listener_req *svc)
-{
- struct qseecom_registered_listener_list *ptr;
- int unique = 1;
- unsigned long flags;
-
- spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
- list_for_each_entry(ptr, &qseecom.registered_listener_list_head, list) {
- if (ptr->svc.listener_id == svc->listener_id) {
- pr_err("Service id: %u is already registered\n",
- ptr->svc.listener_id);
- unique = 0;
- break;
- }
- }
- spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
- return unique;
-}
-
static struct qseecom_registered_listener_list *__qseecom_find_svc(
int32_t listener_id)
{
struct qseecom_registered_listener_list *entry = NULL;
- unsigned long flags;
- spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
list_for_each_entry(entry,
&qseecom.registered_listener_list_head, list) {
if (entry->svc.listener_id == listener_id)
break;
}
- spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
-
if ((entry != NULL) && (entry->svc.listener_id != listener_id)) {
- pr_err("Service id: %u is not found\n", listener_id);
+ pr_debug("Service id: %u is not found\n", listener_id);
return NULL;
}
@@ -1179,9 +1163,9 @@ static int qseecom_register_listener(struct qseecom_dev_handle *data,
void __user *argp)
{
int ret = 0;
- unsigned long flags;
struct qseecom_register_listener_req rcvd_lstnr;
struct qseecom_registered_listener_list *new_entry;
+ struct qseecom_registered_listener_list *ptr_svc;
ret = copy_from_user(&rcvd_lstnr, argp, sizeof(rcvd_lstnr));
if (ret) {
@@ -1193,18 +1177,37 @@ static int qseecom_register_listener(struct qseecom_dev_handle *data,
return -EFAULT;
data->listener.id = rcvd_lstnr.listener_id;
- if (!__qseecom_is_svc_unique(data, &rcvd_lstnr)) {
- pr_err("Service %d is not unique and failed to register\n",
+
+ ptr_svc = __qseecom_find_svc(rcvd_lstnr.listener_id);
+ if (ptr_svc) {
+ if (ptr_svc->unregister_pending == false) {
+ pr_err("Service %d is not unique\n",
rcvd_lstnr.listener_id);
data->released = true;
return -EBUSY;
+ } else {
+ /*wait until listener is unregistered*/
+ pr_debug("register %d has to wait\n",
+ rcvd_lstnr.listener_id);
+ mutex_unlock(&listener_access_lock);
+ ret = wait_event_freezable(
+ qseecom.register_lsnr_pending_wq,
+ list_empty(
+ &qseecom.unregister_lsnr_pending_list_head));
+ if (ret) {
+ pr_err("interrupted register_pending_wq %d\n",
+ rcvd_lstnr.listener_id);
+ mutex_lock(&listener_access_lock);
+ return -ERESTARTSYS;
+ }
+ mutex_lock(&listener_access_lock);
+ }
}
-
new_entry = kzalloc(sizeof(*new_entry), GFP_KERNEL);
if (!new_entry)
return -ENOMEM;
memcpy(&new_entry->svc, &rcvd_lstnr, sizeof(rcvd_lstnr));
- new_entry->rcv_req_flag = -1;
+ new_entry->rcv_req_flag = 0;
new_entry->svc.listener_id = rcvd_lstnr.listener_id;
new_entry->sb_length = rcvd_lstnr.sb_size;
@@ -1220,45 +1223,20 @@ static int qseecom_register_listener(struct qseecom_dev_handle *data,
init_waitqueue_head(&new_entry->listener_block_app_wq);
new_entry->send_resp_flag = 0;
new_entry->listener_in_use = false;
- spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
list_add_tail(&new_entry->list, &qseecom.registered_listener_list_head);
- spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
pr_warn("Service %d is registered\n", rcvd_lstnr.listener_id);
return ret;
}
-static void __qseecom_listener_abort_all(int abort)
-{
- struct qseecom_registered_listener_list *entry = NULL;
- unsigned long flags;
-
- spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
- list_for_each_entry(entry,
- &qseecom.registered_listener_list_head, list) {
- pr_debug("set abort %d for listener %d\n",
- abort, entry->svc.listener_id);
- entry->abort = abort;
- }
- if (abort)
- wake_up_interruptible_all(&qseecom.send_resp_wq);
- spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
-}
-
-static int qseecom_unregister_listener(struct qseecom_dev_handle *data)
+static int __qseecom_unregister_listener(struct qseecom_dev_handle *data,
+ struct qseecom_registered_listener_list *ptr_svc)
{
int ret = 0;
struct qseecom_register_listener_ireq req;
- struct qseecom_registered_listener_list *ptr_svc = NULL;
struct qseecom_command_scm_resp resp;
struct ion_handle *ihandle = NULL; /* Retrieve phy addr */
- ptr_svc = __qseecom_find_svc(data->listener.id);
- if (!ptr_svc) {
- pr_err("Unregiser invalid listener ID %d\n", data->listener.id);
- return -ENODATA;
- }
-
req.qsee_cmd_id = QSEOS_DEREGISTER_LISTENER;
req.listener_id = data->listener.id;
resp.result = QSEOS_RESULT_INCOMPLETE;
@@ -1268,6 +1246,8 @@ static int qseecom_unregister_listener(struct qseecom_dev_handle *data)
if (ret) {
pr_err("scm_call() failed with err: %d (lstnr id=%d)\n",
ret, data->listener.id);
+ if (ret == -EBUSY)
+ return ret;
goto exit;
}
@@ -1279,7 +1259,6 @@ static int qseecom_unregister_listener(struct qseecom_dev_handle *data)
}
data->abort = 1;
- ptr_svc->abort = 1;
wake_up_all(&ptr_svc->rcv_req_wq);
while (atomic_read(&data->ioctl_count) > 1) {
@@ -1306,6 +1285,77 @@ exit:
return ret;
}
+static int qseecom_unregister_listener(struct qseecom_dev_handle *data)
+{
+ struct qseecom_registered_listener_list *ptr_svc = NULL;
+ struct qseecom_unregister_pending_list *entry = NULL;
+
+ ptr_svc = __qseecom_find_svc(data->listener.id);
+ if (!ptr_svc) {
+ pr_err("Unregiser invalid listener ID %d\n", data->listener.id);
+ return -ENODATA;
+ }
+ /* stop CA thread waiting for listener response */
+ ptr_svc->abort = 1;
+ wake_up_interruptible_all(&qseecom.send_resp_wq);
+
+ /* return directly if pending*/
+ if (ptr_svc->unregister_pending)
+ return 0;
+
+ /*add unregistration into pending list*/
+ entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+ if (!entry)
+ return -ENOMEM;
+ entry->data = data;
+ list_add_tail(&entry->list,
+ &qseecom.unregister_lsnr_pending_list_head);
+ ptr_svc->unregister_pending = true;
+ pr_debug("unregister %d pending\n", data->listener.id);
+ return 0;
+}
+
+static void __qseecom_processing_pending_lsnr_unregister(void)
+{
+ struct qseecom_unregister_pending_list *entry = NULL;
+ struct qseecom_registered_listener_list *ptr_svc = NULL;
+ struct list_head *pos;
+ int ret = 0;
+
+ mutex_lock(&listener_access_lock);
+ while (!list_empty(&qseecom.unregister_lsnr_pending_list_head)) {
+ pos = qseecom.unregister_lsnr_pending_list_head.next;
+ entry = list_entry(pos,
+ struct qseecom_unregister_pending_list, list);
+ if (entry && entry->data) {
+ pr_debug("process pending unregister %d\n",
+ entry->data->listener.id);
+ /* don't process if qseecom_release is not called*/
+ if (!entry->data->listener.release_called)
+ break;
+ ptr_svc = __qseecom_find_svc(
+ entry->data->listener.id);
+ if (ptr_svc) {
+ ret = __qseecom_unregister_listener(
+ entry->data, ptr_svc);
+ if (ret == -EBUSY) {
+ pr_debug("unregister %d pending again\n",
+ entry->data->listener.id);
+ mutex_unlock(&listener_access_lock);
+ return;
+ }
+ } else
+ pr_err("invalid listener %d\n",
+ entry->data->listener.id);
+ kzfree(entry->data);
+ }
+ list_del(pos);
+ kzfree(entry);
+ }
+ mutex_unlock(&listener_access_lock);
+ wake_up_interruptible(&qseecom.register_lsnr_pending_wq);
+}
+
static int __qseecom_set_msm_bus_request(uint32_t mode)
{
int ret = 0;
@@ -1640,19 +1690,12 @@ static void __qseecom_clean_listener_sglistinfo(
}
}
-static int __is_listener_rcv_wq_not_ready(
- struct qseecom_registered_listener_list *ptr_svc)
-{
- return ptr_svc->rcv_req_flag == -1;
-}
-
static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data,
struct qseecom_command_scm_resp *resp)
{
int ret = 0;
int rc = 0;
uint32_t lstnr;
- unsigned long flags;
struct qseecom_client_listener_data_irsp send_data_rsp = {0};
struct qseecom_client_listener_data_64bit_irsp send_data_rsp_64bit
= {0};
@@ -1663,30 +1706,23 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data,
void *cmd_buf = NULL;
size_t cmd_len;
struct sglist_info *table = NULL;
- bool not_ready = false;
+ qseecom.app_block_ref_cnt++;
while (resp->result == QSEOS_RESULT_INCOMPLETE) {
lstnr = resp->data;
/*
* Wake up blocking lsitener service with the lstnr id
*/
- spin_lock_irqsave(&qseecom.registered_listener_list_lock,
- flags);
+ mutex_lock(&listener_access_lock);
list_for_each_entry(ptr_svc,
&qseecom.registered_listener_list_head, list) {
if (ptr_svc->svc.listener_id == lstnr) {
- if (__is_listener_rcv_wq_not_ready(ptr_svc)) {
- not_ready = true;
- break;
- }
ptr_svc->listener_in_use = true;
ptr_svc->rcv_req_flag = 1;
wake_up_interruptible(&ptr_svc->rcv_req_wq);
break;
}
}
- spin_unlock_irqrestore(&qseecom.registered_listener_list_lock,
- flags);
if (ptr_svc == NULL) {
pr_err("Listener Svc %d does not exist\n", lstnr);
@@ -1712,22 +1748,13 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data,
}
if (ptr_svc->abort == 1) {
- pr_err("Service %d abort %d\n",
+ pr_debug("Service %d abort %d\n",
lstnr, ptr_svc->abort);
rc = -ENODEV;
status = QSEOS_RESULT_FAILURE;
goto err_resp;
}
- if (not_ready) {
- pr_err("Service %d is not ready to receive request\n",
- lstnr);
- rc = -ENOENT;
- status = QSEOS_RESULT_FAILURE;
- goto err_resp;
-
- }
-
pr_debug("waking up rcv_req_wq and waiting for send_resp_wq\n");
/* initialize the new signal mask with all signals*/
@@ -1735,6 +1762,7 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data,
/* block all signals */
sigprocmask(SIG_SETMASK, &new_sigset, &old_sigset);
+ mutex_unlock(&listener_access_lock);
do {
/*
* When reentrancy is not supported, check global
@@ -1755,7 +1783,7 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data,
break;
}
} while (1);
-
+ mutex_lock(&listener_access_lock);
/* restore signal mask */
sigprocmask(SIG_SETMASK, &old_sigset, NULL);
if (data->abort || ptr_svc->abort) {
@@ -1811,14 +1839,14 @@ err_resp:
ION_IOC_CLEAN_INV_CACHES);
if (ret) {
pr_err("cache operation failed %d\n", ret);
- return ret;
+ goto exit;
}
}
if ((lstnr == RPMB_SERVICE) || (lstnr == SSD_SERVICE)) {
ret = __qseecom_enable_clk(CLK_QSEE);
if (ret)
- return ret;
+ goto exit;
}
ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1,
@@ -1832,7 +1860,7 @@ err_resp:
ret, data->client.app_id);
if ((lstnr == RPMB_SERVICE) || (lstnr == SSD_SERVICE))
__qseecom_disable_clk(CLK_QSEE);
- return ret;
+ goto exit;
}
pr_debug("resp status %d, res= %d, app_id = %d, lstr = %d\n",
status, resp->result, data->client.app_id, lstnr);
@@ -1841,11 +1869,15 @@ err_resp:
pr_err("fail:resp res= %d,app_id = %d,lstr = %d\n",
resp->result, data->client.app_id, lstnr);
ret = -EINVAL;
+ goto exit;
}
+exit:
+ mutex_unlock(&listener_access_lock);
if ((lstnr == RPMB_SERVICE) || (lstnr == SSD_SERVICE))
__qseecom_disable_clk(CLK_QSEE);
}
+ qseecom.app_block_ref_cnt--;
if (rc)
return rc;
@@ -1898,10 +1930,12 @@ static int __qseecom_process_reentrancy_blocked_on_listener(
do {
session_id = resp->resp_type;
+ mutex_lock(&listener_access_lock);
list_ptr = __qseecom_find_svc(resp->data);
if (!list_ptr) {
pr_err("Invalid listener ID %d\n", resp->data);
ret = -ENODATA;
+ mutex_unlock(&listener_access_lock);
goto exit;
}
ptr_app->blocked_on_listener_id = resp->data;
@@ -1917,11 +1951,13 @@ static int __qseecom_process_reentrancy_blocked_on_listener(
do {
qseecom.app_block_ref_cnt++;
ptr_app->app_blocked = true;
+ mutex_unlock(&listener_access_lock);
mutex_unlock(&app_access_lock);
wait_event_freezable(
list_ptr->listener_block_app_wq,
!list_ptr->listener_in_use);
mutex_lock(&app_access_lock);
+ mutex_lock(&listener_access_lock);
ptr_app->app_blocked = false;
qseecom.app_block_ref_cnt--;
} while (list_ptr->listener_in_use);
@@ -1954,9 +1990,11 @@ static int __qseecom_process_reentrancy_blocked_on_listener(
if (ret) {
pr_err("unblock app %d or session %d fail\n",
data->client.app_id, session_id);
+ mutex_unlock(&listener_access_lock);
goto exit;
}
}
+ mutex_unlock(&listener_access_lock);
resp->result = continue_resp.result;
resp->resp_type = continue_resp.resp_type;
resp->data = continue_resp.data;
@@ -1978,7 +2016,6 @@ static int __qseecom_reentrancy_process_incomplete_cmd(
int ret = 0;
int rc = 0;
uint32_t lstnr;
- unsigned long flags;
struct qseecom_client_listener_data_irsp send_data_rsp = {0};
struct qseecom_client_listener_data_64bit_irsp send_data_rsp_64bit
= {0};
@@ -1989,30 +2026,22 @@ static int __qseecom_reentrancy_process_incomplete_cmd(
void *cmd_buf = NULL;
size_t cmd_len;
struct sglist_info *table = NULL;
- bool not_ready = false;
while (ret == 0 && resp->result == QSEOS_RESULT_INCOMPLETE) {
lstnr = resp->data;
/*
* Wake up blocking lsitener service with the lstnr id
*/
- spin_lock_irqsave(&qseecom.registered_listener_list_lock,
- flags);
+ mutex_lock(&listener_access_lock);
list_for_each_entry(ptr_svc,
&qseecom.registered_listener_list_head, list) {
if (ptr_svc->svc.listener_id == lstnr) {
- if (__is_listener_rcv_wq_not_ready(ptr_svc)) {
- not_ready = true;
- break;
- }
ptr_svc->listener_in_use = true;
ptr_svc->rcv_req_flag = 1;
wake_up_interruptible(&ptr_svc->rcv_req_wq);
break;
}
}
- spin_unlock_irqrestore(&qseecom.registered_listener_list_lock,
- flags);
if (ptr_svc == NULL) {
pr_err("Listener Svc %d does not exist\n", lstnr);
@@ -2038,22 +2067,13 @@ static int __qseecom_reentrancy_process_incomplete_cmd(
}
if (ptr_svc->abort == 1) {
- pr_err("Service %d abort %d\n",
+ pr_debug("Service %d abort %d\n",
lstnr, ptr_svc->abort);
rc = -ENODEV;
status = QSEOS_RESULT_FAILURE;
goto err_resp;
}
- if (not_ready) {
- pr_err("Service %d is not ready to receive request\n",
- lstnr);
- rc = -ENOENT;
- status = QSEOS_RESULT_FAILURE;
- goto err_resp;
-
- }
-
pr_debug("waking up rcv_req_wq and waiting for send_resp_wq\n");
/* initialize the new signal mask with all signals*/
@@ -2063,6 +2083,7 @@ static int __qseecom_reentrancy_process_incomplete_cmd(
sigprocmask(SIG_SETMASK, &new_sigset, &old_sigset);
/* unlock mutex btw waking listener and sleep-wait */
+ mutex_unlock(&listener_access_lock);
mutex_unlock(&app_access_lock);
do {
if (!wait_event_freezable(qseecom.send_resp_wq,
@@ -2073,6 +2094,7 @@ static int __qseecom_reentrancy_process_incomplete_cmd(
} while (1);
/* lock mutex again after resp sent */
mutex_lock(&app_access_lock);
+ mutex_lock(&listener_access_lock);
ptr_svc->send_resp_flag = 0;
qseecom.send_resp_flag = 0;
@@ -2134,7 +2156,7 @@ err_resp:
if (lstnr == RPMB_SERVICE) {
ret = __qseecom_enable_clk(CLK_QSEE);
if (ret)
- return ret;
+ goto exit;
}
ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1,
@@ -2161,8 +2183,10 @@ err_resp:
ret = -EINVAL;
goto exit;
}
+ mutex_unlock(&listener_access_lock);
ret = __qseecom_process_reentrancy_blocked_on_listener(
resp, NULL, data);
+ mutex_lock(&listener_access_lock);
if (ret) {
pr_err("failed to process App(%d) %s blocked on listener %d\n",
data->client.app_id,
@@ -2179,6 +2203,7 @@ err_resp:
goto exit;
}
exit:
+ mutex_unlock(&listener_access_lock);
if (lstnr == RPMB_SERVICE)
__qseecom_disable_clk(CLK_QSEE);
@@ -3267,6 +3292,7 @@ exit:
pr_err("cache operation failed %d\n", ret2);
return ret2;
}
+ __qseecom_processing_pending_lsnr_unregister();
return ret;
}
@@ -3862,7 +3888,7 @@ static int __qseecom_listener_has_rcvd_req(struct qseecom_dev_handle *data,
int ret;
ret = (svc->rcv_req_flag == 1);
- return ret || data->abort || svc->abort;
+ return ret || data->abort;
}
static int qseecom_receive_req(struct qseecom_dev_handle *data)
@@ -3870,14 +3896,14 @@ static int qseecom_receive_req(struct qseecom_dev_handle *data)
int ret = 0;
struct qseecom_registered_listener_list *this_lstnr;
+ mutex_lock(&listener_access_lock);
this_lstnr = __qseecom_find_svc(data->listener.id);
if (!this_lstnr) {
pr_err("Invalid listener ID\n");
+ mutex_unlock(&listener_access_lock);
return -ENODATA;
}
-
- if (this_lstnr->rcv_req_flag == -1)
- this_lstnr->rcv_req_flag = 0;
+ mutex_unlock(&listener_access_lock);
while (1) {
if (wait_event_freezable(this_lstnr->rcv_req_wq,
@@ -3886,16 +3912,17 @@ static int qseecom_receive_req(struct qseecom_dev_handle *data)
pr_warn("Interrupted: exiting Listener Service = %d\n",
(uint32_t)data->listener.id);
/* woken up for different reason */
- this_lstnr->rcv_req_flag = -1;
return -ERESTARTSYS;
}
- if (data->abort || this_lstnr->abort) {
+ if (data->abort) {
pr_err("Aborting Listener Service = %d\n",
(uint32_t)data->listener.id);
return -ENODEV;
}
+ mutex_lock(&listener_access_lock);
this_lstnr->rcv_req_flag = 0;
+ mutex_unlock(&listener_access_lock);
break;
}
return ret;
@@ -4482,6 +4509,8 @@ int qseecom_start_app(struct qseecom_handle **handle,
uint32_t fw_size, app_arch;
uint32_t app_id = 0;
+ __qseecom_processing_pending_lsnr_unregister();
+
if (atomic_read(&qseecom.qseecom_state) != QSEECOM_STATE_READY) {
pr_err("Not allowed to be called in %d state\n",
atomic_read(&qseecom.qseecom_state));
@@ -4655,6 +4684,8 @@ int qseecom_shutdown_app(struct qseecom_handle **handle)
unsigned long flags = 0;
bool found_handle = false;
+ __qseecom_processing_pending_lsnr_unregister();
+
if (atomic_read(&qseecom.qseecom_state) != QSEECOM_STATE_READY) {
pr_err("Not allowed to be called in %d state\n",
atomic_read(&qseecom.qseecom_state));
@@ -4703,6 +4734,8 @@ int qseecom_send_command(struct qseecom_handle *handle, void *send_buf,
struct qseecom_dev_handle *data;
bool perf_enabled = false;
+ __qseecom_processing_pending_lsnr_unregister();
+
if (atomic_read(&qseecom.qseecom_state) != QSEECOM_STATE_READY) {
pr_err("Not allowed to be called in %d state\n",
atomic_read(&qseecom.qseecom_state));
@@ -7012,6 +7045,11 @@ static inline long qseecom_ioctl(struct file *file,
pr_err("Aborting qseecom driver\n");
return -ENODEV;
}
+ if (cmd != QSEECOM_IOCTL_RECEIVE_REQ &&
+ cmd != QSEECOM_IOCTL_SEND_RESP_REQ &&
+ cmd != QSEECOM_IOCTL_SEND_MODFD_RESP &&
+ cmd != QSEECOM_IOCTL_SEND_MODFD_RESP_64)
+ __qseecom_processing_pending_lsnr_unregister();
switch (cmd) {
case QSEECOM_IOCTL_REGISTER_LISTENER_REQ: {
@@ -7022,13 +7060,13 @@ static inline long qseecom_ioctl(struct file *file,
break;
}
pr_debug("ioctl register_listener_req()\n");
- mutex_lock(&app_access_lock);
+ mutex_lock(&listener_access_lock);
atomic_inc(&data->ioctl_count);
data->type = QSEECOM_LISTENER_SERVICE;
ret = qseecom_register_listener(data, argp);
atomic_dec(&data->ioctl_count);
wake_up_all(&data->abort_wq);
- mutex_unlock(&app_access_lock);
+ mutex_unlock(&listener_access_lock);
if (ret)
pr_err("failed qseecom_register_listener: %d\n", ret);
break;
@@ -7054,14 +7092,12 @@ static inline long qseecom_ioctl(struct file *file,
break;
}
pr_debug("ioctl unregister_listener_req()\n");
- __qseecom_listener_abort_all(1);
- mutex_lock(&app_access_lock);
+ mutex_lock(&listener_access_lock);
atomic_inc(&data->ioctl_count);
ret = qseecom_unregister_listener(data);
atomic_dec(&data->ioctl_count);
wake_up_all(&data->abort_wq);
- mutex_unlock(&app_access_lock);
- __qseecom_listener_abort_all(0);
+ mutex_unlock(&listener_access_lock);
if (ret)
pr_err("failed qseecom_unregister_listener: %d\n", ret);
break;
@@ -7216,6 +7252,7 @@ static inline long qseecom_ioctl(struct file *file,
ret = -EINVAL;
break;
}
+ mutex_lock(&listener_access_lock);
atomic_inc(&data->ioctl_count);
if (!qseecom.qsee_reentrancy_support)
ret = qseecom_send_resp();
@@ -7223,6 +7260,7 @@ static inline long qseecom_ioctl(struct file *file,
ret = qseecom_reentrancy_send_resp(data);
atomic_dec(&data->ioctl_count);
wake_up_all(&data->abort_wq);
+ mutex_unlock(&listener_access_lock);
if (ret)
pr_err("failed qseecom_send_resp: %d\n", ret);
break;
@@ -7558,6 +7596,7 @@ static inline long qseecom_ioctl(struct file *file,
ret = -EINVAL;
break;
}
+ mutex_lock(&listener_access_lock);
atomic_inc(&data->ioctl_count);
if (cmd == QSEECOM_IOCTL_SEND_MODFD_RESP)
ret = qseecom_send_modfd_resp(data, argp);
@@ -7565,6 +7604,7 @@ static inline long qseecom_ioctl(struct file *file,
ret = qseecom_send_modfd_resp_64(data, argp);
atomic_dec(&data->ioctl_count);
wake_up_all(&data->abort_wq);
+ mutex_unlock(&listener_access_lock);
if (ret)
pr_err("failed qseecom_send_mod_resp: %d\n", ret);
__qseecom_clean_data_sglistinfo(data);
@@ -7722,18 +7762,19 @@ static int qseecom_release(struct inode *inode, struct file *file)
{
struct qseecom_dev_handle *data = file->private_data;
int ret = 0;
+ bool free_private_data = true;
if (data->released == false) {
pr_debug("data: released=false, type=%d, mode=%d, data=0x%pK\n",
data->type, data->mode, data);
switch (data->type) {
case QSEECOM_LISTENER_SERVICE:
- pr_warn("release lsnr svc %d\n", data->listener.id);
- __qseecom_listener_abort_all(1);
- mutex_lock(&app_access_lock);
+ pr_debug("release lsnr svc %d\n", data->listener.id);
+ free_private_data = false;
+ mutex_lock(&listener_access_lock);
ret = qseecom_unregister_listener(data);
- mutex_unlock(&app_access_lock);
- __qseecom_listener_abort_all(0);
+ data->listener.release_called = true;
+ mutex_unlock(&listener_access_lock);
break;
case QSEECOM_CLIENT_APP:
mutex_lock(&app_access_lock);
@@ -7772,8 +7813,9 @@ static int qseecom_release(struct inode *inode, struct file *file)
if (data->perf_enabled == true)
qsee_disable_clock_vote(data, CLK_DFAB);
}
- kfree(data);
+ if (free_private_data)
+ kfree(data);
return ret;
}
@@ -8600,12 +8642,13 @@ static int qseecom_probe(struct platform_device *pdev)
}
INIT_LIST_HEAD(&qseecom.registered_listener_list_head);
- spin_lock_init(&qseecom.registered_listener_list_lock);
INIT_LIST_HEAD(&qseecom.registered_app_list_head);
spin_lock_init(&qseecom.registered_app_list_lock);
+ INIT_LIST_HEAD(&qseecom.unregister_lsnr_pending_list_head);
INIT_LIST_HEAD(&qseecom.registered_kclient_list_head);
spin_lock_init(&qseecom.registered_kclient_list_lock);
init_waitqueue_head(&qseecom.send_resp_wq);
+ init_waitqueue_head(&qseecom.register_lsnr_pending_wq);
qseecom.send_resp_flag = 0;
qseecom.qsee_version = QSEEE_VERSION_00;
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 04ac554ccd90..448aea08ec24 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -1300,6 +1300,17 @@ static int mmc_blk_ioctl_multi_cmd(struct block_device *bdev,
mmc_get_card(card);
+ if (mmc_card_cmdq(card)) {
+ err = mmc_cmdq_halt(card->host, true);
+ if (err) {
+ pr_err("%s: halt failed while doing %s err (%d)\n",
+ mmc_hostname(card->host),
+ __func__, err);
+ mmc_put_card(card);
+ goto cmd_done;
+ }
+ }
+
for (i = 0; i < num_of_cmds && !ioc_err; i++)
ioc_err = __mmc_blk_ioctl_cmd(card, md, idata[i]);
@@ -1307,6 +1318,12 @@ static int mmc_blk_ioctl_multi_cmd(struct block_device *bdev,
if (md->area_type & MMC_BLK_DATA_AREA_RPMB)
mmc_blk_part_switch(card, dev_get_drvdata(&card->dev));
+ if (mmc_card_cmdq(card)) {
+ if (mmc_cmdq_halt(card->host, false))
+ pr_err("%s: %s: cmdq unhalt failed\n",
+ mmc_hostname(card->host), __func__);
+ }
+
mmc_put_card(card);
/* copy to user if data and response */
diff --git a/drivers/perf/arm_pmu.c b/drivers/perf/arm_pmu.c
index 37df1bf277ca..09e8d38f57ae 100644
--- a/drivers/perf/arm_pmu.c
+++ b/drivers/perf/arm_pmu.c
@@ -752,11 +752,7 @@ static void cpu_pm_pmu_setup(struct arm_pmu *armpmu, unsigned long cmd)
if (!event)
continue;
- /*
- * Check if an attempt was made to free this event during
- * the CPU went offline.
- */
- if (event->state == PERF_EVENT_STATE_ZOMBIE)
+ if (event->state != PERF_EVENT_STATE_ACTIVE)
continue;
switch (cmd) {
@@ -882,10 +878,8 @@ static int arm_perf_starting_cpu(unsigned int cpu, struct hlist_node *node)
if (!pmu || !cpumask_test_cpu(cpu, &pmu->supported_cpus))
return 0;
- data.cmd = CPU_PM_EXIT;
- cpu_pm_pmu_common(&data);
- if (data.ret == NOTIFY_DONE)
- return 0;
+ if (pmu->reset)
+ pmu->reset(pmu);
if (data.armpmu->pmu_state != ARM_PMU_STATE_OFF &&
data.armpmu->plat_device) {
@@ -911,8 +905,6 @@ static int arm_perf_stopping_cpu(unsigned int cpu, struct hlist_node *node)
if (!pmu || !cpumask_test_cpu(cpu, &pmu->supported_cpus))
return 0;
- data.cmd = CPU_PM_ENTER;
- cpu_pm_pmu_common(&data);
/* Disarm the PMU IRQ before disappearing. */
if (data.armpmu->pmu_state == ARM_PMU_STATE_RUNNING &&
data.armpmu->plat_device) {
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_intf.c b/drivers/platform/msm/ipa/ipa_v2/ipa_intf.c
index f1f6b900d474..b3c38b9d7f86 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_intf.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_intf.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -737,8 +737,14 @@ ssize_t ipa_read(struct file *filp, char __user *buf, size_t count,
IPADBG("msg=%pK\n", msg);
locked = 0;
mutex_unlock(&ipa_ctx->msg_lock);
+ if (count < sizeof(struct ipa_msg_meta)) {
+ kfree(msg);
+ msg = NULL;
+ ret = -EFAULT;
+ break;
+ }
if (copy_to_user(buf, &msg->meta,
- sizeof(struct ipa_msg_meta))) {
+ sizeof(struct ipa_msg_meta))) {
kfree(msg);
msg = NULL;
ret = -EFAULT;
@@ -747,8 +753,15 @@ ssize_t ipa_read(struct file *filp, char __user *buf, size_t count,
buf += sizeof(struct ipa_msg_meta);
count -= sizeof(struct ipa_msg_meta);
if (msg->buff) {
- if (copy_to_user(buf, msg->buff,
- msg->meta.msg_len)) {
+ if (count >= msg->meta.msg_len) {
+ if (copy_to_user(buf, msg->buff,
+ msg->meta.msg_len)) {
+ kfree(msg);
+ msg = NULL;
+ ret = -EFAULT;
+ break;
+ }
+ } else {
kfree(msg);
msg = NULL;
ret = -EFAULT;
diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c
index 07715b7bee8e..ec438df89a2a 100644
--- a/drivers/power/supply/power_supply_sysfs.c
+++ b/drivers/power/supply/power_supply_sysfs.c
@@ -341,6 +341,7 @@ static struct device_attribute power_supply_attrs[] = {
POWER_SUPPLY_ATTR(qc_opti_disable),
POWER_SUPPLY_ATTR(fcc_stepper_enable),
POWER_SUPPLY_ATTR(cc_soc),
+ POWER_SUPPLY_ATTR(qg_vbms_mode),
/* Local extensions of type int64_t */
POWER_SUPPLY_ATTR(charge_counter_ext),
/* Properties of type `const char *' */
diff --git a/drivers/power/supply/qcom/fg-alg.c b/drivers/power/supply/qcom/fg-alg.c
index f3f2c6636000..09c3fc47f013 100644
--- a/drivers/power/supply/qcom/fg-alg.c
+++ b/drivers/power/supply/qcom/fg-alg.c
@@ -1055,9 +1055,19 @@ static void ttf_work(struct work_struct *work)
struct ttf *ttf = container_of(work,
struct ttf, ttf_work.work);
int rc, ibatt_now, vbatt_now, ttf_now, charge_status;
+ int valid = 0;
ktime_t ktime_now;
mutex_lock(&ttf->lock);
+ rc = ttf->get_ttf_param(ttf->data, TTF_VALID, &valid);
+ if (rc < 0) {
+ pr_err("failed to get ttf_valid rc=%d\n", rc);
+ goto end_work;
+ }
+
+ if (!valid)
+ goto end_work;
+
rc = ttf->get_ttf_param(ttf->data, TTF_CHG_STATUS, &charge_status);
if (rc < 0) {
pr_err("failed to get charge_status rc=%d\n", rc);
@@ -1198,7 +1208,16 @@ int ttf_get_time_to_empty(struct ttf *ttf, int *val)
*/
void ttf_update(struct ttf *ttf, bool input_present)
{
- int delay_ms;
+ int delay_ms, rc, valid = 0;
+
+ rc = ttf->get_ttf_param(ttf->data, TTF_VALID, &valid);
+ if (rc < 0) {
+ pr_err("failed to get ttf_valid rc=%d\n", rc);
+ return;
+ }
+
+ if (!valid)
+ return;
if (ttf->input_present == input_present)
return;
diff --git a/drivers/power/supply/qcom/qg-core.h b/drivers/power/supply/qcom/qg-core.h
index 4f0773b542cc..6f5f9f1c9d43 100644
--- a/drivers/power/supply/qcom/qg-core.h
+++ b/drivers/power/supply/qcom/qg-core.h
@@ -64,6 +64,7 @@ struct qg_dt {
bool esr_disable;
bool esr_discharge_enable;
bool qg_ext_sense;
+ bool qg_vbms_mode;
};
struct qg_esr_data {
@@ -128,6 +129,7 @@ struct qpnp_qg {
int esr_nominal;
int soh;
int soc_reporting_ready;
+ int vbms_ibat_ua;
u32 fifo_done_count;
u32 wa_flags;
u32 seq_no;
diff --git a/drivers/power/supply/qcom/qg-reg.h b/drivers/power/supply/qcom/qg-reg.h
index 894e0764301c..69f2e1ed4354 100644
--- a/drivers/power/supply/qcom/qg-reg.h
+++ b/drivers/power/supply/qcom/qg-reg.h
@@ -121,6 +121,7 @@
#define QG_SDAM_MAX_OFFSET 0xA4
/* Below offset is used by PBS */
+#define QG_SDAM_SEQ_OFFSET 0xBB /* 1-byte 0xBB */
#define QG_SDAM_PON_OCV_OFFSET 0xBC /* 2-byte 0xBC-0xBD */
#endif
diff --git a/drivers/power/supply/qcom/qg-util.c b/drivers/power/supply/qcom/qg-util.c
index a3e045e93f35..3b5065a1de25 100644
--- a/drivers/power/supply/qcom/qg-util.c
+++ b/drivers/power/supply/qcom/qg-util.c
@@ -342,6 +342,11 @@ int qg_get_battery_current(struct qpnp_qg *chip, int *ibat_ua)
return 0;
}
+ if (chip->dt.qg_vbms_mode) {
+ *ibat_ua = chip->vbms_ibat_ua;
+ return 0;
+ }
+
/* hold data */
rc = qg_masked_write(chip, chip->qg_base + QG_DATA_CTL2_REG,
BURST_AVG_HOLD_FOR_READ_BIT,
diff --git a/drivers/power/supply/qcom/qpnp-qg.c b/drivers/power/supply/qcom/qpnp-qg.c
index 66badbe92683..5030352ea650 100644
--- a/drivers/power/supply/qcom/qpnp-qg.c
+++ b/drivers/power/supply/qcom/qpnp-qg.c
@@ -1029,6 +1029,9 @@ static void process_udata_work(struct work_struct *work)
if (chip->udata.param[QG_FULL_SOC].valid)
chip->full_soc = chip->udata.param[QG_FULL_SOC].data;
+ if (chip->udata.param[QG_VBMS_IBAT].valid)
+ chip->vbms_ibat_ua = chip->udata.param[QG_VBMS_IBAT].data;
+
if (chip->udata.param[QG_SOC].valid ||
chip->udata.param[QG_SYS_SOC].valid) {
@@ -1573,7 +1576,8 @@ static int qg_get_ttf_param(void *data, enum ttf_param param, int *val)
switch (param) {
case TTF_VALID:
- *val = (!chip->battery_missing && chip->profile_loaded);
+ *val = (!chip->battery_missing && chip->profile_loaded &&
+ !chip->dt.qg_vbms_mode);
break;
case TTF_MSOC:
rc = qg_get_battery_capacity(chip, val);
@@ -1791,6 +1795,9 @@ static int qg_psy_get_property(struct power_supply *psy,
case POWER_SUPPLY_PROP_CC_SOC:
rc = qg_get_cc_soc(chip, &pval->intval);
break;
+ case POWER_SUPPLY_PROP_QG_VBMS_MODE:
+ pval->intval = !!chip->dt.qg_vbms_mode;
+ break;
default:
pr_debug("Unsupported property %d\n", psp);
break;
@@ -1842,6 +1849,7 @@ static enum power_supply_property qg_psy_props[] = {
POWER_SUPPLY_PROP_ESR_NOMINAL,
POWER_SUPPLY_PROP_SOH,
POWER_SUPPLY_PROP_CC_SOC,
+ POWER_SUPPLY_PROP_QG_VBMS_MODE,
};
static const struct power_supply_desc qg_psy_desc = {
@@ -2839,6 +2847,9 @@ done_fifo:
}
}
+ if (chip->dt.qg_vbms_mode)
+ chip->dt.s3_entry_fifo_length = 1;
+
if (chip->dt.s3_entry_fifo_length != -EINVAL) {
if (chip->dt.s3_entry_fifo_length < 1)
chip->dt.s3_entry_fifo_length = 1;
@@ -2944,6 +2955,8 @@ done_fifo:
static int qg_post_init(struct qpnp_qg *chip)
{
+ u8 status = 0;
+
/* disable all IRQs if profile is not loaded */
if (!chip->profile_loaded) {
vote(chip->vbatt_irq_disable_votable,
@@ -2954,10 +2967,18 @@ static int qg_post_init(struct qpnp_qg *chip)
PROFILE_IRQ_DISABLE, true, 0);
}
+ if (chip->dt.qg_vbms_mode) {
+ chip->dt.esr_disable = true;
+ chip->dt.cl_disable = true;
+ }
+
/* restore ESR data */
if (!chip->dt.esr_disable)
qg_retrieve_esr_params(chip);
+ /* read STATUS2 register to clear its last state */
+ qg_read(chip, chip->qg_base + QG_STATUS2_REG, &status, 1);
+
return 0;
}
@@ -3438,18 +3459,24 @@ static int qg_parse_dt(struct qpnp_qg *chip)
chip->cl->dt.min_start_soc, chip->cl->dt.max_start_soc,
chip->cl->dt.min_temp, chip->cl->dt.max_temp);
}
- qg_dbg(chip, QG_DEBUG_PON, "DT: vbatt_empty_mv=%dmV vbatt_low_mv=%dmV delta_soc=%d ext-sns=%d\n",
+
+ chip->dt.qg_vbms_mode = of_property_read_bool(node,
+ "qcom,qg-vbms-mode");
+
+ qg_dbg(chip, QG_DEBUG_PON, "DT: vbatt_empty_mv=%dmV vbatt_low_mv=%dmV delta_soc=%d ext-sns=%d qg_vbms_mode=%d\n",
chip->dt.vbatt_empty_mv, chip->dt.vbatt_low_mv,
- chip->dt.delta_soc, chip->dt.qg_ext_sense);
+ chip->dt.delta_soc, chip->dt.qg_ext_sense,
+ chip->dt.qg_vbms_mode);
return 0;
}
static int process_suspend(struct qpnp_qg *chip)
{
- u8 status = 0;
+ u8 status = 0, val;
int rc;
u32 fifo_rt_length = 0, sleep_fifo_length = 0;
+ bool process_fifo = false;
/* skip if profile is not loaded */
if (!chip->profile_loaded)
@@ -3459,6 +3486,15 @@ static int process_suspend(struct qpnp_qg *chip)
chip->suspend_data = false;
+ val = (chip->seq_no % 128) + 1;
+ rc = qg_sdam_multibyte_write(QG_SDAM_SEQ_OFFSET, &val, 1);
+ if (rc < 0) {
+ pr_err("Failed to write sdam seq, rc=%d\n", rc);
+ return rc;
+ }
+ /* read STATUS2 register to clear its last state */
+ qg_read(chip, chip->qg_base + QG_STATUS2_REG, &status, 1);
+
/* ignore any suspend processing if we are charging */
if (chip->charge_status == POWER_SUPPLY_STATUS_CHARGING) {
qg_dbg(chip, QG_DEBUG_PM, "Charging @ suspend - ignore processing\n");
@@ -3483,7 +3519,13 @@ static int process_suspend(struct qpnp_qg *chip)
* the the #fifo to enter sleep, save the FIFO data
* and reset the fifo count.
*/
- if (fifo_rt_length >= (chip->dt.s2_fifo_length - sleep_fifo_length)) {
+ if (chip->dt.qg_vbms_mode && fifo_rt_length >= 1)
+ process_fifo = true;
+ else if (fifo_rt_length >=
+ (chip->dt.s2_fifo_length - sleep_fifo_length))
+ process_fifo = true;
+
+ if (process_fifo) {
rc = qg_master_hold(chip, true);
if (rc < 0) {
pr_err("Failed to hold master, rc=%d\n", rc);
@@ -3508,9 +3550,6 @@ static int process_suspend(struct qpnp_qg *chip)
chip->suspend_data = true;
}
- /* read STATUS2 register to clear its last state */
- qg_read(chip, chip->qg_base + QG_STATUS2_REG, &status, 1);
-
qg_dbg(chip, QG_DEBUG_PM, "FIFO rt_length=%d sleep_fifo_length=%d default_s2_count=%d suspend_data=%d\n",
fifo_rt_length, sleep_fifo_length,
chip->dt.s2_fifo_length, chip->suspend_data);
@@ -3520,7 +3559,7 @@ static int process_suspend(struct qpnp_qg *chip)
static int process_resume(struct qpnp_qg *chip)
{
- u8 status2 = 0, rt_status = 0;
+ u8 status2 = 0, rt_status = 0, val = 0;
u32 ocv_uv = 0, ocv_raw = 0;
int rc;
@@ -3576,6 +3615,11 @@ static int process_resume(struct qpnp_qg *chip)
chip->suspend_data = false;
}
+ rc = qg_sdam_multibyte_write(QG_SDAM_SEQ_OFFSET, &val, 1);
+ if (rc < 0) {
+ pr_err("Failed to write sdam seq, rc=%d\n", rc);
+ return rc;
+ }
schedule_delayed_work(&chip->ttf->ttf_work, 0);
return rc;
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index e8d860df7c79..3ae576655f8b 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -3,7 +3,7 @@
*
* This code is based on drivers/scsi/ufs/ufshcd.c
* Copyright (C) 2011-2013 Samsung India Software Operations
- * Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2019, The Linux Foundation. All rights reserved.
*
* Authors:
* Santosh Yaraganavi <santosh.sy@samsung.com>
@@ -3384,7 +3384,7 @@ static int ufshcd_wait_for_dev_cmd(struct ufs_hba *hba,
ufshcd_outstanding_req_clear(hba, lrbp->task_tag);
}
- if (err)
+ if (err && err != -EAGAIN)
ufsdbg_set_err_state(hba);
return err;
@@ -3445,18 +3445,6 @@ static int ufshcd_exec_dev_cmd(struct ufs_hba *hba,
int tag;
struct completion wait;
unsigned long flags;
- bool has_read_lock = false;
-
- /*
- * May get invoked from shutdown and IOCTL contexts.
- * In shutdown context, it comes in with lock acquired.
- * In error recovery context, it may come with lock acquired.
- */
-
- if (!ufshcd_is_shutdown_ongoing(hba) && !ufshcd_eh_in_progress(hba)) {
- down_read(&hba->lock);
- has_read_lock = true;
- }
/*
* Get free slot, sleep if slots are unavailable.
@@ -3489,8 +3477,6 @@ static int ufshcd_exec_dev_cmd(struct ufs_hba *hba,
out_put_tag:
ufshcd_put_dev_cmd_tag(hba, tag);
wake_up(&hba->dev_cmd.tag_wq);
- if (has_read_lock)
- up_read(&hba->lock);
return err;
}
@@ -3565,10 +3551,15 @@ int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode opcode,
struct ufs_query_res *response = NULL;
int err, index = 0, selector = 0;
int timeout = QUERY_REQ_TIMEOUT;
+ bool has_read_lock = false;
BUG_ON(!hba);
ufshcd_hold_all(hba);
+ if (!ufshcd_is_shutdown_ongoing(hba) && !ufshcd_eh_in_progress(hba)) {
+ down_read(&hba->lock);
+ has_read_lock = true;
+ }
mutex_lock(&hba->dev_cmd.lock);
ufshcd_init_query(hba, &request, &response, opcode, idn, index,
selector);
@@ -3612,6 +3603,8 @@ int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode opcode,
out_unlock:
mutex_unlock(&hba->dev_cmd.lock);
+ if (has_read_lock)
+ up_read(&hba->lock);
ufshcd_release_all(hba);
return err;
}
@@ -3634,6 +3627,7 @@ int ufshcd_query_attr(struct ufs_hba *hba, enum query_opcode opcode,
struct ufs_query_req *request = NULL;
struct ufs_query_res *response = NULL;
int err;
+ bool has_read_lock = false;
BUG_ON(!hba);
@@ -3645,6 +3639,16 @@ int ufshcd_query_attr(struct ufs_hba *hba, enum query_opcode opcode,
goto out;
}
+ /*
+ * May get invoked from shutdown and IOCTL contexts.
+ * In shutdown context, it comes in with lock acquired.
+ * In error recovery context, it may come with lock acquired.
+ */
+
+ if (!ufshcd_is_shutdown_ongoing(hba) && !ufshcd_eh_in_progress(hba)) {
+ down_read(&hba->lock);
+ has_read_lock = true;
+ }
mutex_lock(&hba->dev_cmd.lock);
ufshcd_init_query(hba, &request, &response, opcode, idn, index,
selector);
@@ -3677,6 +3681,8 @@ int ufshcd_query_attr(struct ufs_hba *hba, enum query_opcode opcode,
out_unlock:
mutex_unlock(&hba->dev_cmd.lock);
+ if (has_read_lock)
+ up_read(&hba->lock);
out:
ufshcd_release_all(hba);
return err;
@@ -3727,6 +3733,7 @@ static int __ufshcd_query_descriptor(struct ufs_hba *hba,
struct ufs_query_req *request = NULL;
struct ufs_query_res *response = NULL;
int err;
+ bool has_read_lock = false;
BUG_ON(!hba);
@@ -3745,6 +3752,10 @@ static int __ufshcd_query_descriptor(struct ufs_hba *hba,
goto out;
}
+ if (!ufshcd_is_shutdown_ongoing(hba) && !ufshcd_eh_in_progress(hba)) {
+ down_read(&hba->lock);
+ has_read_lock = true;
+ }
mutex_lock(&hba->dev_cmd.lock);
ufshcd_init_query(hba, &request, &response, opcode, idn, index,
selector);
@@ -3780,6 +3791,9 @@ static int __ufshcd_query_descriptor(struct ufs_hba *hba,
out_unlock:
mutex_unlock(&hba->dev_cmd.lock);
+ if (has_read_lock)
+ up_read(&hba->lock);
+
out:
ufshcd_release_all(hba);
return err;
@@ -5301,8 +5315,13 @@ static int ufshcd_verify_dev_init(struct ufs_hba *hba)
{
int err = 0;
int retries;
+ bool has_read_lock = false;
ufshcd_hold_all(hba);
+ if (!ufshcd_is_shutdown_ongoing(hba) && !ufshcd_eh_in_progress(hba)) {
+ down_read(&hba->lock);
+ has_read_lock = true;
+ }
mutex_lock(&hba->dev_cmd.lock);
for (retries = NOP_OUT_RETRIES; retries > 0; retries--) {
err = ufshcd_exec_dev_cmd(hba, DEV_CMD_TYPE_NOP,
@@ -5314,6 +5333,8 @@ static int ufshcd_verify_dev_init(struct ufs_hba *hba)
dev_dbg(hba->dev, "%s: error %d retrying\n", __func__, err);
}
mutex_unlock(&hba->dev_cmd.lock);
+ if (has_read_lock)
+ up_read(&hba->lock);
ufshcd_release_all(hba);
if (err)
@@ -10252,12 +10273,9 @@ static int ufshcd_devfreq_scale(struct ufs_hba *hba, bool scale_up)
* e.g. link_recovery. Hence, release the rw_sem
* before hibern8.
*/
- up_write(&hba->lock);
ret = ufshcd_uic_hibern8_enter(hba);
- down_write(&hba->lock);
if (ret)
- /* link will be bad state so no need to scale_up_gear */
- return ret;
+ goto scale_up_gear;
ufshcd_custom_cmd_log(hba, "Hibern8-entered");
}
@@ -10269,8 +10287,7 @@ static int ufshcd_devfreq_scale(struct ufs_hba *hba, bool scale_up)
if (ufshcd_is_auto_hibern8_supported(hba)) {
ret = ufshcd_uic_hibern8_exit(hba);
if (ret)
- /* link will be bad state so no need to scale_up_gear */
- return ret;
+ goto scale_up_gear;
ufshcd_custom_cmd_log(hba, "Hibern8-Exited");
}
diff --git a/drivers/soc/qcom/glink_smem_native_xprt.c b/drivers/soc/qcom/glink_smem_native_xprt.c
index 5640666b3cea..f131c79abeaa 100644
--- a/drivers/soc/qcom/glink_smem_native_xprt.c
+++ b/drivers/soc/qcom/glink_smem_native_xprt.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -483,6 +483,8 @@ static int fifo_read(struct edge_info *einfo, void *_data, int len)
uint32_t fifo_size = einfo->rx_fifo_size;
uint32_t n;
+ if (read_index >= fifo_size || write_index >= fifo_size)
+ return 0;
while (len) {
ptr = einfo->rx_fifo + read_index;
if (read_index <= write_index)
@@ -529,6 +531,8 @@ static int fifo_write_body(struct edge_info *einfo, const void *_data,
uint32_t fifo_size = einfo->tx_fifo_size;
uint32_t n;
+ if (read_index >= fifo_size || *write_index >= fifo_size)
+ return 0;
while (len) {
ptr = einfo->tx_fifo + *write_index;
if (*write_index < read_index) {
diff --git a/drivers/soc/qcom/glink_spi_xprt.c b/drivers/soc/qcom/glink_spi_xprt.c
index a08c4bfde4a2..efcd94cdda01 100644
--- a/drivers/soc/qcom/glink_spi_xprt.c
+++ b/drivers/soc/qcom/glink_spi_xprt.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -484,6 +484,13 @@ static int glink_spi_xprt_rx_cmd(struct edge_info *einfo, void *dst,
int ret;
read_id = einfo->rx_fifo_read;
+ if ((read_id > (einfo->rx_fifo_start + einfo->fifo_size)) ||
+ (read_id < einfo->rx_fifo_start)) {
+ pr_err("%s: Invalid rx_fifo_read: %d, start: %d, size: %d\n",
+ __func__, read_id, einfo->rx_fifo_start,
+ einfo->fifo_size);
+ return -EINVAL;
+ }
do {
if ((read_id + size_to_read) >=
(einfo->rx_fifo_start + einfo->fifo_size))
@@ -722,11 +729,11 @@ static void process_rx_cmd(struct edge_info *einfo,
struct rx_short_data_desc {
unsigned char data[SHORT_PKT_SIZE];
};
- struct command *cmd;
+ struct command *cmd = NULL;
struct intent_desc *intents;
struct rx_desc *rx_descp;
struct rx_short_data_desc *rx_sd_descp;
- int offset = 0;
+ uint64_t offset = 0;
int rcu_id;
uint16_t rcid;
uint16_t name_len;
@@ -742,6 +749,8 @@ static void process_rx_cmd(struct edge_info *einfo,
}
while (offset < rx_size) {
+ if (offset + sizeof(*cmd) > rx_size)
+ goto err;
cmd = (struct command *)(rx_data + offset);
offset += sizeof(*cmd);
switch (cmd->id) {
@@ -760,7 +769,12 @@ static void process_rx_cmd(struct edge_info *einfo,
case OPEN_CMD:
rcid = cmd->param1;
name_len = (uint16_t)(cmd->param2 & 0xFFFF);
+ if (name_len > GLINK_NAME_SIZE)
+ goto err;
prio = (uint16_t)((cmd->param2 & 0xFFFF0000) >> 16);
+ if (offset + ALIGN(name_len, FIFO_ALIGNMENT) >
+ rx_size)
+ goto err;
name = (char *)(rx_data + offset);
offset += ALIGN(name_len, FIFO_ALIGNMENT);
einfo->xprt_if.glink_core_if_ptr->rx_cmd_ch_remote_open(
@@ -786,6 +800,8 @@ static void process_rx_cmd(struct edge_info *einfo,
case RX_INTENT_CMD:
for (i = 0; i < cmd->param2; i++) {
+ if (offset + sizeof(*intents) > rx_size)
+ goto err;
intents = (struct intent_desc *)
(rx_data + offset);
offset += sizeof(*intents);
@@ -821,6 +837,8 @@ static void process_rx_cmd(struct edge_info *einfo,
case TX_DATA_CONT_CMD:
case TRACER_PKT_CMD:
case TRACER_PKT_CONT_CMD:
+ if (offset + sizeof(*rx_descp) > rx_size)
+ goto err;
rx_descp = (struct rx_desc *)(rx_data + offset);
offset += sizeof(*rx_descp);
process_rx_data(einfo, cmd->id, cmd->param1,
@@ -830,6 +848,8 @@ static void process_rx_cmd(struct edge_info *einfo,
break;
case TX_SHORT_DATA_CMD:
+ if (offset + sizeof(*rx_sd_descp) > rx_size)
+ goto err;
rx_sd_descp = (struct rx_short_data_desc *)
(rx_data + offset);
offset += sizeof(*rx_sd_descp);
@@ -858,6 +878,13 @@ static void process_rx_cmd(struct edge_info *einfo,
}
}
srcu_read_unlock(&einfo->use_ref, rcu_id);
+ return;
+err:
+ srcu_read_unlock(&einfo->use_ref, rcu_id);
+ if (cmd)
+ pr_err("%s: invalid size of rx_data: %d, cmd : %d\n",
+ __func__, rx_size, cmd->id);
+ return;
}
/**
diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c
index 15e10907c6ef..84ad1e74f73c 100644
--- a/drivers/soc/qcom/icnss.c
+++ b/drivers/soc/qcom/icnss.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -2497,7 +2497,8 @@ static int icnss_driver_event_pd_service_down(struct icnss_priv *priv,
goto out;
}
- icnss_fw_crashed(priv, event_data);
+ if (!test_bit(ICNSS_PD_RESTART, &priv->state))
+ icnss_fw_crashed(priv, event_data);
out:
kfree(data);
diff --git a/drivers/usb/pd/policy_engine.c b/drivers/usb/pd/policy_engine.c
index 3000cf3ecded..8f965e95bddb 100644
--- a/drivers/usb/pd/policy_engine.c
+++ b/drivers/usb/pd/policy_engine.c
@@ -1214,8 +1214,6 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)
case PE_SRC_NEGOTIATE_CAPABILITY:
if (PD_RDO_OBJ_POS(pd->rdo) != 1 ||
PD_RDO_FIXED_CURR(pd->rdo) >
- PD_SRC_PDO_FIXED_MAX_CURR(*default_src_caps) ||
- PD_RDO_FIXED_CURR_MINMAX(pd->rdo) >
PD_SRC_PDO_FIXED_MAX_CURR(*default_src_caps)) {
/* send Reject */
ret = pd_send_msg(pd, MSG_REJECT, NULL, 0, SOP_MSG);
diff --git a/drivers/video/fbdev/msm/mdp3_ctrl.c b/drivers/video/fbdev/msm/mdp3_ctrl.c
index fc9f8a5d52da..ff7d7126df85 100644
--- a/drivers/video/fbdev/msm/mdp3_ctrl.c
+++ b/drivers/video/fbdev/msm/mdp3_ctrl.c
@@ -960,7 +960,7 @@ static int mdp3_ctrl_on(struct msm_fb_data_type *mfd)
MDSS_EVENT_UNBLANK, NULL);
rc |= panel->event_handler(panel,
MDSS_EVENT_PANEL_ON, NULL);
- if (mdss_fb_is_power_on_ulp(mfd))
+ if (mdss_fb_is_power_on_lp(mfd))
rc |= mdp3_enable_panic_ctrl();
mdp3_clk_enable(0, 0);
}
@@ -1099,7 +1099,7 @@ static int mdp3_ctrl_off(struct msm_fb_data_type *mfd)
*/
pm_runtime_get_sync(&mdp3_res->pdev->dev);
- MDSS_XLOG(XLOG_FUNC_ENTRY, __LINE__, mdss_fb_is_power_on_ulp(mfd),
+ MDSS_XLOG(XLOG_FUNC_ENTRY, __LINE__, mdss_fb_is_power_on_lp(mfd),
mfd->panel_power_state);
panel = mdp3_session->panel;
@@ -1240,9 +1240,9 @@ static int mdp3_ctrl_off(struct msm_fb_data_type *mfd)
}
}
- if (mdss_fb_is_power_on_ulp(mfd) &&
+ if (mdss_fb_is_power_on_lp(mfd) &&
(mfd->panel.type == MIPI_CMD_PANEL)) {
- pr_debug("%s: Disable MDP3 clocks in ULP\n", __func__);
+ pr_debug("%s: Disable MDP3 clocks in LP\n", __func__);
if (!mdp3_session->clk_on)
mdp3_ctrl_clk_enable(mfd, 1);
/*
@@ -1252,7 +1252,7 @@ static int mdp3_ctrl_off(struct msm_fb_data_type *mfd)
rc = mdp3_session->dma->stop(mdp3_session->dma,
mdp3_session->intf);
if (rc)
- pr_warn("fail to stop the MDP3 dma in ULP\n");
+ pr_warn("fail to stop the MDP3 dma in LP\n");
/* Wait to ensure TG to turn off */
msleep(20);
/*
diff --git a/drivers/video/fbdev/msm/mdss_fb.c b/drivers/video/fbdev/msm/mdss_fb.c
index 631c1ecd4f5c..87f85d5620d3 100644
--- a/drivers/video/fbdev/msm/mdss_fb.c
+++ b/drivers/video/fbdev/msm/mdss_fb.c
@@ -3005,7 +3005,7 @@ static int __mdss_fb_wait_for_fence_sub(struct msm_sync_pt_data *sync_pt_data,
ret = mdss_wait_sync_fence(fences[i], wait_ms);
- if (ret == -ETIME) {
+ if (ret == -ETIMEDOUT) {
wait_jf = timeout - jiffies;
wait_ms = jiffies_to_msecs(wait_jf);
if (wait_jf < 0)
@@ -3022,14 +3022,14 @@ static int __mdss_fb_wait_for_fence_sub(struct msm_sync_pt_data *sync_pt_data,
MDSS_XLOG_TOUT_HANDLER("mdp");
ret = mdss_wait_sync_fence(fences[i], wait_ms);
- if (ret == -ETIME)
+ if (ret == -ETIMEDOUT)
break;
}
mdss_put_sync_fence(fences[i]);
}
if (ret < 0) {
- pr_err("%s: sync_fence_wait failed! ret = %x\n",
+ pr_err("%s: sync_fence_wait failed! ret = %d\n",
sync_pt_data->fence_name, ret);
for (; i < fence_cnt; i++)
mdss_put_sync_fence(fences[i]);
diff --git a/fs/proc/inode.c b/fs/proc/inode.c
index e69ebe648a34..be3e1db832b5 100644
--- a/fs/proc/inode.c
+++ b/fs/proc/inode.c
@@ -456,17 +456,12 @@ struct inode *proc_get_inode(struct super_block *sb, struct proc_dir_entry *de)
return inode;
}
-int proc_fill_super(struct super_block *s, void *data, int silent)
+int proc_fill_super(struct super_block *s)
{
- struct pid_namespace *ns = get_pid_ns(s->s_fs_info);
struct inode *root_inode;
int ret;
- if (!proc_parse_options(data, ns))
- return -EINVAL;
-
- /* User space would break if executables or devices appear on proc */
- s->s_iflags |= SB_I_USERNS_VISIBLE | SB_I_NOEXEC | SB_I_NODEV;
+ s->s_iflags |= SB_I_USERNS_VISIBLE | SB_I_NODEV;
s->s_flags |= MS_NODIRATIME | MS_NOSUID | MS_NOEXEC;
s->s_blocksize = 1024;
s->s_blocksize_bits = 10;
diff --git a/fs/proc/internal.h b/fs/proc/internal.h
index d8105cd8b01c..d8edf39e0c1d 100644
--- a/fs/proc/internal.h
+++ b/fs/proc/internal.h
@@ -213,7 +213,7 @@ extern const struct file_operations proc_reclaim_operations;
extern void proc_init_inodecache(void);
extern struct inode *proc_get_inode(struct super_block *, struct proc_dir_entry *);
-extern int proc_fill_super(struct super_block *, void *data, int flags);
+extern int proc_fill_super(struct super_block *);
extern void proc_entry_rundown(struct proc_dir_entry *);
/*
@@ -278,7 +278,6 @@ static inline void proc_tty_init(void) {}
* root.c
*/
extern struct proc_dir_entry proc_root;
-extern int proc_parse_options(char *options, struct pid_namespace *pid);
extern void proc_self_init(void);
extern int proc_remount(struct super_block *, int *, char *);
diff --git a/fs/proc/root.c b/fs/proc/root.c
index c2f5014d642d..1d68fcd9313f 100644
--- a/fs/proc/root.c
+++ b/fs/proc/root.c
@@ -23,6 +23,21 @@
#include "internal.h"
+static int proc_test_super(struct super_block *sb, void *data)
+{
+ return sb->s_fs_info == data;
+}
+
+static int proc_set_super(struct super_block *sb, void *data)
+{
+ int err = set_anon_super(sb, NULL);
+ if (!err) {
+ struct pid_namespace *ns = (struct pid_namespace *)data;
+ sb->s_fs_info = get_pid_ns(ns);
+ }
+ return err;
+}
+
enum {
Opt_gid, Opt_hidepid, Opt_err,
};
@@ -33,7 +48,7 @@ static const match_table_t tokens = {
{Opt_err, NULL},
};
-int proc_parse_options(char *options, struct pid_namespace *pid)
+static int proc_parse_options(char *options, struct pid_namespace *pid)
{
char *p;
substring_t args[MAX_OPT_ARGS];
@@ -85,16 +100,45 @@ int proc_remount(struct super_block *sb, int *flags, char *data)
static struct dentry *proc_mount(struct file_system_type *fs_type,
int flags, const char *dev_name, void *data)
{
+ int err;
+ struct super_block *sb;
struct pid_namespace *ns;
+ char *options;
if (flags & MS_KERNMOUNT) {
- ns = data;
- data = NULL;
+ ns = (struct pid_namespace *)data;
+ options = NULL;
} else {
ns = task_active_pid_ns(current);
+ options = data;
+
+ /* Does the mounter have privilege over the pid namespace? */
+ if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN))
+ return ERR_PTR(-EPERM);
+ }
+
+ sb = sget(fs_type, proc_test_super, proc_set_super, flags, ns);
+ if (IS_ERR(sb))
+ return ERR_CAST(sb);
+
+ if (!proc_parse_options(options, ns)) {
+ deactivate_locked_super(sb);
+ return ERR_PTR(-EINVAL);
+ }
+
+ if (!sb->s_root) {
+ err = proc_fill_super(sb);
+ if (err) {
+ deactivate_locked_super(sb);
+ return ERR_PTR(err);
+ }
+
+ sb->s_flags |= MS_ACTIVE;
+ /* User space would break if executables appear on proc */
+ sb->s_iflags |= SB_I_NOEXEC;
}
- return mount_ns(fs_type, flags, data, ns, ns->user_ns, proc_fill_super);
+ return dget(sb->s_root);
}
static void proc_kill_sb(struct super_block *sb)
diff --git a/include/dt-bindings/clock/msm-clocks-hwio-8952.h b/include/dt-bindings/clock/msm-clocks-hwio-8952.h
index cba5a864b1d2..a8483cb6ae98 100644
--- a/include/dt-bindings/clock/msm-clocks-hwio-8952.h
+++ b/include/dt-bindings/clock/msm-clocks-hwio-8952.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-2016, 2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2016, 2018-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -294,7 +294,8 @@
#define dsi0_1phypll_source_val 3 /* byte1_clk & pclk1_clk */
#define dsi1_0phypll_source_val 3 /* byte0_clk & pclk0_clk */
#define dsi1_1phypll_source_val 1 /* byte1_clk & pclk1_clk */
-
+#define gpll0_gfx_source_val 5 /* GPLL0 GFX on QM215 */
+#define gpll6_gfx_source_val 6 /* GPLL6 GFX on QM215 */
#define F(f, s, div, m, n) \
{ \
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index d32e7b8c0b87..29dedd4eb1b1 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -497,8 +497,8 @@ struct perf_addr_filters_head {
* enum perf_event_active_state - the states of a event
*/
enum perf_event_active_state {
- PERF_EVENT_STATE_DEAD = -5,
- PERF_EVENT_STATE_ZOMBIE = -4,
+ PERF_EVENT_STATE_DORMANT = -5,
+ PERF_EVENT_STATE_DEAD = -4,
PERF_EVENT_STATE_EXIT = -3,
PERF_EVENT_STATE_ERROR = -2,
PERF_EVENT_STATE_OFF = -1,
@@ -721,7 +721,13 @@ struct perf_event {
/* Is this event shared with other events */
bool shared;
- struct list_head zombie_entry;
+
+ /*
+ * Entry into the list that holds the events whose CPUs
+ * are offline. These events will be installed once the
+ * CPU wakes up and will be removed from the list after that
+ */
+ struct list_head dormant_event_entry;
#endif /* CONFIG_PERF_EVENTS */
};
@@ -1401,9 +1407,11 @@ static struct device_attribute format_attr_##_name = __ATTR_RO(_name)
#ifdef CONFIG_PERF_EVENTS
int perf_event_init_cpu(unsigned int cpu);
int perf_event_exit_cpu(unsigned int cpu);
+int perf_event_restart_events(unsigned int cpu);
#else
#define perf_event_init_cpu NULL
#define perf_event_exit_cpu NULL
+#define perf_event_restart_events NULL
#endif
#endif /* _LINUX_PERF_EVENT_H */
diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
index 6ec5e52e16ec..93b79a4b1dcc 100644
--- a/include/linux/power_supply.h
+++ b/include/linux/power_supply.h
@@ -304,6 +304,7 @@ enum power_supply_property {
POWER_SUPPLY_PROP_QC_OPTI_DISABLE,
POWER_SUPPLY_PROP_FCC_STEPPER_ENABLE,
POWER_SUPPLY_PROP_CC_SOC,
+ POWER_SUPPLY_PROP_QG_VBMS_MODE,
/* Local extensions of type int64_t */
POWER_SUPPLY_PROP_CHARGE_COUNTER_EXT,
/* Properties of type `const char *' */
diff --git a/include/uapi/linux/qg.h b/include/uapi/linux/qg.h
index 54aa36261980..8bd220fbc6a8 100644
--- a/include/uapi/linux/qg.h
+++ b/include/uapi/linux/qg.h
@@ -21,7 +21,7 @@ enum qg {
QG_FULL_SOC,
QG_CLEAR_LEARNT_DATA,
QG_SYS_SOC,
- QG_RESERVED_10,
+ QG_VBMS_IBAT,
QG_MAX,
};
@@ -34,6 +34,7 @@ enum qg {
#define QG_FULL_SOC QG_FULL_SOC
#define QG_CLEAR_LEARNT_DATA QG_CLEAR_LEARNT_DATA
#define QG_SYS_SOC QG_SYS_SOC
+#define QG_VBMS_IBAT QG_VBMS_IBAT
struct fifo_data {
unsigned int v;
diff --git a/include/uapi/media/cam_req_mgr.h b/include/uapi/media/cam_req_mgr.h
index 0b4f1cc40df3..b903078dccbd 100644
--- a/include/uapi/media/cam_req_mgr.h
+++ b/include/uapi/media/cam_req_mgr.h
@@ -383,10 +383,12 @@ struct cam_mem_cache_ops_cmd {
* @CAM_REQ_MGR_ERROR_TYPE_DEVICE: Device error message, fatal to session
* @CAM_REQ_MGR_ERROR_TYPE_REQUEST: Error on a single request, not fatal
* @CAM_REQ_MGR_ERROR_TYPE_BUFFER: Buffer was not filled, not fatal
+ * @CAM_REQ_MGR_ERROR_TYPE_RECOVERY: Fatal error, can be recovered
*/
#define CAM_REQ_MGR_ERROR_TYPE_DEVICE 0
#define CAM_REQ_MGR_ERROR_TYPE_REQUEST 1
#define CAM_REQ_MGR_ERROR_TYPE_BUFFER 2
+#define CAM_REQ_MGR_ERROR_TYPE_RECOVERY 3
/**
* struct cam_req_mgr_error_msg
diff --git a/kernel/cpu.c b/kernel/cpu.c
index aa035154bb72..df007c474778 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -1463,7 +1463,7 @@ static struct cpuhp_step cpuhp_ap_states[] = {
},
[CPUHP_AP_PERF_ONLINE] = {
.name = "perf:online",
- .startup.single = perf_event_init_cpu,
+ .startup.single = perf_event_restart_events,
.teardown.single = perf_event_exit_cpu,
},
[CPUHP_AP_WORKQUEUE_ONLINE] = {
diff --git a/kernel/events/core.c b/kernel/events/core.c
index 6be8ea2fb116..8dd675001654 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -2315,6 +2315,23 @@ static void ctx_resched(struct perf_cpu_context *cpuctx,
perf_pmu_enable(cpuctx->ctx.pmu);
}
+#if defined CONFIG_HOTPLUG_CPU || defined CONFIG_KEXEC_CORE
+static LIST_HEAD(dormant_event_list);
+static DEFINE_SPINLOCK(dormant_event_list_lock);
+
+static void perf_prepare_install_in_context(struct perf_event *event)
+{
+ spin_lock(&dormant_event_list_lock);
+ if (event->state == PERF_EVENT_STATE_DORMANT)
+ goto out;
+
+ event->state = PERF_EVENT_STATE_DORMANT;
+ list_add_tail(&event->dormant_event_entry, &dormant_event_list);
+out:
+ spin_unlock(&dormant_event_list_lock);
+}
+#endif
+
/*
* Cross CPU call to install and enable a performance event
*
@@ -2460,6 +2477,34 @@ again:
raw_spin_unlock_irq(&ctx->lock);
}
+#if defined CONFIG_HOTPLUG_CPU || defined CONFIG_KEXEC_CORE
+static void perf_deferred_install_in_context(int cpu)
+{
+ struct perf_event *event, *tmp;
+ struct perf_event_context *ctx;
+
+ spin_lock(&dormant_event_list_lock);
+ list_for_each_entry_safe(event, tmp, &dormant_event_list,
+ dormant_event_entry) {
+ if (cpu != event->cpu)
+ continue;
+
+ list_del(&event->dormant_event_entry);
+ event->state = PERF_EVENT_STATE_INACTIVE;
+ spin_unlock(&dormant_event_list_lock);
+
+ ctx = event->ctx;
+
+ mutex_lock(&ctx->mutex);
+ perf_install_in_context(ctx, event, cpu);
+ mutex_unlock(&ctx->mutex);
+
+ spin_lock(&dormant_event_list_lock);
+ }
+ spin_unlock(&dormant_event_list_lock);
+}
+#endif
+
/*
* Put a event into inactive state and update time fields.
* Enabling the leader of a group effectively enables all
@@ -4277,14 +4322,6 @@ static void put_event(struct perf_event *event)
}
/*
- * Maintain a zombie list to collect all the zombie events
- */
-#if defined CONFIG_HOTPLUG_CPU || defined CONFIG_KEXEC_CORE
-static LIST_HEAD(zombie_list);
-static DEFINE_SPINLOCK(zombie_list_lock);
-#endif
-
-/*
* Kill an event dead; while event:refcount will preserve the event
* object, it will not preserve its functionality. Once the last 'user'
* gives up the object, we'll destroy the thing.
@@ -4294,23 +4331,12 @@ static int __perf_event_release_kernel(struct perf_event *event)
struct perf_event_context *ctx = event->ctx;
struct perf_event *child, *tmp;
- /*
- * If the cpu associated to this event is offline, set the event as a
- * zombie event. The cleanup of the cpu would be done if the CPU is
- * back online.
- */
#if defined CONFIG_HOTPLUG_CPU || defined CONFIG_KEXEC_CORE
- if (event->cpu != -1 && per_cpu(is_hotplugging, event->cpu)) {
- if (event->state == PERF_EVENT_STATE_ZOMBIE)
- return 0;
-
- event->state = PERF_EVENT_STATE_ZOMBIE;
-
- spin_lock(&zombie_list_lock);
- list_add_tail(&event->zombie_entry, &zombie_list);
- spin_unlock(&zombie_list_lock);
-
- return 0;
+ if (event->cpu != -1) {
+ spin_lock(&dormant_event_list_lock);
+ if (event->state == PERF_EVENT_STATE_DORMANT)
+ list_del(&event->dormant_event_entry);
+ spin_unlock(&dormant_event_list_lock);
}
#endif
@@ -4627,6 +4653,15 @@ perf_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
struct perf_event_context *ctx;
int ret;
+#if defined CONFIG_HOTPLUG_CPU || defined CONFIG_KEXEC_CORE
+ spin_lock(&dormant_event_list_lock);
+ if (event->state == PERF_EVENT_STATE_DORMANT) {
+ spin_unlock(&dormant_event_list_lock);
+ return 0;
+ }
+ spin_unlock(&dormant_event_list_lock);
+#endif
+
ctx = perf_event_ctx_lock(event);
ret = __perf_read(event, buf, count);
perf_event_ctx_unlock(event, ctx);
@@ -9455,13 +9490,13 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu,
mutex_init(&event->child_mutex);
INIT_LIST_HEAD(&event->child_list);
+ INIT_LIST_HEAD(&event->dormant_event_entry);
INIT_LIST_HEAD(&event->group_entry);
INIT_LIST_HEAD(&event->event_entry);
INIT_LIST_HEAD(&event->sibling_list);
INIT_LIST_HEAD(&event->rb_entry);
INIT_LIST_HEAD(&event->active_entry);
INIT_LIST_HEAD(&event->addr_filters.list);
- INIT_LIST_HEAD(&event->zombie_entry);
INIT_HLIST_NODE(&event->hlist_entry);
@@ -11114,111 +11149,27 @@ int perf_event_init_cpu(unsigned int cpu)
}
#if defined CONFIG_HOTPLUG_CPU || defined CONFIG_KEXEC_CORE
-static void
-check_hotplug_start_event(struct perf_event *event)
-{
- if (event->pmu->events_across_hotplug &&
- event->attr.type == PERF_TYPE_SOFTWARE &&
- event->pmu->start)
- event->pmu->start(event, 0);
-}
-
-static void perf_event_zombie_cleanup(unsigned int cpu)
+int perf_event_restart_events(unsigned int cpu)
{
- struct perf_event *event, *tmp;
-
- spin_lock(&zombie_list_lock);
-
- list_for_each_entry_safe(event, tmp, &zombie_list, zombie_entry) {
- if (event->cpu != cpu)
- continue;
-
- list_del(&event->zombie_entry);
- spin_unlock(&zombie_list_lock);
-
- /*
- * The detachment of the event with the
- * PMU expects it to be in an active state
- */
- event->state = PERF_EVENT_STATE_ACTIVE;
- __perf_event_release_kernel(event);
-
- spin_lock(&zombie_list_lock);
- }
-
- spin_unlock(&zombie_list_lock);
-}
-
-static int perf_event_start_swevents(unsigned int cpu)
-{
- struct perf_event_context *ctx;
- struct pmu *pmu;
- struct perf_event *event;
- int idx;
-
mutex_lock(&pmus_lock);
- perf_event_zombie_cleanup(cpu);
-
- idx = srcu_read_lock(&pmus_srcu);
- list_for_each_entry_rcu(pmu, &pmus, entry) {
- ctx = &per_cpu_ptr(pmu->pmu_cpu_context, cpu)->ctx;
- mutex_lock(&ctx->mutex);
- raw_spin_lock(&ctx->lock);
- list_for_each_entry(event, &ctx->event_list, event_entry)
- check_hotplug_start_event(event);
- raw_spin_unlock(&ctx->lock);
- mutex_unlock(&ctx->mutex);
- }
- srcu_read_unlock(&pmus_srcu, idx);
per_cpu(is_hotplugging, cpu) = false;
+ perf_deferred_install_in_context(cpu);
mutex_unlock(&pmus_lock);
return 0;
}
-/*
- * If keeping events across hotplugging is supported, do not
- * remove the event list so event lives beyond CPU hotplug.
- * The context is exited via an fd close path when userspace
- * is done and the target CPU is online. If software clock
- * event is active, then stop hrtimer associated with it.
- * Start the timer when the CPU comes back online.
- */
-static void
-check_hotplug_remove_from_context(struct perf_event *event,
- struct perf_cpu_context *cpuctx,
- struct perf_event_context *ctx)
-{
- if (event->pmu->events_across_hotplug &&
- event->attr.type == PERF_TYPE_SOFTWARE &&
- event->pmu->stop)
- event->pmu->stop(event, PERF_EF_UPDATE);
- else if (!event->pmu->events_across_hotplug)
- __perf_remove_from_context(event, cpuctx,
- ctx, (void *)DETACH_GROUP);
-}
-
-static void __perf_event_exit_context(void *__info)
-{
- struct perf_event_context *ctx = __info;
- struct perf_cpu_context *cpuctx = __get_cpu_context(ctx);
- struct perf_event *event;
-
- raw_spin_lock(&ctx->lock);
- list_for_each_entry(event, &ctx->event_list, event_entry)
- check_hotplug_remove_from_context(event, cpuctx, ctx);
- raw_spin_unlock(&ctx->lock);
-}
-
static void perf_event_exit_cpu_context(int cpu)
{
struct perf_cpu_context *cpuctx;
struct perf_event_context *ctx;
unsigned long flags;
+ struct perf_event *event, *event_tmp;
struct pmu *pmu;
int idx;
idx = srcu_read_lock(&pmus_srcu);
+ per_cpu(is_hotplugging, cpu) = true;
list_for_each_entry_rcu(pmu, &pmus, entry) {
cpuctx = per_cpu_ptr(pmu->pmu_cpu_context, cpu);
ctx = &cpuctx->ctx;
@@ -11233,7 +11184,12 @@ static void perf_event_exit_cpu_context(int cpu)
}
mutex_lock(&ctx->mutex);
- smp_call_function_single(cpu, __perf_event_exit_context, ctx, 1);
+ list_for_each_entry_safe(event, event_tmp, &ctx->event_list,
+ event_entry) {
+ perf_remove_from_context(event, DETACH_GROUP);
+ if (event->pmu->events_across_hotplug)
+ perf_prepare_install_in_context(event);
+ }
mutex_unlock(&ctx->mutex);
}
srcu_read_unlock(&pmus_srcu, idx);
@@ -11246,8 +11202,8 @@ static void perf_event_exit_cpu_context(int cpu) { }
int perf_event_exit_cpu(unsigned int cpu)
{
+
mutex_lock(&pmus_lock);
- per_cpu(is_hotplugging, cpu) = true;
perf_event_exit_cpu_context(cpu);
mutex_unlock(&pmus_lock);
return 0;
@@ -11292,25 +11248,6 @@ static struct notifier_block perf_event_idle_nb = {
.notifier_call = event_idle_notif,
};
-#ifdef CONFIG_HOTPLUG_CPU
-static int perf_cpu_hp_init(void)
-{
- int ret;
-
- ret = cpuhp_setup_state_nocalls(CPUHP_AP_PERF_ONLINE,
- "PERF/CORE/CPUHP_AP_PERF_ONLINE",
- perf_event_start_swevents,
- perf_event_exit_cpu);
- if (ret)
- pr_err("CPU hotplug notifier for perf core could not be registered: %d\n",
- ret);
-
- return ret;
-}
-#else
-static int perf_cpu_hp_init(void) { return 0; }
-#endif
-
void __init perf_event_init(void)
{
int ret, cpu;
@@ -11337,8 +11274,6 @@ void __init perf_event_init(void)
perf_event_init_cpu(smp_processor_id());
idle_notifier_register(&perf_event_idle_nb);
register_reboot_notifier(&perf_reboot_notifier);
- ret = perf_cpu_hp_init();
- WARN(ret, "core perf_cpu_hp_init() failed with: %d", ret);
ret = init_hw_breakpoint();
WARN(ret, "hw_breakpoint initialization failed with: %d", ret);
diff --git a/mm/memory.c b/mm/memory.c
index 7a88700906d2..ccf1a6b9f7e1 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -943,6 +943,7 @@ static int copy_pte_range(struct mm_struct *dst_mm, struct mm_struct *src_mm,
spinlock_t *src_ptl, *dst_ptl;
int progress = 0;
int rss[NR_MM_COUNTERS];
+ unsigned long orig_addr = addr;
swp_entry_t entry = (swp_entry_t){0};
again:
@@ -981,6 +982,15 @@ again:
} while (dst_pte++, src_pte++, addr += PAGE_SIZE, addr != end);
arch_leave_lazy_mmu_mode();
+
+ /*
+ * Prevent the page fault handler to copy the page while stale tlb entry
+ * are still not flushed.
+ */
+ if (IS_ENABLED(CONFIG_SPECULATIVE_PAGE_FAULT) &&
+ is_cow_mapping(vma->vm_flags))
+ flush_tlb_range(vma, orig_addr, end);
+
spin_unlock(src_ptl);
pte_unmap(orig_src_pte);
add_mm_rss_vec(dst_mm, rss);
diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
index 0534378309ff..409662fdc74c 100755
--- a/scripts/checkpatch.pl
+++ b/scripts/checkpatch.pl
@@ -2618,7 +2618,7 @@ sub process {
$sig_nospace =~ s/\s//g;
$sig_nospace = lc($sig_nospace);
if (defined $signatures{$sig_nospace}) {
- WARN("BAD_SIGN_OFF",
+ WARN("DUPLICATE_SIGN_OFF",
"Duplicate signature\n" . $herecurr);
} else {
$signatures{$sig_nospace} = 1;