diff options
author | Linux Build Service Account <lnxbuild@localhost> | 2019-02-17 10:16:56 -0800 |
---|---|---|
committer | Linux Build Service Account <lnxbuild@localhost> | 2019-02-17 10:16:56 -0800 |
commit | e2f180b56585f70bc9521bd89900a89ae8ef53f6 (patch) | |
tree | 3f1843dd05260bd3c3eab9308978bdfc0e37052a | |
parent | 9753c747140da1ffbc114cf38fb7e4a0438345a4 (diff) | |
parent | e4c9b6f1af3b6dbbc6e01a00a4e9fbc7cdebd3a2 (diff) |
Merge e4c9b6f1af3b6dbbc6e01a00a4e9fbc7cdebd3a2 on remote branchLA.UM.7.8.r1-04800-SDM710.0
Change-Id: I3159c8dc8c0e4fdf4fce8c85c38e261cb9737b24
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(¬ify); - 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(¬ify); - 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(¬ify); - 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(¬ify); 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(¬ify); + + /* + * 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(¬ify); + 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(¬ify); + 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; |