diff options
author | Linux Build Service Account <lnxbuild@localhost> | 2019-11-05 04:33:42 -0800 |
---|---|---|
committer | Linux Build Service Account <lnxbuild@localhost> | 2019-11-05 04:33:42 -0800 |
commit | 23d122c5b5ec3cd7806c9115bc76231c9da81578 (patch) | |
tree | 4565c687c57b226e578979cf35f013be4e416fd9 | |
parent | cc87714b357b0bbd6a71ba9ecabf3f1bbba220af (diff) | |
parent | 836f69c9b1d0d5e9afcad9052aaca7bc3938f758 (diff) |
Merge 836f69c9b1d0d5e9afcad9052aaca7bc3938f758 on remote branchLA.UM.7.1.r1-17200-sm8150.0
Change-Id: Icc84bba202d180e185d3bf9d56d3d9c27e7ac84f
73 files changed, 3156 insertions, 182 deletions
diff --git a/Documentation/devicetree/bindings/arm/msm/imem.txt b/Documentation/devicetree/bindings/arm/msm/imem.txt index 440628d02630..8e69affce058 100644 --- a/Documentation/devicetree/bindings/arm/msm/imem.txt +++ b/Documentation/devicetree/bindings/arm/msm/imem.txt @@ -78,6 +78,11 @@ SSR Minidump Offset -Compatible: "qcom,msm-imem-minidump" -reg: start address and size of ssr imem region +Minidump Debug Offset +---------------------- +-Compatible: "qcom,msm-imem-minidump-debug" +-reg: start address and size minidump debug imem region + Required properties: -compatible: "qcom,msm-imem-diag-dload" -reg: start address and size of USB Diag download mode region in imem @@ -131,4 +136,9 @@ Example: compatible = "qcom,msm-imem-minidump"; reg = <0xb88 28>; }; + + minidump_debug@b0c { + compatible = "qcom,msm-imem-minidump-debug"; + reg = <0xb0c 0x4>; + }; }; diff --git a/arch/arm64/boot/dts/qcom/sdmmagpie.dtsi b/arch/arm64/boot/dts/qcom/sdmmagpie.dtsi index 48832e55c26d..71a51095d6a4 100644 --- a/arch/arm64/boot/dts/qcom/sdmmagpie.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmmagpie.dtsi @@ -546,55 +546,55 @@ pil_modem_mem: modem_region@8b000000 { compatible = "removed-dma-pool"; no-map; - reg = <0 0x8b000000 0 0x7e00000>; + reg = <0 0x8b000000 0 0x8400000>; }; - pil_video_mem: pil_video_region@92e00000 { + pil_video_mem: pil_video_region@93400000 { compatible = "removed-dma-pool"; no-map; - reg = <0 0x92e00000 0 0x500000>; + reg = <0 0x93400000 0 0x500000>; }; - pil_cdsp_mem: cdsp_regions@93300000 { + pil_cdsp_mem: cdsp_regions@93900000 { compatible = "removed-dma-pool"; no-map; - reg = <0 0x93300000 0 0x1e00000>; + reg = <0 0x93900000 0 0x1e00000>; }; - pil_adsp_mem: pil_adsp_region@95100000 { + pil_adsp_mem: pil_adsp_region@95700000 { compatible = "removed-dma-pool"; no-map; - reg = <0 0x95100000 0 0x1e00000>; + reg = <0 0x95700000 0 0x1e00000>; }; - wlan_msa_mem: wlan_msa_region@96f00000 { + wlan_msa_mem: wlan_msa_region@97500000 { compatible = "removed-dma-pool"; no-map; - reg = <0 0x96f00000 0 0x180000>; + reg = <0 0x97500000 0 0x180000>; }; - npu_mem: npu_region@97080000 { + npu_mem: npu_region@97680000 { compatible = "removed-dma-pool"; no-map; - reg = <0 0x97080000 0 0x80000>; + reg = <0 0x97680000 0 0x80000>; }; - pil_ipa_fw_mem: ips_fw_region@97100000 { + pil_ipa_fw_mem: ips_fw_region@97700000 { compatible = "removed-dma-pool"; no-map; - reg = <0 0x97100000 0 0x10000>; + reg = <0 0x97700000 0 0x10000>; }; - pil_ipa_gsi_mem: ipa_gsi_region@97110000 { + pil_ipa_gsi_mem: ipa_gsi_region@97710000 { compatible = "removed-dma-pool"; no-map; - reg = <0 0x97110000 0 0x5000>; + reg = <0 0x97710000 0 0x5000>; }; - pil_gpu_mem: gpu_region@97115000 { + pil_gpu_mem: gpu_region@97715000 { compatible = "removed-dma-pool"; no-map; - reg = <0 0x97115000 0 0x2000>; + reg = <0 0x97715000 0 0x2000>; }; qseecom_mem: qseecom_region@9e400000 { diff --git a/arch/arm64/boot/dts/qcom/sm6150.dtsi b/arch/arm64/boot/dts/qcom/sm6150.dtsi index 5c964fc69c68..0b394f986bdf 100644 --- a/arch/arm64/boot/dts/qcom/sm6150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150.dtsi @@ -542,49 +542,49 @@ pil_modem_mem: modem_region@8b000000 { compatible = "removed-dma-pool"; no-map; - reg = <0 0x8b000000 0 0x7e00000>; + reg = <0 0x8b000000 0 0x8400000>; }; - pil_video_mem: pil_video_region@92e00000 { + pil_video_mem: pil_video_region@93400000 { compatible = "removed-dma-pool"; no-map; - reg = <0 0x92e00000 0 0x500000>; + reg = <0 0x93400000 0 0x500000>; }; - wlan_msa_mem: wlan_msa_region@93300000 { + wlan_msa_mem: wlan_msa_region@93900000 { compatible = "removed-dma-pool"; no-map; - reg = <0 0x93300000 0 0x200000>; + reg = <0 0x93900000 0 0x200000>; }; - pil_cdsp_mem: cdsp_regions@93500000 { + pil_cdsp_mem: cdsp_regions@93b00000 { compatible = "removed-dma-pool"; no-map; - reg = <0 0x93500000 0 0x1e00000>; + reg = <0 0x93b00000 0 0x1e00000>; }; - pil_adsp_mem: pil_adsp_region@95300000 { + pil_adsp_mem: pil_adsp_region@95900000 { compatible = "removed-dma-pool"; no-map; - reg = <0 0x95300000 0 0x1e00000>; + reg = <0 0x95900000 0 0x1e00000>; }; - pil_ipa_fw_mem: ips_fw_region@0x97100000 { + pil_ipa_fw_mem: ips_fw_region@0x97700000 { compatible = "removed-dma-pool"; no-map; - reg = <0 0x97100000 0 0x10000>; + reg = <0 0x97700000 0 0x10000>; }; - pil_ipa_gsi_mem: ipa_gsi_region@0x97110000 { + pil_ipa_gsi_mem: ipa_gsi_region@0x97710000 { compatible = "removed-dma-pool"; no-map; - reg = <0 0x97110000 0 0x5000>; + reg = <0 0x97710000 0 0x5000>; }; - pil_gpu_mem: gpu_region@0x97115000 { + pil_gpu_mem: gpu_region@0x97715000 { compatible = "removed-dma-pool"; no-map; - reg = <0 0x97115000 0 0x2000>; + reg = <0 0x97715000 0 0x2000>; }; qseecom_mem: qseecom_region@0x9e400000 { diff --git a/arch/arm64/boot/dts/qcom/sm8150.dtsi b/arch/arm64/boot/dts/qcom/sm8150.dtsi index 99e44d95a9c7..a53d4e772839 100644 --- a/arch/arm64/boot/dts/qcom/sm8150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150.dtsi @@ -1346,6 +1346,11 @@ reg = <0x94c 200>; }; + minidump_debug@b0c { + compatible = "qcom,msm-imem-minidump-debug"; + reg = <0xb0c 0x4>; + }; + diag_dload@c8 { compatible = "qcom,msm-imem-diag-dload"; reg = <0xc8 200>; diff --git a/drivers/bus/mhi/devices/mhi_uci.c b/drivers/bus/mhi/devices/mhi_uci.c index 7dd2ac71e65f..648ae65e3597 100644 --- a/drivers/bus/mhi/devices/mhi_uci.c +++ b/drivers/bus/mhi/devices/mhi_uci.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 @@ -53,6 +53,7 @@ struct uci_dev { struct uci_chan ul_chan; struct uci_chan dl_chan; size_t mtu; + size_t actual_mtu; /* maximum size of incoming buffer */ int ref_count; bool enabled; void *ipc_log; @@ -122,22 +123,24 @@ static int mhi_queue_inbound(struct uci_dev *uci_dev) struct mhi_device *mhi_dev = uci_dev->mhi_dev; int nr_trbs = mhi_get_no_free_descriptors(mhi_dev, DMA_FROM_DEVICE); size_t mtu = uci_dev->mtu; + size_t actual_mtu = uci_dev->actual_mtu; void *buf; struct uci_buf *uci_buf; int ret = -EIO, i; for (i = 0; i < nr_trbs; i++) { - buf = kmalloc(mtu + sizeof(*uci_buf), GFP_KERNEL); + buf = kmalloc(mtu, GFP_KERNEL); if (!buf) return -ENOMEM; - uci_buf = buf + mtu; + uci_buf = buf + actual_mtu; uci_buf->data = buf; - MSG_VERB("Allocated buf %d of %d size %ld\n", i, nr_trbs, mtu); + MSG_VERB("Allocated buf %d of %d size %ld\n", i, nr_trbs, + actual_mtu); - ret = mhi_queue_transfer(mhi_dev, DMA_FROM_DEVICE, buf, mtu, - MHI_EOT); + ret = mhi_queue_transfer(mhi_dev, DMA_FROM_DEVICE, buf, + actual_mtu, MHI_EOT); if (ret) { kfree(buf); MSG_ERR("Failed to queue buffer %d\n", i); @@ -412,8 +415,8 @@ static ssize_t mhi_uci_read(struct file *file, if (uci_dev->enabled) ret = mhi_queue_transfer(mhi_dev, DMA_FROM_DEVICE, - uci_buf->data, uci_dev->mtu, - MHI_EOT); + uci_buf->data, + uci_dev->actual_mtu, MHI_EOT); else ret = -ERESTARTSYS; @@ -600,6 +603,7 @@ static int mhi_uci_probe(struct mhi_device *mhi_dev, }; uci_dev->mtu = min_t(size_t, id->driver_data, mhi_dev->mtu); + uci_dev->actual_mtu = uci_dev->mtu - sizeof(struct uci_buf); mhi_device_set_devdata(mhi_dev, uci_dev); uci_dev->enabled = true; @@ -643,7 +647,7 @@ static void mhi_dl_xfer_cb(struct mhi_device *mhi_dev, } spin_lock_irqsave(&uci_chan->lock, flags); - buf = mhi_result->buf_addr + uci_dev->mtu; + buf = mhi_result->buf_addr + uci_dev->actual_mtu; buf->data = mhi_result->buf_addr; buf->len = mhi_result->bytes_xferd; list_add_tail(&buf->node, &uci_chan->pending); diff --git a/drivers/char/diag/diag_masks.c b/drivers/char/diag/diag_masks.c index e2b022affbee..f60c94a05531 100644 --- a/drivers/char/diag/diag_masks.c +++ b/drivers/char/diag/diag_masks.c @@ -907,7 +907,8 @@ static int diag_cmd_set_msg_mask(unsigned char *src_buf, int src_len, goto end; if (mask_size + write_len > dest_len) mask_size = dest_len - write_len; - memcpy(dest_buf + write_len, src_buf + header_len, mask_size); + if (mask_size && src_len >= header_len + mask_size) + memcpy(dest_buf + write_len, src_buf + header_len, mask_size); write_len += mask_size; for (i = 0; i < NUM_MD_SESSIONS; i++) { if (i == APPS_DATA) diff --git a/drivers/crypto/msm/ice.c b/drivers/crypto/msm/ice.c index 08218503b2fe..ab9f7f6dec84 100644 --- a/drivers/crypto/msm/ice.c +++ b/drivers/crypto/msm/ice.c @@ -26,7 +26,8 @@ #include <soc/qcom/qseecomi.h> #include "iceregs.h" #include <linux/pfk.h> - +#include <linux/atomic.h> +#include <linux/wait.h> #define TZ_SYSCALL_CREATE_SMC_ID(o, s, f) \ ((uint32_t)((((o & 0x3f) << 24) | (s & 0xff) << 8) | (f & 0xff))) @@ -114,6 +115,9 @@ struct ice_device { struct qcom_ice_bus_vote bus_vote; ktime_t ice_reset_start_time; ktime_t ice_reset_complete_time; + atomic_t is_ice_suspended; + atomic_t is_ice_busy; + wait_queue_head_t block_suspend_ice_queue; }; static int qti_ice_setting_config(struct request *req, @@ -807,7 +811,6 @@ static int qcom_ice_probe(struct platform_device *pdev) * operation arrives. */ ice_dev->is_ice_enabled = false; - platform_set_drvdata(pdev, ice_dev); list_add_tail(&ice_dev->list, &ice_devices); @@ -842,6 +845,21 @@ static int qcom_ice_remove(struct platform_device *pdev) static int qcom_ice_suspend(struct platform_device *pdev) { + struct ice_device *ice_dev; + + ice_dev = (struct ice_device *)platform_get_drvdata(pdev); + + if (!ice_dev) + return -EINVAL; + + if (atomic_read(&ice_dev->is_ice_busy) != 0) + wait_event_interruptible_timeout( + ice_dev->block_suspend_ice_queue, + atomic_read(&ice_dev->is_ice_busy) != 0, + msecs_to_jiffies(1000)); + + atomic_set(&ice_dev->is_ice_suspended, 1); + return 0; } @@ -1095,7 +1113,7 @@ static int qcom_ice_finish_init(struct ice_device *ice_dev) err = -EFAULT; goto out; } - + init_waitqueue_head(&ice_dev->block_suspend_ice_queue); qcom_ice_low_power_mode_enable(ice_dev); qcom_ice_optimization_enable(ice_dev); qcom_ice_config_proc_ignore(ice_dev); @@ -1103,7 +1121,8 @@ static int qcom_ice_finish_init(struct ice_device *ice_dev) qcom_ice_enable(ice_dev); ice_dev->is_ice_enabled = true; qcom_ice_enable_intr(ice_dev); - + atomic_set(&ice_dev->is_ice_suspended, 0); + atomic_set(&ice_dev->is_ice_busy, 0); out: return err; } @@ -1200,7 +1219,6 @@ static int qcom_ice_resume(struct platform_device *pdev) * after receiving this event */ struct ice_device *ice_dev; - ice_dev = platform_get_drvdata(pdev); if (!ice_dev) @@ -1214,7 +1232,7 @@ static int qcom_ice_resume(struct platform_device *pdev) */ qcom_ice_enable(ice_dev); } - + atomic_set(&ice_dev->is_ice_suspended, 0); return 0; } @@ -1456,11 +1474,18 @@ static int qcom_ice_config_start(struct platform_device *pdev, bool is_pfe = false; unsigned long sec_end = 0; sector_t data_size; + struct ice_device *ice_dev; if (!pdev || !req) { pr_err("%s: Invalid params passed\n", __func__); return -EINVAL; } + ice_dev = platform_get_drvdata(pdev); + + if (!ice_dev) { + pr_err("%s: INVALID ice_dev\n", __func__); + return -EINVAL; + } /* * It is not an error to have a request with no bio @@ -1477,7 +1502,18 @@ static int qcom_ice_config_start(struct platform_device *pdev, return 0; } + if (atomic_read(&ice_dev->is_ice_suspended) == 1) + return -EINVAL; + + if (async) + atomic_set(&ice_dev->is_ice_busy, 1); + ret = pfk_load_key_start(req->bio, &pfk_crypto_data, &is_pfe, async); + + if (async) { + atomic_set(&ice_dev->is_ice_busy, 0); + wake_up_interruptible(&ice_dev->block_suspend_ice_queue); + } if (is_pfe) { if (ret) { if (ret != -EBUSY && ret != -EAGAIN) @@ -1544,7 +1580,6 @@ static int qcom_ice_config_end(struct request *req) /* It is not an error to have a request with no bio */ return 0; } - ret = pfk_load_key_end(req->bio, &is_pfe); if (is_pfe) { if (ret != 0) diff --git a/drivers/devfreq/governor_gpubw_mon.c b/drivers/devfreq/governor_gpubw_mon.c index 6c53704aac9c..e17cf0de19ef 100644 --- a/drivers/devfreq/governor_gpubw_mon.c +++ b/drivers/devfreq/governor_gpubw_mon.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 @@ -232,10 +232,11 @@ static int devfreq_gpubw_event_handler(struct devfreq *devfreq, case DEVFREQ_GOV_SUSPEND: { struct devfreq_msm_adreno_tz_data *priv = devfreq->data; - - priv->bus.total_time = 0; - priv->bus.gpu_time = 0; - priv->bus.ram_time = 0; + if (priv) { + priv->bus.total_time = 0; + priv->bus.gpu_time = 0; + priv->bus.ram_time = 0; + } } break; default: diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c index fc7d164f2d36..2b4e2052d248 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c @@ -111,7 +111,7 @@ static ssize_t debugfs_state_info_read(struct file *file, dsi_ctrl->clk_freq.pix_clk_rate, dsi_ctrl->clk_freq.esc_clk_rate); - /* TODO: make sure that this does not exceed 4K */ + len = min_t(size_t, len, SZ_4K); if (copy_to_user(buff, buf, len)) { kfree(buf); return -EFAULT; @@ -166,8 +166,7 @@ static ssize_t debugfs_reg_dump_read(struct file *file, return rc; } - - /* TODO: make sure that this does not exceed 4K */ + len = min_t(size_t, len, SZ_4K); if (copy_to_user(buff, buf, len)) { kfree(buf); return -EFAULT; diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_drm.c b/drivers/gpu/drm/msm/dsi-staging/dsi_drm.c index 188fe23493c7..eee48496fdbb 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_drm.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_drm.c @@ -186,14 +186,15 @@ static void dsi_bridge_pre_enable(struct drm_bridge *bridge) return; } - SDE_ATRACE_BEGIN("dsi_bridge_pre_enable"); + SDE_ATRACE_BEGIN("dsi_display_prepare"); rc = dsi_display_prepare(c_bridge->display); if (rc) { pr_err("[%d] DSI display prepare failed, rc=%d\n", c_bridge->id, rc); - SDE_ATRACE_END("dsi_bridge_pre_enable"); + SDE_ATRACE_END("dsi_display_prepare"); return; } + SDE_ATRACE_END("dsi_display_prepare"); SDE_ATRACE_BEGIN("dsi_display_enable"); rc = dsi_display_enable(c_bridge->display); @@ -203,7 +204,6 @@ static void dsi_bridge_pre_enable(struct drm_bridge *bridge) (void)dsi_display_unprepare(c_bridge->display); } SDE_ATRACE_END("dsi_display_enable"); - SDE_ATRACE_END("dsi_bridge_pre_enable"); rc = dsi_display_splash_res_cleanup(c_bridge->display); if (rc) diff --git a/drivers/gpu/drm/msm/sde/sde_connector.c b/drivers/gpu/drm/msm/sde/sde_connector.c index 485b434ccb46..7352319e407c 100644 --- a/drivers/gpu/drm/msm/sde/sde_connector.c +++ b/drivers/gpu/drm/msm/sde/sde_connector.c @@ -1522,6 +1522,7 @@ static ssize_t _sde_debugfs_conn_cmd_tx_sts_read(struct file *file, return 0; } + blen = min_t(size_t, MAX_CMD_PAYLOAD_SIZE, count); if (copy_to_user(buf, buffer, blen)) { SDE_ERROR("copy to user buffer failed\n"); return -EFAULT; diff --git a/drivers/gpu/drm/msm/sde/sde_trace.h b/drivers/gpu/drm/msm/sde/sde_trace.h index 2909778f4e46..61807d572272 100644 --- a/drivers/gpu/drm/msm/sde/sde_trace.h +++ b/drivers/gpu/drm/msm/sde/sde_trace.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2017, 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 @@ -145,38 +145,24 @@ TRACE_EVENT(sde_encoder_underrun, ); TRACE_EVENT(tracing_mark_write, - TP_PROTO(int pid, const char *name, bool trace_begin), - TP_ARGS(pid, name, trace_begin), + TP_PROTO(char trace_type, const struct task_struct *task, + const char *name, int value), + TP_ARGS(trace_type, task, name, value), TP_STRUCT__entry( + __field(char, trace_type) __field(int, pid) __string(trace_name, name) - __field(bool, trace_begin) - ), - TP_fast_assign( - __entry->pid = pid; - __assign_str(trace_name, name); - __entry->trace_begin = trace_begin; - ), - TP_printk("%s|%d|%s", __entry->trace_begin ? "B" : "E", - __entry->pid, __get_str(trace_name)) -) - -TRACE_EVENT(sde_trace_counter, - TP_PROTO(int pid, char *name, int value), - TP_ARGS(pid, name, value), - TP_STRUCT__entry( - __field(int, pid) - __string(counter_name, name) __field(int, value) ), TP_fast_assign( - __entry->pid = current->tgid; - __assign_str(counter_name, name); + __entry->trace_type = trace_type; + __entry->pid = task ? task->tgid : 0; + __assign_str(trace_name, name); __entry->value = value; ), - TP_printk("%d|%s|%d", __entry->pid, - __get_str(counter_name), __entry->value) -) + TP_printk("%c|%d|%s|%d", __entry->trace_type, + __entry->pid, __get_str(trace_name), __entry->value) +); #define SDE_TRACE_EVTLOG_SIZE 15 TRACE_EVENT(sde_evtlog, @@ -319,12 +305,13 @@ TRACE_EVENT(sde_perf_calc_crtc, __entry->core_clk_rate) ); -#define SDE_ATRACE_END(name) trace_tracing_mark_write(current->tgid, name, 0) -#define SDE_ATRACE_BEGIN(name) trace_tracing_mark_write(current->tgid, name, 1) +#define sde_atrace trace_tracing_mark_write + +#define SDE_ATRACE_END(name) sde_atrace('E', current, name, 0) +#define SDE_ATRACE_BEGIN(name) sde_atrace('B', current, name, 0) #define SDE_ATRACE_FUNC() SDE_ATRACE_BEGIN(__func__) -#define SDE_ATRACE_INT(name, value) \ - trace_sde_trace_counter(current->tgid, name, value) +#define SDE_ATRACE_INT(name, value) sde_atrace('C', current, name, value) #endif /* _SDE_TRACE_H_ */ diff --git a/drivers/gpu/drm/msm/sde_power_handle.c b/drivers/gpu/drm/msm/sde_power_handle.c index b0627c20aacd..c66ede7cf01b 100644 --- a/drivers/gpu/drm/msm/sde_power_handle.c +++ b/drivers/gpu/drm/msm/sde_power_handle.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 @@ -1046,10 +1046,9 @@ int sde_power_resource_enable(struct sde_power_handle *phandle, SDE_POWER_EVENT_POST_DISABLE); } -end: SDE_EVT32_VERBOSE(enable, SDE_EVTLOG_FUNC_EXIT); - mutex_unlock(&phandle->phandle_lock); SDE_ATRACE_END("sde_power_resource_enable"); + mutex_unlock(&phandle->phandle_lock); return rc; clk_err: @@ -1063,8 +1062,10 @@ vreg_err: sde_power_data_bus_update(&phandle->data_bus_handle[i], 0); data_bus_hdl_err: phandle->current_usecase_ndx = prev_usecase_ndx; - mutex_unlock(&phandle->phandle_lock); SDE_ATRACE_END("sde_power_resource_enable"); + +end: + mutex_unlock(&phandle->phandle_lock); return rc; } diff --git a/drivers/gpu/drm/msm/sde_rsc.c b/drivers/gpu/drm/msm/sde_rsc.c index 2070c18c3c10..bd0b1e7840f8 100644 --- a/drivers/gpu/drm/msm/sde_rsc.c +++ b/drivers/gpu/drm/msm/sde_rsc.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 @@ -29,6 +29,7 @@ #include <drm/drm_irq.h> #include "sde_rsc_priv.h" #include "sde_dbg.h" +#include "sde_trace.h" #define SDE_RSC_DRV_DBG_NAME "sde_rsc_drv" #define SDE_RSC_WRAPPER_DBG_NAME "sde_rsc_wrapper" @@ -871,6 +872,7 @@ int sde_rsc_client_state_update(struct sde_rsc_client *caller_client, } pr_debug("state switch successfully complete: %d\n", state); + SDE_ATRACE_INT("rsc_state", state); rsc->current_state = state; SDE_EVT32(caller_client->id, caller_client->current_state, state, rsc->current_state, SDE_EVTLOG_FUNC_EXIT); @@ -1054,6 +1056,7 @@ end: if (blen <= 0) return 0; + blen = min_t(size_t, MAX_BUFFER_SIZE, count); if (copy_to_user(buf, buffer, blen)) return -EFAULT; @@ -1147,6 +1150,7 @@ end: if (blen <= 0) return 0; + blen = min_t(size_t, MAX_BUFFER_SIZE, count); if (copy_to_user(buf, buffer, blen)) return -EFAULT; diff --git a/drivers/gpu/msm/adreno_dispatch.c b/drivers/gpu/msm/adreno_dispatch.c index 478af4c725f6..54acb93cd67e 100644 --- a/drivers/gpu/msm/adreno_dispatch.c +++ b/drivers/gpu/msm/adreno_dispatch.c @@ -1396,6 +1396,22 @@ int adreno_dispatcher_queue_cmds(struct kgsl_device_private *dev_priv, user_ts = *timestamp; + /* + * If there is only one drawobj in the array and it is of + * type SYNCOBJ_TYPE, skip comparing user_ts as it can be 0 + */ + if (!(count == 1 && drawobj[0]->type == SYNCOBJ_TYPE) && + (drawctxt->base.flags & KGSL_CONTEXT_USER_GENERATED_TS)) { + /* + * User specified timestamps need to be greater than the last + * issued timestamp in the context + */ + if (timestamp_cmp(drawctxt->timestamp, user_ts) >= 0) { + spin_unlock(&drawctxt->lock); + return -ERANGE; + } + } + for (i = 0; i < count; i++) { switch (drawobj[i]->type) { diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c index f1552a35a5a5..19b2773e7595 100644 --- a/drivers/gpu/msm/kgsl.c +++ b/drivers/gpu/msm/kgsl.c @@ -3425,12 +3425,16 @@ long kgsl_ioctl_sparse_phys_alloc(struct kgsl_device_private *dev_priv, unsigned int cmd, void *data) { struct kgsl_process_private *process = dev_priv->process_priv; + struct kgsl_device *device = dev_priv->device; struct kgsl_sparse_phys_alloc *param = data; struct kgsl_mem_entry *entry; uint64_t flags; int ret; int id; + if (!(device->flags & KGSL_FLAG_SPARSE)) + return -ENOTSUPP; + ret = _sparse_alloc_param_sanity_check(param->size, param->pagesize); if (ret) return ret; @@ -3514,9 +3518,13 @@ long kgsl_ioctl_sparse_phys_free(struct kgsl_device_private *dev_priv, unsigned int cmd, void *data) { struct kgsl_process_private *process = dev_priv->process_priv; + struct kgsl_device *device = dev_priv->device; struct kgsl_sparse_phys_free *param = data; struct kgsl_mem_entry *entry; + if (!(device->flags & KGSL_FLAG_SPARSE)) + return -ENOTSUPP; + entry = kgsl_sharedmem_find_id_flags(process, param->id, KGSL_MEMFLAGS_SPARSE_PHYS); if (entry == NULL) @@ -3546,10 +3554,14 @@ long kgsl_ioctl_sparse_virt_alloc(struct kgsl_device_private *dev_priv, unsigned int cmd, void *data) { struct kgsl_process_private *private = dev_priv->process_priv; + struct kgsl_device *device = dev_priv->device; struct kgsl_sparse_virt_alloc *param = data; struct kgsl_mem_entry *entry; int ret; + if (!(device->flags & KGSL_FLAG_SPARSE)) + return -ENOTSUPP; + ret = _sparse_alloc_param_sanity_check(param->size, param->pagesize); if (ret) return ret; @@ -3590,9 +3602,13 @@ long kgsl_ioctl_sparse_virt_free(struct kgsl_device_private *dev_priv, unsigned int cmd, void *data) { struct kgsl_process_private *process = dev_priv->process_priv; + struct kgsl_device *device = dev_priv->device; struct kgsl_sparse_virt_free *param = data; struct kgsl_mem_entry *entry = NULL; + if (!(device->flags & KGSL_FLAG_SPARSE)) + return -ENOTSUPP; + entry = kgsl_sharedmem_find_id_flags(process, param->id, KGSL_MEMFLAGS_SPARSE_VIRT); if (entry == NULL) @@ -3939,6 +3955,7 @@ long kgsl_ioctl_sparse_bind(struct kgsl_device_private *dev_priv, unsigned int cmd, void *data) { struct kgsl_process_private *private = dev_priv->process_priv; + struct kgsl_device *device = dev_priv->device; struct kgsl_sparse_bind *param = data; struct kgsl_sparse_binding_object obj; struct kgsl_mem_entry *virt_entry; @@ -3947,6 +3964,9 @@ long kgsl_ioctl_sparse_bind(struct kgsl_device_private *dev_priv, int ret = 0; int i = 0; + if (!(device->flags & KGSL_FLAG_SPARSE)) + return -ENOTSUPP; + ptr = (void __user *) (uintptr_t) param->list; if (param->size > sizeof(struct kgsl_sparse_binding_object) || @@ -4002,6 +4022,9 @@ long kgsl_ioctl_gpu_sparse_command(struct kgsl_device_private *dev_priv, long result; unsigned int i = 0; + if (!(device->flags & KGSL_FLAG_SPARSE)) + return -ENOTSUPP; + /* Make sure sparse and syncpoint count isn't too big */ if (param->numsparse > KGSL_MAX_SPARSE || param->numsyncs > KGSL_MAX_SYNCPOINTS) @@ -4771,6 +4794,9 @@ int kgsl_device_platform_probe(struct kgsl_device *device) /* Initialize logging first, so that failures below actually print. */ kgsl_device_debugfs_init(device); + /* Disable the sparse ioctl invocation as they are not used */ + device->flags &= ~KGSL_FLAG_SPARSE; + status = kgsl_pwrctrl_init(device); if (status) goto error; diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h index b4903d6c9ef0..11e36e514a41 100644 --- a/drivers/gpu/msm/kgsl_device.h +++ b/drivers/gpu/msm/kgsl_device.h @@ -66,6 +66,7 @@ enum kgsl_event_results { }; #define KGSL_FLAG_WAKE_ON_TOUCH BIT(0) +#define KGSL_FLAG_SPARSE BIT(1) /* * "list" of event types for ftrace symbolic magic diff --git a/drivers/iommu/dma-mapping-fast.c b/drivers/iommu/dma-mapping-fast.c index 23c721b072dc..08deff94e783 100644 --- a/drivers/iommu/dma-mapping-fast.c +++ b/drivers/iommu/dma-mapping-fast.c @@ -174,7 +174,6 @@ static dma_addr_t __fast_smmu_alloc_iova(struct dma_fast_smmu_mapping *mapping, nbits, align); if (unlikely(bit > mapping->num_4k_pages)) { /* try wrapping */ - mapping->next_start = 0; /* TODO: SHOULD I REALLY DO THIS?!? */ bit = bitmap_find_next_zero_area( mapping->bitmap, mapping->num_4k_pages, 0, nbits, align); diff --git a/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_util.c b/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_util.c index a97a51965ae3..72dbd937b111 100644 --- a/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_util.c +++ b/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_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 @@ -714,3 +714,150 @@ void cam_cdm_util_dump_cmd_buf( } } while (buf_now <= cmd_buf_end); } + +static long cam_cdm_util_dump_reg_cont_cmd_v2( + uint32_t *cmd_buf_addr, + struct cam_cdm_cmd_buf_dump_info *dump_info) +{ + long ret = 0; + struct cdm_regcontinuous_cmd *p_regcont_cmd; + uint32_t *temp_ptr = cmd_buf_addr; + int i = 0; + struct cam_cdm_cmd_dump_header *hdr; + uint32_t *addr, *start; + uint8_t *dst; + uint32_t min_len, remain_len; + + p_regcont_cmd = (struct cdm_regcontinuous_cmd *)temp_ptr; + temp_ptr += CDMCmdHeaderSizes[CAM_CDM_CMD_REG_CONT]; + ret += CDMCmdHeaderSizes[CAM_CDM_CMD_REG_CONT]; + CAM_DBG(CAM_CDM, "REG_CONT: COUNT: %u OFFSET: 0x%X", + p_regcont_cmd->count, p_regcont_cmd->offset); + + min_len = (sizeof(uint32_t) * p_regcont_cmd->count) + + sizeof(struct cam_cdm_cmd_dump_header); + remain_len = dump_info->dst_max_size - dump_info->dst_offset; + if (remain_len < min_len) { + CAM_ERR_RATE_LIMIT(CAM_CDM, "Dump buffer exhaust %d %d", + remain_len, min_len); + return ret; + } + dst = (char *)dump_info->dst_start + dump_info->dst_offset; + hdr = (struct cam_cdm_cmd_dump_header *)dst; + snprintf(hdr->tag, CAM_CDM_CMD_TAG_MAX_LEN, "CDM_REG_CONT:"); + hdr->word_size = sizeof(uint32_t); + addr = (uint32_t *)(dst + sizeof(struct cam_cdm_cmd_dump_header)); + start = addr; + *addr++ = p_regcont_cmd->offset; + *addr++ = p_regcont_cmd->count; + for (i = 0; i < p_regcont_cmd->count; i++) { + *addr = *temp_ptr; + temp_ptr++; + addr++; + ret++; + } + hdr->size = hdr->word_size * (addr - start); + dump_info->dst_offset += hdr->size + + sizeof(struct cam_cdm_cmd_dump_header); + return ret; +} + +static long cam_cdm_util_dump_reg_random_cmd_v2( + uint32_t *cmd_buf_addr, + struct cam_cdm_cmd_buf_dump_info *dump_info) +{ + struct cdm_regrandom_cmd *p_regrand_cmd; + uint32_t *temp_ptr = cmd_buf_addr; + long ret = 0; + int i = 0; + uint32_t *addr, *start; + struct cam_cdm_cmd_dump_header *hdr; + uint8_t *dst; + uint32_t min_len, remain_len; + + p_regrand_cmd = (struct cdm_regrandom_cmd *)temp_ptr; + temp_ptr += CDMCmdHeaderSizes[CAM_CDM_CMD_REG_RANDOM]; + ret += CDMCmdHeaderSizes[CAM_CDM_CMD_REG_RANDOM]; + + min_len = (2 * sizeof(uint32_t) * p_regrand_cmd->count) + + sizeof(struct cam_cdm_cmd_dump_header); + remain_len = dump_info->dst_max_size - dump_info->dst_offset; + if (remain_len < min_len) { + CAM_ERR_RATE_LIMIT(CAM_CDM, "Dump buffer exhaust %d %d", + remain_len, min_len); + return ret; + } + dst = (char *)dump_info->dst_start + dump_info->dst_offset; + hdr = (struct cam_cdm_cmd_dump_header *)dst; + snprintf(hdr->tag, CAM_CDM_CMD_TAG_MAX_LEN, "CDM_REG_RANDOM:"); + hdr->word_size = sizeof(uint32_t); + addr = (uint32_t *)(dst + sizeof(struct cam_cdm_cmd_dump_header)); + start = addr; + *addr++ = p_regrand_cmd->count; + for (i = 0; i < p_regrand_cmd->count; i++) { + addr[0] = temp_ptr[0] & CAM_CDM_REG_OFFSET_MASK; + addr[1] = temp_ptr[1]; + temp_ptr += 2; + addr += 2; + ret += 2; + } + hdr->size = hdr->word_size * (addr - start); + dump_info->dst_offset += hdr->size + + sizeof(struct cam_cdm_cmd_dump_header); + return ret; +} + +void cam_cdm_util_dump_cmd_bufs_v2( + struct cam_cdm_cmd_buf_dump_info *dump_info) +{ + uint32_t cmd = 0; + uint32_t *buf_now; + + if (!dump_info || !dump_info->src_start || !dump_info->src_end || + !dump_info->dst_start) { + CAM_INFO(CAM_CDM, "Invalid args"); + return; + } + buf_now = dump_info->src_start; + do { + cmd = *dump_info->src_start; + cmd = cmd >> CAM_CDM_COMMAND_OFFSET; + + switch (cmd) { + case CAM_CDM_CMD_DMI: + case CAM_CDM_CMD_DMI_32: + case CAM_CDM_CMD_DMI_64: + buf_now += CDMCmdHeaderSizes[CAM_CDM_CMD_DMI]; + break; + case CAM_CDM_CMD_REG_CONT: + buf_now += cam_cdm_util_dump_reg_cont_cmd_v2(buf_now, + dump_info); + break; + case CAM_CDM_CMD_REG_RANDOM: + buf_now += cam_cdm_util_dump_reg_random_cmd_v2(buf_now, + dump_info); + break; + case CAM_CDM_CMD_BUFF_INDIRECT: + buf_now += CDMCmdHeaderSizes[CAM_CDM_CMD_BUFF_INDIRECT]; + break; + case CAM_CDM_CMD_GEN_IRQ: + buf_now += CDMCmdHeaderSizes[CAM_CDM_CMD_GEN_IRQ]; + break; + case CAM_CDM_CMD_WAIT_EVENT: + buf_now += CDMCmdHeaderSizes[CAM_CDM_CMD_WAIT_EVENT]; + break; + case CAM_CDM_CMD_CHANGE_BASE: + buf_now += CDMCmdHeaderSizes[CAM_CDM_CMD_CHANGE_BASE]; + break; + case CAM_CDM_CMD_PERF_CTRL: + buf_now += CDMCmdHeaderSizes[CAM_CDM_CMD_PERF_CTRL]; + break; + default: + CAM_INFO(CAM_CDM, "Invalid CMD: 0x%x buf 0x%x", + cmd, *buf_now); + buf_now++; + break; + } + } while (buf_now <= dump_info->src_end); + +} diff --git a/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_util.h b/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_util.h index 8f2b48853ca8..d8dc31cc572d 100644 --- a/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_util.h +++ b/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_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 @@ -13,6 +13,9 @@ #ifndef _CAM_CDM_UTIL_H_ #define _CAM_CDM_UTIL_H_ +/* Max len for tag name for header while dumping cmd buffer*/ +#define CAM_CDM_CMD_TAG_MAX_LEN 32 + enum cam_cdm_command { CAM_CDM_CMD_UNUSED = 0x0, CAM_CDM_CMD_DMI = 0x1, @@ -152,6 +155,34 @@ void (*cdm_write_genirq)( }; /** + * struct cam_cdm_cmd_buf_dump_info; - Camera CDM dump info + * @src_start: source start address + * @src_end: source end address + * @dst_start: dst start address + * @dst_offset: dst offset + * @dst_max_size max size of destination buffer + */ +struct cam_cdm_cmd_buf_dump_info { + uint32_t *src_start; + uint32_t *src_end; + uintptr_t dst_start; + uint32_t dst_offset; + uint32_t dst_max_size; +}; + +/** + * struct cam_cdm_cmd_dump_header- Camera CDM dump header + * @tag: tag name for header + * @size: size of data + * @word_size: size of each word + */ +struct cam_cdm_cmd_dump_header { + char tag[CAM_CDM_CMD_TAG_MAX_LEN]; + uint64_t size; + uint32_t word_size; +}; + +/** * cam_cdm_util_log_cmd_bufs() * * @brief: Util function to log cdm command buffers @@ -163,6 +194,17 @@ void (*cdm_write_genirq)( void cam_cdm_util_dump_cmd_buf( uint32_t *cmd_buffer_start, uint32_t *cmd_buffer_end); +/** + * cam_cdm_util_dump_cmd_bufs_v2() + * + * @brief: Util function to log cdm command buffers + * to a buffer + * + * @dump_info: Information about source and destination buffers + * + */ +void cam_cdm_util_dump_cmd_bufs_v2( + struct cam_cdm_cmd_buf_dump_info *dump_info); #endif /* _CAM_CDM_UTIL_H_ */ diff --git a/drivers/media/platform/msm/camera/cam_core/cam_context.h b/drivers/media/platform/msm/camera/cam_core/cam_context.h index 84a190a4c5a6..a3577f09dd78 100644 --- a/drivers/media/platform/msm/camera/cam_core/cam_context.h +++ b/drivers/media/platform/msm/camera/cam_core/cam_context.h @@ -25,6 +25,9 @@ struct cam_context; /* max device name string length*/ #define CAM_CTX_DEV_NAME_MAX_LENGTH 20 +/* max tag dump header string length*/ +#define CAM_CONTEXT_DUMP_TAG_MAX_LEN 32 + /* max request number */ #define CAM_CTX_REQ_MAX 20 #define CAM_CTX_CFG_MAX 20 @@ -230,6 +233,19 @@ struct cam_context { }; /** + * struct cam_context_dump_header - Function for context dump header + * + * @tag : Tag for context dump header + * @size : Size of data + * @word_size : Word size of data + */ +struct cam_context_dump_header { + char tag[CAM_CONTEXT_DUMP_TAG_MAX_LEN]; + uint64_t size; + uint32_t word_size; +}; + +/** * cam_context_shutdown() * * @brief: Calls while device close or shutdown diff --git a/drivers/media/platform/msm/camera/cam_core/cam_context_utils.c b/drivers/media/platform/msm/camera/cam_core/cam_context_utils.c index 1705b536bc37..211146d36ea0 100644 --- a/drivers/media/platform/msm/camera/cam_core/cam_context_utils.c +++ b/drivers/media/platform/msm/camera/cam_core/cam_context_utils.c @@ -1045,6 +1045,72 @@ end: return rc; } +static int cam_context_dump_context(struct cam_context *ctx, + struct cam_hw_dump_args *dump_args) +{ + int rc = 0; + struct cam_context_dump_header *hdr; + char *dst; + uint64_t *addr, *start; + uintptr_t cpu_addr; + size_t buf_len; + uint32_t min_len, remain_len; + struct cam_ctx_request *req; + int i; + + if (list_empty(&ctx->active_req_list)) { + CAM_ERR(CAM_CTXT, "[%s][%d] no active request", + ctx->dev_name, ctx->ctx_id); + return -EIO; + } + rc = cam_mem_get_cpu_buf(dump_args->buf_handle, + &cpu_addr, &buf_len); + if (!cpu_addr || !buf_len || rc) { + CAM_ERR(CAM_CTXT, + "lnvalid addr %u len %zu rc %d", + dump_args->buf_handle, buf_len, rc); + return rc; + } + remain_len = buf_len - dump_args->offset; + min_len = 2 * (sizeof(struct cam_context_dump_header) + + CAM_CONTEXT_DUMP_TAG_MAX_LEN); + if (remain_len < min_len) { + CAM_ERR(CAM_CTXT, "dump buffer exhaust %d %d", + remain_len, min_len); + goto end; + } + dst = (char *)cpu_addr + dump_args->offset; + hdr = (struct cam_context_dump_header *)dst; + snprintf(hdr->tag, CAM_CONTEXT_DUMP_TAG_MAX_LEN, + "%s_CTXT_DUMP:", ctx->dev_name); + hdr->word_size = sizeof(uint64_t); + addr = (uint64_t *)(dst + sizeof(struct cam_context_dump_header)); + start = addr; + req = list_first_entry(&ctx->active_req_list, + struct cam_ctx_request, list); + *addr++ = ctx->ctx_id; + *addr++ = refcount_read(&(ctx->refcount.refcount)); + *addr++ = ctx->last_flush_req; + *addr++ = ctx->state; + *addr++ = req->num_out_map_entries; + for (i = 0; i < req->num_out_map_entries; i++) + if (req->out_map_entries[i].sync_id != -1) + *addr++ = req->out_map_entries[i].sync_id; + for (i = 0; i < req->num_in_map_entries; i++) + if (req->in_map_entries[i].sync_id != -1) + *addr++ = req->in_map_entries[i].sync_id; + *addr++ = req->num_in_map_entries; + hdr->size = hdr->word_size * (addr - start); + dump_args->offset += hdr->size + + sizeof(struct cam_context_dump_header); +end: + rc = cam_mem_put_cpu_buf(dump_args->buf_handle); + if (rc) + CAM_ERR(CAM_CTXT, "Cpu put failed handle %u", + dump_args->buf_handle); + return rc; +} + int32_t cam_context_dump_dev_to_hw(struct cam_context *ctx, struct cam_dump_req_cmd *cmd) { @@ -1074,11 +1140,14 @@ int32_t cam_context_dump_dev_to_hw(struct cam_context *ctx, ctx->dev_name, ctx->ctx_id, dump_args.buf_handle); return rc; } - CAM_INFO(CAM_CTXT, "[%s] ctx: %d Filled Length %d", - ctx->dev_name, ctx->ctx_id, - dump_args.offset - cmd->offset); - /* Drivers update offest upto which the buffer is written*/ - cmd->offset = dump_args.offset; + if (dump_args.offset != cmd->offset) { + cam_context_dump_context(ctx, &dump_args); + CAM_INFO(CAM_CTXT, "[%s] ctx: %d Filled Length %d", + ctx->dev_name, ctx->ctx_id, + dump_args.offset - cmd->offset); + /* Drivers update the offest */ + cmd->offset = dump_args.offset; + } } else { CAM_INFO(CAM_CTXT, "%s hw dump not registered", ctx->dev_name); } diff --git a/drivers/media/platform/msm/camera/cam_fd/cam_fd_context.c b/drivers/media/platform/msm/camera/cam_fd/cam_fd_context.c index 70ff72c39028..9e14e40127c0 100644 --- a/drivers/media/platform/msm/camera/cam_fd/cam_fd_context.c +++ b/drivers/media/platform/msm/camera/cam_fd/cam_fd_context.c @@ -124,6 +124,18 @@ static int __cam_fd_ctx_release_dev_in_activated(struct cam_context *ctx, return rc; } +static int __cam_fd_ctx_dump_dev_in_activated(struct cam_context *ctx, + struct cam_dump_req_cmd *cmd) +{ + int rc; + + rc = cam_context_dump_dev_to_hw(ctx, cmd); + if (rc) + CAM_ERR(CAM_FD, "Failed to dump device, rc=%d", rc); + + return rc; +} + static int __cam_fd_ctx_flush_dev_in_activated(struct cam_context *ctx, struct cam_flush_dev_cmd *cmd) { @@ -203,6 +215,7 @@ static struct cam_ctx_ops .release_dev = __cam_fd_ctx_release_dev_in_activated, .config_dev = __cam_fd_ctx_config_dev_in_activated, .flush_dev = __cam_fd_ctx_flush_dev_in_activated, + .dump_dev = __cam_fd_ctx_dump_dev_in_activated, }, .crm_ops = {}, .irq_ops = __cam_fd_ctx_handle_irq_in_activated, diff --git a/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c index b2838b4a902f..91a1b141e659 100644 --- a/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c +++ b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c @@ -910,6 +910,7 @@ static int cam_fd_mgr_util_submit_frame(void *priv, void *data) hw_device->req_id = frame_req->request_id; mutex_unlock(&hw_device->lock); + cam_common_util_get_curr_timestamp(&frame_req->submit_timestamp); rc = cam_fd_mgr_util_put_frame_req( &hw_mgr->frame_processing_list, &frame_req); if (rc) { @@ -1530,6 +1531,110 @@ static int cam_fd_mgr_hw_flush(void *hw_mgr_priv, return rc; } +static int cam_fd_mgr_hw_dump(void *hw_mgr_priv, + void *hw_dump_args) +{ + struct cam_fd_hw_mgr *hw_mgr = (struct cam_fd_hw_mgr *)hw_mgr_priv; + struct cam_hw_dump_args *dump_args = hw_dump_args; + struct cam_fd_mgr_frame_request *frame_req, *req_temp; + uint64_t diff; + struct timeval cur_time; + int rc = 0; + struct cam_fd_hw_mgr_ctx *hw_ctx = + (struct cam_fd_hw_mgr_ctx *)dump_args->ctxt_to_hw_map; + struct cam_fd_device *hw_device; + char *dst; + struct cam_fd_hw_dump_args fd_dump_args; + struct cam_fd_hw_dump_header *hdr; + uint64_t *addr, *start; + uint32_t min_len, remain_len; + + rc = cam_fd_mgr_util_get_device(hw_mgr, hw_ctx, &hw_device); + if (rc) { + CAM_ERR(CAM_FD, "Error in getting device %d", rc); + return rc; + } + list_for_each_entry_safe(frame_req, req_temp, + &hw_mgr->frame_processing_list, list) { + if (frame_req->request_id == dump_args->request_id) + goto hw_dump; + } + return rc; +hw_dump: + cam_common_util_get_curr_timestamp(&cur_time); + diff = cam_common_util_get_time_diff(&cur_time, + &frame_req->submit_timestamp); + if (diff < CAM_FD_RESPONSE_TIME_THRESHOLD) { + CAM_INFO(CAM_FD, "No Error req %lld %ld:%06ld %ld:%06ld", + dump_args->request_id, + frame_req->submit_timestamp.tv_sec, + frame_req->submit_timestamp.tv_usec, + cur_time.tv_sec, + cur_time.tv_usec); + return 0; + } + CAM_INFO(CAM_FD, "Error req %lld %ld:%06ld %ld:%06ld", + dump_args->request_id, + frame_req->submit_timestamp.tv_sec, + frame_req->submit_timestamp.tv_usec, + cur_time.tv_sec, + cur_time.tv_usec); + rc = cam_mem_get_cpu_buf(dump_args->buf_handle, + &fd_dump_args.cpu_addr, &fd_dump_args.buf_len); + if (!fd_dump_args.cpu_addr || !fd_dump_args.buf_len || rc) { + CAM_ERR(CAM_FD, + "lnvalid addr %u len %zu rc %d", + dump_args->buf_handle, fd_dump_args.buf_len, rc); + return rc; + } + remain_len = fd_dump_args.buf_len - dump_args->offset; + min_len = 2 * (sizeof(struct cam_fd_hw_dump_header) + + CAM_FD_HW_DUMP_TAG_MAX_LEN); + if (remain_len < min_len) { + CAM_ERR(CAM_FD, "dump buffer exhaust %d %d", + remain_len, min_len); + goto end; + } + dst = (char *)fd_dump_args.cpu_addr + dump_args->offset; + hdr = (struct cam_fd_hw_dump_header *)dst; + snprintf(hdr->tag, CAM_FD_HW_DUMP_TAG_MAX_LEN, + "FD_REQ:"); + hdr->word_size = sizeof(uint64_t); + addr = (uint64_t *)(dst + sizeof(struct cam_fd_hw_dump_header)); + start = addr; + *addr++ = frame_req->request_id; + *addr++ = frame_req->submit_timestamp.tv_sec; + *addr++ = frame_req->submit_timestamp.tv_usec; + *addr++ = cur_time.tv_sec; + *addr++ = cur_time.tv_usec; + hdr->size = hdr->word_size * (addr - start); + dump_args->offset += hdr->size + + sizeof(struct cam_fd_hw_dump_header); + + fd_dump_args.request_id = dump_args->request_id; + fd_dump_args.offset = dump_args->offset; + if (hw_device->hw_intf->hw_ops.process_cmd) { + rc = hw_device->hw_intf->hw_ops.process_cmd( + hw_device->hw_intf->hw_priv, + CAM_FD_HW_CMD_HW_DUMP, + &fd_dump_args, + sizeof(struct + cam_fd_hw_dump_args)); + if (rc) { + CAM_ERR(CAM_FD, "Hw Dump cmd fails req %lld rc %d", + frame_req->request_id, rc); + goto end; + } + } + dump_args->offset = fd_dump_args.offset; +end: + rc = cam_mem_put_cpu_buf(dump_args->buf_handle); + if (rc) + CAM_ERR(CAM_FD, "Cpu put failed handle %u", + dump_args->buf_handle); + return rc; +} + static int cam_fd_mgr_hw_stop(void *hw_mgr_priv, void *mgr_stop_args) { struct cam_fd_hw_mgr *hw_mgr = (struct cam_fd_hw_mgr *)hw_mgr_priv; @@ -1977,6 +2082,7 @@ int cam_fd_hw_mgr_init(struct device_node *of_node, hw_mgr_intf->hw_write = NULL; hw_mgr_intf->hw_close = NULL; hw_mgr_intf->hw_flush = cam_fd_mgr_hw_flush; + hw_mgr_intf->hw_dump = cam_fd_mgr_hw_dump; return rc; diff --git a/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.h b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.h index a903ab091c73..87464a37372c 100644 --- a/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.h +++ b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/cam_fd_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 @@ -27,6 +27,11 @@ #define CAM_FD_HW_MAX 1 #define CAM_FD_WORKQ_NUM_TASK 10 +/* + * Response time threshold in ms beyond which a request is not expected to be + * with FD hw + */ +#define CAM_FD_RESPONSE_TIME_THRESHOLD 100000 struct cam_fd_hw_mgr; @@ -107,6 +112,7 @@ struct cam_fd_device { * @hw_update_entries : HW update entries corresponding to this request * which needs to be submitted to HW through CDM * @num_hw_update_entries : Number of HW update entries + * @submit_timestamp : Time stamp for submit req with hw */ struct cam_fd_mgr_frame_request { struct list_head list; @@ -115,6 +121,7 @@ struct cam_fd_mgr_frame_request { struct cam_fd_hw_req_private hw_req_private; struct cam_hw_update_entry hw_update_entries[CAM_FD_MAX_HW_ENTRIES]; uint32_t num_hw_update_entries; + struct timeval submit_timestamp; }; /** diff --git a/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c index 8be20a772129..20378cad81a6 100644 --- a/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c +++ b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_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 @@ -523,6 +523,59 @@ static int cam_fd_hw_util_processcmd_frame_done(struct cam_hw_info *fd_hw, return 0; } +static int cam_fd_hw_util_processcmd_hw_dump(struct cam_hw_info *fd_hw, + void *args) +{ + struct cam_fd_hw_dump_args *dump_args; + struct cam_hw_soc_info *soc_info; + int i, j; + char *dst; + uint32_t *addr, *start; + struct cam_fd_hw_dump_header *hdr; + uint32_t num_reg, min_len, remain_len; + + mutex_lock(&fd_hw->hw_mutex); + if (fd_hw->hw_state == CAM_HW_STATE_POWER_DOWN) { + CAM_INFO(CAM_FD, "power off state"); + mutex_unlock(&fd_hw->hw_mutex); + return 0; + } + mutex_unlock(&fd_hw->hw_mutex); + + dump_args = (struct cam_fd_hw_dump_args *)args; + soc_info = &fd_hw->soc_info; + remain_len = dump_args->buf_len - dump_args->offset; + min_len = 2 * (sizeof(struct cam_fd_hw_dump_header) + + CAM_FD_HW_DUMP_TAG_MAX_LEN) + + soc_info->reg_map[0].size; + if (remain_len < min_len) { + CAM_ERR(CAM_FD, "dump buffer exhaust %d %d", + remain_len, min_len); + return 0; + } + dst = (char *)dump_args->cpu_addr + dump_args->offset; + hdr = (struct cam_fd_hw_dump_header *)dst; + snprintf(hdr->tag, CAM_FD_HW_DUMP_TAG_MAX_LEN, + "FD_REG:"); + hdr->word_size = sizeof(uint32_t); + addr = (uint32_t *)(dst + sizeof(struct cam_fd_hw_dump_header)); + start = addr; + *addr++ = soc_info->index; + num_reg = soc_info->reg_map[0].size/4; + for (j = 0; j < soc_info->num_reg_map; j++) { + for (i = 0; i < num_reg; i++) { + *addr++ = soc_info->mem_block[0]->start + i*4; + *addr++ = cam_io_r(soc_info->reg_map[i].mem_base + + (i*4)); + } + } + hdr->size = hdr->word_size * (addr - start); + dump_args->offset += hdr->size + + sizeof(struct cam_fd_hw_dump_header); + CAM_DBG(CAM_FD, "%d", dump_args->offset); + return 0; +} + irqreturn_t cam_fd_hw_irq(int irq_num, void *data) { struct cam_hw_info *fd_hw = (struct cam_hw_info *)data; @@ -1163,6 +1216,11 @@ int cam_fd_hw_process_cmd(void *hw_priv, uint32_t cmd_type, cmd_frame_results); break; } + case CAM_FD_HW_CMD_HW_DUMP: { + rc = cam_fd_hw_util_processcmd_hw_dump(fd_hw, + cmd_args); + break; + } default: break; } diff --git a/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_intf.h b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_intf.h index ef3b6c9314e2..8799a716a733 100644 --- a/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_intf.h +++ b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_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 @@ -31,6 +31,7 @@ #define CAM_FD_MAX_IO_BUFFERS 5 #define CAM_FD_MAX_HW_ENTRIES 5 +#define CAM_FD_HW_DUMP_TAG_MAX_LEN 32 /** * enum cam_fd_hw_type - Enum for FD HW type @@ -87,6 +88,7 @@ enum cam_fd_hw_irq_type { * @CAM_FD_HW_CMD_FRAME_DONE : Command to process frame done settings * @CAM_FD_HW_CMD_UPDATE_SOC : Command to process soc update * @CAM_FD_HW_CMD_REGISTER_CALLBACK : Command to set hw mgr callback + * @CAM_FD_HW_CMD_HW_DUMP : Command to dump fd hw information * @CAM_FD_HW_CMD_MAX : Indicates max cmd */ enum cam_fd_hw_cmd_type { @@ -94,6 +96,7 @@ enum cam_fd_hw_cmd_type { CAM_FD_HW_CMD_FRAME_DONE, CAM_FD_HW_CMD_UPDATE_SOC, CAM_FD_HW_CMD_REGISTER_CALLBACK, + CAM_FD_HW_CMD_HW_DUMP, CAM_FD_HW_CMD_MAX, }; @@ -286,4 +289,32 @@ struct cam_fd_hw_cmd_set_irq_cb { void *data; }; +/** + * struct cam_fd_hw_dump_args : Args for dump request + * + * @cpu_addr : start address of the target buffer + * @offset : offset of the buffer + * @request_id : Issue request id + * @buf_len : Length of target buffer + */ +struct cam_fd_hw_dump_args { + uintptr_t cpu_addr; + uint64_t offset; + uint64_t request_id; + size_t buf_len; +}; + +/** + * struct cam_fd_hw_dump_header : fd hw dump header + * + * @tag : fd hw dump header tag + * @size : Size of data + * @word_size : size of each word + */ +struct cam_fd_hw_dump_header { + char tag[CAM_FD_HW_DUMP_TAG_MAX_LEN]; + uint64_t size; + uint32_t word_size; +}; + #endif /* _CAM_FD_HW_INTF_H_ */ diff --git a/drivers/media/platform/msm/camera/cam_icp/cam_icp_context.c b/drivers/media/platform/msm/camera/cam_icp/cam_icp_context.c index 41d175188d85..f98ad43acbd6 100644 --- a/drivers/media/platform/msm/camera/cam_icp/cam_icp_context.c +++ b/drivers/media/platform/msm/camera/cam_icp/cam_icp_context.c @@ -118,6 +118,18 @@ static int __cam_icp_start_dev_in_acquired(struct cam_context *ctx, return rc; } +static int __cam_icp_dump_dev_in_ready(struct cam_context *ctx, + struct cam_dump_req_cmd *cmd) +{ + int rc; + + rc = cam_context_dump_dev_to_hw(ctx, cmd); + if (rc) + CAM_ERR(CAM_ICP, "Failed to dump device"); + + return rc; +} + static int __cam_icp_flush_dev_in_ready(struct cam_context *ctx, struct cam_flush_dev_cmd *cmd) { @@ -229,6 +241,7 @@ static struct cam_ctx_ops .start_dev = __cam_icp_start_dev_in_acquired, .config_dev = __cam_icp_config_dev_in_ready, .flush_dev = __cam_icp_flush_dev_in_ready, + .dump_dev = __cam_icp_dump_dev_in_ready, }, .crm_ops = {}, .irq_ops = __cam_icp_handle_buf_done_in_ready, @@ -241,6 +254,7 @@ static struct cam_ctx_ops .release_dev = __cam_icp_release_dev_in_ready, .config_dev = __cam_icp_config_dev_in_ready, .flush_dev = __cam_icp_flush_dev_in_ready, + .dump_dev = __cam_icp_dump_dev_in_ready, }, .crm_ops = {}, .irq_ops = __cam_icp_handle_buf_done_in_ready, diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/a5_hw/a5_core.c b/drivers/media/platform/msm/camera/cam_icp/icp_hw/a5_hw/a5_core.c index 4dbc8f1bd991..41d128a074c7 100644 --- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/a5_hw/a5_core.c +++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/a5_hw/a5_core.c @@ -242,6 +242,43 @@ fw_download_failed: return rc; } +static int cam_a5_fw_dump(struct cam_icp_hw_dump_args *dump_args, + struct cam_a5_device_core_info *core_info) +{ + u8 *dest; + u8 *src; + uint64_t size_required = 0; + struct cam_icp_dump_header *hdr; + + if (!core_info || !dump_args) { + CAM_ERR(CAM_ICP, "invalid params %pK %pK", + core_info, dump_args); + return -EINVAL; + } + if (!core_info->fw_kva_addr || !dump_args->cpu_addr) { + CAM_ERR(CAM_ICP, "invalid params %pK, 0x%zx", + core_info->fw_kva_addr, dump_args->cpu_addr); + return -EINVAL; + } + size_required = core_info->fw_buf_len + + sizeof(struct cam_icp_dump_header); + if ((dump_args->buf_len - dump_args->offset) < size_required) { + CAM_WARN(CAM_ICP, "Dump buffer exhaust %lld %lld", + size_required, core_info->fw_buf_len); + return 0; + } + dest = (u8 *)dump_args->cpu_addr + dump_args->offset; + hdr = (struct cam_icp_dump_header *)dest; + snprintf(hdr->tag, CAM_ICP_DUMP_TAG_MAX_LEN, "ICP_FW:"); + hdr->word_size = sizeof(u8); + hdr->size = core_info->fw_buf_len; + src = (u8 *)core_info->fw_kva_addr; + dest = (u8 *)dest + sizeof(struct cam_icp_dump_header); + memcpy_fromio(dest, src, core_info->fw_buf_len); + dump_args->offset += hdr->size + sizeof(struct cam_icp_dump_header); + return 0; +} + int cam_a5_init_hw(void *device_priv, void *init_hw_args, uint32_t arg_size) { @@ -480,6 +517,12 @@ int cam_a5_process_cmd(void *device_priv, uint32_t cmd_type, } rc = hfi_cmd_ubwc_config(a5_soc->ubwc_cfg); break; + case CAM_ICP_A5_CMD_HW_DUMP: { + struct cam_icp_hw_dump_args *dump_args = cmd_args; + + rc = cam_a5_fw_dump(dump_args, core_info); + break; + } default: break; } diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c index 370768a0609d..5a6bc0b644ca 100644 --- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c +++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c @@ -3405,7 +3405,8 @@ static int cam_icp_mgr_config_hw(void *hw_mgr_priv, void *config_hw_args) idx = cam_icp_clk_idx_from_req_id(ctx_data, req_id); cam_icp_mgr_ipe_bps_clk_update(hw_mgr, ctx_data, idx); ctx_data->hfi_frame_process.fw_process_flag[idx] = true; - + cam_common_util_get_curr_timestamp( + &ctx_data->hfi_frame_process.submit_timestamp[idx]); CAM_DBG(CAM_ICP, "req_id %llu, io config %llu", req_id, frame_info->io_config); @@ -4435,6 +4436,99 @@ static int cam_icp_mgr_flush_req(struct cam_icp_hw_ctx_data *ctx_data, return 0; } +static int cam_icp_mgr_hw_dump(void *hw_priv, void *hw_dump_args) +{ + struct cam_hw_dump_args *dump_args = hw_dump_args; + struct cam_icp_hw_mgr *hw_mgr = hw_priv; + struct cam_hw_intf *a5_dev_intf = NULL; + struct cam_icp_hw_dump_args icp_dump_args; + int rc = 0; + struct cam_icp_hw_ctx_data *ctx_data; + struct hfi_frame_process_info *frm_process; + struct timeval cur_time; + uint64_t diff; + int i; + struct cam_icp_dump_header *hdr; + uint64_t *addr, *start; + uint8_t *dst; + uint32_t min_len, remain_len; + + if ((!hw_priv) || (!hw_dump_args)) { + CAM_ERR(CAM_ICP, "Input params are Null:"); + return -EINVAL; + } + ctx_data = dump_args->ctxt_to_hw_map; + CAM_DBG(CAM_ICP, "Req %lld", dump_args->request_id); + frm_process = &ctx_data->hfi_frame_process; + for (i = 0; i < CAM_FRAME_CMD_MAX; i++) { + if ((frm_process->request_id[i] == + dump_args->request_id) && + frm_process->fw_process_flag[i]) + goto hw_dump; + } + return 0; +hw_dump: + cam_common_util_get_curr_timestamp(&cur_time); + diff = cam_common_util_get_time_diff( + &cur_time, + &frm_process->submit_timestamp[i]); + if (diff < CAM_ICP_CTX_RESPONSE_TIME_THRESHOLD) { + CAM_INFO(CAM_ICP, "No Error req %lld %ld:%06ld %ld:%06ld", + dump_args->request_id, + frm_process->submit_timestamp[i].tv_sec, + frm_process->submit_timestamp[i].tv_usec, + cur_time.tv_sec, + cur_time.tv_usec); + return 0; + } + CAM_INFO(CAM_ICP, "Error req %lld %ld:%06ld %ld:%06ld", + dump_args->request_id, + frm_process->submit_timestamp[i].tv_sec, + frm_process->submit_timestamp[i].tv_usec, + cur_time.tv_sec, + cur_time.tv_usec); + rc = cam_mem_get_cpu_buf(dump_args->buf_handle, + &icp_dump_args.cpu_addr, &icp_dump_args.buf_len); + if (!icp_dump_args.cpu_addr || !icp_dump_args.buf_len || rc) { + CAM_ERR(CAM_ICP, + "lnvalid addr %u len %zu rc %d", + dump_args->buf_handle, icp_dump_args.buf_len, rc); + return rc; + } + remain_len = icp_dump_args.buf_len - dump_args->offset; + min_len = 2 * (sizeof(struct cam_icp_dump_header) + + CAM_ICP_DUMP_TAG_MAX_LEN); + if (remain_len < min_len) { + CAM_ERR(CAM_ICP, "dump buffer exhaust %d %d", + remain_len, min_len); + goto end; + } + dst = (char *)icp_dump_args.cpu_addr + dump_args->offset; + hdr = (struct cam_icp_dump_header *)dst; + snprintf(hdr->tag, CAM_ICP_DUMP_TAG_MAX_LEN, "ICP_REQ:"); + hdr->word_size = sizeof(uint64_t); + addr = (uint64_t *)(dst + sizeof(struct cam_icp_dump_header)); + start = addr; + *addr++ = frm_process->request_id[i]; + *addr++ = frm_process->submit_timestamp[i].tv_sec; + *addr++ = frm_process->submit_timestamp[i].tv_usec; + *addr++ = cur_time.tv_sec; + *addr++ = cur_time.tv_usec; + hdr->size = hdr->word_size * (addr - start); + dump_args->offset += (hdr->size + sizeof(struct cam_icp_dump_header)); + /* Dumping the fw image*/ + icp_dump_args.offset = dump_args->offset; + a5_dev_intf = hw_mgr->a5_dev_intf; + rc = a5_dev_intf->hw_ops.process_cmd( + a5_dev_intf->hw_priv, + CAM_ICP_A5_CMD_HW_DUMP, &icp_dump_args, + sizeof(struct cam_icp_hw_dump_args)); + dump_args->offset = icp_dump_args.offset; +end: + rc = cam_mem_put_cpu_buf(dump_args->buf_handle); + return rc; +} + static int cam_icp_mgr_hw_flush(void *hw_priv, void *hw_flush_args) { struct cam_hw_flush_args *flush_args = hw_flush_args; @@ -5353,6 +5447,7 @@ int cam_icp_hw_mgr_init(struct device_node *of_node, uint64_t *hw_mgr_hdl, hw_mgr_intf->hw_close = cam_icp_mgr_hw_close_u; hw_mgr_intf->hw_flush = cam_icp_mgr_hw_flush; hw_mgr_intf->hw_cmd = cam_icp_mgr_cmd; + hw_mgr_intf->hw_dump = cam_icp_mgr_hw_dump; icp_hw_mgr.secure_mode = CAM_SECURE_MODE_NON_SECURE; mutex_init(&icp_hw_mgr.hw_mgr_mutex); diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h index 731d2355882f..d5eb96f805c6 100644 --- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h +++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h @@ -70,6 +70,12 @@ #define CAM_ICP_CTX_MAX_CMD_BUFFERS 0x2 +/* + * Response time threshold in ms beyond which a request is not expected + * to be with ICP hw + */ +#define CAM_ICP_CTX_RESPONSE_TIME_THRESHOLD 300000 + /** * struct icp_hfi_mem_info * @qtbl: Memory info of queue table @@ -155,6 +161,7 @@ struct icp_frame_info { * @fw_process_flag: Frame process flag * @clk_info: Clock information for a request * @frame_info: information needed to process request + * @submit_timestamp: Submit timestamp to hw */ struct hfi_frame_process_info { struct hfi_cmd_ipebps_async hfi_frame_cmd[CAM_FRAME_CMD_MAX]; @@ -169,6 +176,7 @@ struct hfi_frame_process_info { uint32_t fw_process_flag[CAM_FRAME_CMD_MAX]; struct cam_icp_clk_bw_request clk_info[CAM_FRAME_CMD_MAX]; struct icp_frame_info frame_info[CAM_FRAME_CMD_MAX]; + struct timeval submit_timestamp[CAM_FRAME_CMD_MAX]; }; /** diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/include/cam_a5_hw_intf.h b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/include/cam_a5_hw_intf.h index 17a79d8d3f30..c892a71f1f1b 100644 --- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/include/cam_a5_hw_intf.h +++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/include/cam_a5_hw_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 @@ -33,6 +33,7 @@ enum cam_icp_a5_cmd_type { CAM_ICP_A5_CMD_CPAS_STOP, CAM_ICP_A5_CMD_UBWC_CFG, CAM_ICP_A5_CMD_PC_PREP, + CAM_ICP_A5_CMD_HW_DUMP, CAM_ICP_A5_CMD_MAX, }; diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/include/cam_icp_hw_mgr_intf.h b/drivers/media/platform/msm/camera/cam_icp/icp_hw/include/cam_icp_hw_mgr_intf.h index 2ebe41417d1d..f4e04ffeea4c 100644 --- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/include/cam_icp_hw_mgr_intf.h +++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/include/cam_icp_hw_mgr_intf.h @@ -27,6 +27,8 @@ #define CPAS_IPE1_BIT 0x2000 +#define CAM_ICP_DUMP_TAG_MAX_LEN 32 + int cam_icp_hw_mgr_init(struct device_node *of_node, uint64_t *hw_mgr_hdl, int *iommu_hdl); @@ -44,4 +46,28 @@ struct cam_icp_cpas_vote { uint32_t axi_vote_valid; }; +/** + * struct cam_icp_hw_dump_args + * @cpu_addr: kernel vaddr + * @buf_len: buffer length + * @offset: offset + */ +struct cam_icp_hw_dump_args { + uintptr_t cpu_addr; + size_t buf_len; + int32_t offset; +}; + +/** + * struct cam_icp_dump_header + * @tag: tag of the packet + * @size: size of data in packet + * @word_size: size of each word in packet + */ +struct cam_icp_dump_header { + char tag[CAM_ICP_DUMP_TAG_MAX_LEN]; + uint64_t size; + int32_t word_size; +}; + #endif /* CAM_ICP_HW_MGR_INTF_H */ diff --git a/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c b/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c index f68cd80ea7cd..ca7380b1d748 100644 --- a/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c +++ b/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c @@ -29,13 +29,123 @@ static const char isp_dev_name[] = "cam-isp"; -#define INC_STATE_MONITOR_HEAD(head) \ +#define INC_HEAD(head, max_entries) \ (atomic64_add_return(1, head) % \ - CAM_ISP_CTX_STATE_MONITOR_MAX_ENTRIES) + max_entries) static int cam_isp_context_dump_active_request(void *data, unsigned long iova, uint32_t buf_info); +static const char *__cam_isp_evt_val_to_type( + uint32_t evt_id) +{ + switch (evt_id) { + case CAM_ISP_CTX_EVENT_SUBMIT: + return "SUBMIT"; + case CAM_ISP_CTX_EVENT_APPLY: + return "APPLY"; + case CAM_ISP_CTX_EVENT_EPOCH: + return "EPOCH"; + case CAM_ISP_CTX_EVENT_RUP: + return "RUP"; + case CAM_ISP_CTX_EVENT_BUFDONE: + return "BUFDONE"; + default: + return "CAM_ISP_EVENT_INVALID"; + } +} + +static void __cam_isp_ctx_update_event_record( + struct cam_isp_context *ctx_isp, + enum cam_isp_ctx_event event, + struct cam_ctx_request *req) +{ + int iterator = 0; + struct cam_isp_ctx_req *req_isp; + struct timeval cur_time; + + switch (event) { + case CAM_ISP_CTX_EVENT_EPOCH: + case CAM_ISP_CTX_EVENT_RUP: + case CAM_ISP_CTX_EVENT_BUFDONE: + break; + case CAM_ISP_CTX_EVENT_SUBMIT: + case CAM_ISP_CTX_EVENT_APPLY: + if (!req) { + CAM_ERR(CAM_ISP, "Invalid arg for event %d", event); + return; + } + break; + default: + break; + } + + iterator = INC_HEAD(&ctx_isp->event_record_head[event], + CAM_ISP_CTX_EVENT_RECORD_MAX_ENTRIES); + cam_common_util_get_curr_timestamp(&cur_time); + + if (req) { + req_isp = (struct cam_isp_ctx_req *) req->req_priv; + ctx_isp->event_record[event][iterator].req_id = + req->request_id; + req_isp->event_timestamp[event].tv_sec = + cur_time.tv_sec; + req_isp->event_timestamp[event].tv_usec = + cur_time.tv_usec; + } else { + ctx_isp->event_record[event][iterator].req_id = 0; + } + ctx_isp->event_record[event][iterator].timestamp.tv_sec = + cur_time.tv_sec; + ctx_isp->event_record[event][iterator].timestamp.tv_usec = + cur_time.tv_usec; +} + +static void __cam_isp_ctx_dump_event_record( + struct cam_isp_context *ctx_isp, + uintptr_t cpu_addr, + size_t buf_len, + uint32_t *offset) +{ + int i, j; + struct cam_isp_context_event_record *record; + int index; + uint64_t state_head; + struct cam_isp_context_dump_header *hdr; + uint64_t *addr, *start; + uint8_t *dst; + + if (!cpu_addr || !buf_len || !offset) { + CAM_ERR(CAM_ISP, "Invalid args"); + return; + } + for (i = 0; i < CAM_ISP_CTX_EVENT_MAX; i++) { + state_head = atomic64_read(&ctx_isp->event_record_head[i]); + dst = (char *)cpu_addr + *offset; + hdr = (struct cam_isp_context_dump_header *)dst; + snprintf(hdr->tag, + CAM_ISP_CONTEXT_DUMP_TAG_MAX_LEN, "ISP_EVT_%s:", + __cam_isp_evt_val_to_type(i)); + hdr->word_size = sizeof(uint64_t); + addr = (uint64_t *)(dst + + sizeof(struct cam_isp_context_dump_header)); + start = addr; + for (j = CAM_ISP_CTX_EVENT_RECORD_MAX_ENTRIES - 1; j >= 0; + j--) { + index = (((state_head - j) + + CAM_ISP_CTX_EVENT_RECORD_MAX_ENTRIES) % + CAM_ISP_CTX_EVENT_RECORD_MAX_ENTRIES); + record = &ctx_isp->event_record[i][index]; + *addr++ = record->req_id; + *addr++ = record->timestamp.tv_sec; + *addr++ = record->timestamp.tv_usec; + } + hdr->size = hdr->word_size * (addr - start); + *offset += hdr->size + + sizeof(struct cam_isp_context_dump_header); + } +} + static void __cam_isp_ctx_update_state_monitor_array( struct cam_isp_context *ctx_isp, enum cam_isp_hw_event_type hw_event, @@ -44,7 +154,8 @@ static void __cam_isp_ctx_update_state_monitor_array( { int iterator = 0; - iterator = INC_STATE_MONITOR_HEAD(&ctx_isp->state_monitor_head); + iterator = INC_HEAD(&ctx_isp->state_monitor_head, + CAM_ISP_CTX_STATE_MONITOR_MAX_ENTRIES); ctx_isp->cam_isp_ctx_state_monitor[iterator].curr_state = curr_state; ctx_isp->cam_isp_ctx_state_monitor[iterator].next_state = @@ -160,7 +271,11 @@ static void __cam_isp_ctx_dump_state_monitor_array( } } -static void cam_isp_ctx_dump_req(struct cam_isp_ctx_req *req_isp) +static void cam_isp_ctx_dump_req(struct cam_isp_ctx_req *req_isp, + uintptr_t cpu_addr, + size_t buf_len, + uint32_t *offset, + bool dump_to_buff) { int i = 0, rc = 0; size_t len = 0; @@ -168,6 +283,7 @@ static void cam_isp_ctx_dump_req(struct cam_isp_ctx_req *req_isp) uint32_t *buf_start, *buf_end; size_t remain_len = 0; bool need_put = false; + struct cam_cdm_cmd_buf_dump_info dump_info; for (i = 0; i < req_isp->num_cfg; i++) { rc = cam_packet_util_get_cmd_mem_addr( @@ -202,7 +318,21 @@ put: req_isp->cfg[i].offset); buf_end = (uint32_t *)((uint8_t *) buf_start + req_isp->cfg[i].len - 1); - cam_cdm_util_dump_cmd_buf(buf_start, buf_end); + if (dump_to_buff) { + if (!cpu_addr || !offset || !buf_len) { + CAM_ERR(CAM_ISP, "Invalid args"); + break; + } + dump_info.src_start = buf_start; + dump_info.src_end = buf_end; + dump_info.dst_start = cpu_addr; + dump_info.dst_offset = *offset; + dump_info.dst_max_size = buf_len; + cam_cdm_util_dump_cmd_bufs_v2(&dump_info); + *offset = dump_info.dst_offset; + } else { + cam_cdm_util_dump_cmd_buf(buf_start, buf_end); + } if (cam_mem_put_cpu_buf(req_isp->cfg[i].handle)) CAM_WARN(CAM_ISP, "Failed to put cpu buf: 0x%x", req_isp->cfg[i].handle); @@ -216,6 +346,7 @@ static int __cam_isp_ctx_enqueue_request_in_order( struct cam_ctx_request *req_current; struct cam_ctx_request *req_prev; struct list_head temp_list; + struct cam_isp_context *ctx_isp; INIT_LIST_HEAD(&temp_list); spin_lock_bh(&ctx->lock); @@ -246,6 +377,9 @@ static int __cam_isp_ctx_enqueue_request_in_order( } } } + ctx_isp = (struct cam_isp_context *) ctx->ctx_priv; + __cam_isp_ctx_update_event_record(ctx_isp, + CAM_ISP_CTX_EVENT_SUBMIT, req); spin_unlock_bh(&ctx->lock); return 0; } @@ -490,7 +624,6 @@ static int __cam_isp_ctx_handle_buf_done_in_activated_state( req_isp->fence_map_out[j].resource_handle, 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); if (rc) @@ -560,6 +693,8 @@ static int __cam_isp_ctx_handle_buf_done_in_activated_state( CAM_ISP_HW_EVENT_DONE, ctx_isp->substate_activated, ctx_isp->substate_activated); + __cam_isp_ctx_update_event_record(ctx_isp, + CAM_ISP_CTX_EVENT_BUFDONE, req); } else { list_del_init(&req->list); list_add_tail(&req->list, &ctx->free_req_list); @@ -574,6 +709,8 @@ static int __cam_isp_ctx_handle_buf_done_in_activated_state( CAM_ISP_HW_EVENT_DONE, ctx_isp->substate_activated, ctx_isp->substate_activated); + __cam_isp_ctx_update_event_record(ctx_isp, + CAM_ISP_CTX_EVENT_BUFDONE, req); } if (ctx_isp->active_req_cnt && ctx_isp->irq_delay_detect) { @@ -742,6 +879,10 @@ static int __cam_isp_ctx_reg_upd_in_activated_state( 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); + + __cam_isp_ctx_update_event_record(ctx_isp, + CAM_ISP_CTX_EVENT_RUP, req); + } else { /* no io config, so the request is completed. */ list_add_tail(&req->list, &ctx->free_req_list); @@ -776,7 +917,7 @@ static int __cam_isp_ctx_notify_sof_in_activated_state( int rc = 0; struct cam_req_mgr_trigger_notify notify; struct cam_context *ctx = ctx_isp->base; - struct cam_ctx_request *req; + struct cam_ctx_request *req = NULL; uint64_t request_id = 0; /* @@ -807,6 +948,8 @@ static int __cam_isp_ctx_notify_sof_in_activated_state( ctx_isp->req_info.reported_req_id = request_id; ctx_isp->req_info.last_reported_id_time_stamp = jiffies_to_msecs(jiffies); + __cam_isp_ctx_update_event_record(ctx_isp, + CAM_ISP_CTX_EVENT_EPOCH, req); break; } } @@ -973,6 +1116,8 @@ static int __cam_isp_ctx_epoch_in_applied(struct cam_isp_context *ctx_isp, __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id, CAM_REQ_MGR_SOF_EVENT_SUCCESS); + __cam_isp_ctx_update_event_record(ctx_isp, + CAM_ISP_CTX_EVENT_EPOCH, NULL); goto end; } @@ -1018,6 +1163,8 @@ static int __cam_isp_ctx_epoch_in_applied(struct cam_isp_context *ctx_isp, } __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id, CAM_REQ_MGR_SOF_EVENT_ERROR); + __cam_isp_ctx_update_event_record(ctx_isp, + CAM_ISP_CTX_EVENT_EPOCH, req); ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_BUBBLE; CAM_DBG(CAM_ISP, "next substate %d", @@ -1128,7 +1275,8 @@ static int __cam_isp_ctx_epoch_in_bubble_applied( __cam_isp_ctx_dump_state_monitor_array(ctx_isp, true); __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id, CAM_REQ_MGR_SOF_EVENT_SUCCESS); - + __cam_isp_ctx_update_event_record(ctx_isp, + CAM_ISP_CTX_EVENT_EPOCH, NULL); ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_BUBBLE; goto end; } @@ -1175,13 +1323,20 @@ static int __cam_isp_ctx_epoch_in_bubble_applied( jiffies_to_msecs(jiffies); __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id, CAM_REQ_MGR_SOF_EVENT_ERROR); - } else + __cam_isp_ctx_update_event_record(ctx_isp, + CAM_ISP_CTX_EVENT_EPOCH, req); + } else { __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id, CAM_REQ_MGR_SOF_EVENT_SUCCESS); - } else + __cam_isp_ctx_update_event_record(ctx_isp, + CAM_ISP_CTX_EVENT_EPOCH, NULL); + } + } else { __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id, CAM_REQ_MGR_SOF_EVENT_SUCCESS); - + __cam_isp_ctx_update_event_record(ctx_isp, + CAM_ISP_CTX_EVENT_EPOCH, NULL); + } ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_BUBBLE; CAM_DBG(CAM_ISP, "next substate %d", ctx_isp->substate_activated); end: @@ -1253,7 +1408,7 @@ static int __cam_isp_ctx_handle_error(struct cam_isp_context *ctx_isp, req_isp = (struct cam_isp_ctx_req *) req_to_dump->req_priv; if (error_event_data->enable_reg_dump) - cam_isp_ctx_dump_req(req_isp); + cam_isp_ctx_dump_req(req_isp, 0, 0, NULL, false); list_for_each_entry_safe(req, req_temp, &ctx->active_req_list, list) { @@ -1916,6 +2071,8 @@ static int __cam_isp_ctx_apply_req_in_activated_state( CAM_DBG(CAM_ISP, "new substate state %d, applied req %lld", next_state, ctx_isp->req_info.last_applied_req_id); + __cam_isp_ctx_update_event_record(ctx_isp, + CAM_ISP_CTX_EVENT_APPLY, req); spin_unlock_bh(&ctx->lock); } end: @@ -1971,6 +2128,160 @@ static int __cam_isp_ctx_apply_req_in_bubble( return rc; } +static int __cam_isp_ctx_dump_req_info(struct cam_context *ctx, + struct cam_ctx_request *req, + uintptr_t cpu_addr, + size_t buf_len, + uint32_t *offset) +{ + int rc = 0; + struct cam_isp_ctx_req *req_isp; + struct cam_isp_context *ctx_isp; + int i; + struct cam_isp_context_dump_header *hdr; + int32_t *addr, *start; + uint8_t *dst; + + if (!req || !ctx || !offset || !cpu_addr || !buf_len) { + CAM_ERR(CAM_ISP, "Invalid parameters %pK %pK %u %pK %pK %pK ", + req, ctx, offset, cpu_addr, buf_len); + return -EINVAL; + } + req_isp = (struct cam_isp_ctx_req *)req->req_priv; + ctx_isp = (struct cam_isp_context *)ctx->ctx_priv; + dst = (char *)cpu_addr + *offset; + hdr = (struct cam_isp_context_dump_header *)dst; + hdr->word_size = sizeof(int32_t); + snprintf(hdr->tag, CAM_ISP_CONTEXT_DUMP_TAG_MAX_LEN, + "ISP_OUT_FENCE:"); + addr = (int32_t *)(dst + sizeof(struct cam_isp_context_dump_header)); + start = addr; + for (i = 0; i < req_isp->num_fence_map_out; i++) { + if (req_isp->fence_map_out[i].sync_id != -1) { + *addr++ = req_isp->fence_map_out[i].resource_handle; + *addr++ = req_isp->fence_map_out[i].sync_id; + } + } + hdr->size = hdr->word_size * (addr - start); + *offset += hdr->size + sizeof(struct cam_isp_context_dump_header); + cam_isp_ctx_dump_req(req_isp, cpu_addr, buf_len, + offset, true); + return rc; +} + +static int __cam_isp_ctx_dump_in_top_state(struct cam_context *ctx, + struct cam_req_mgr_dump_info *dump_info) +{ + struct cam_ctx_request *req = NULL; + struct cam_isp_ctx_req *req_isp; + struct cam_ctx_request *req_temp; + struct cam_hw_dump_args dump_args; + struct cam_isp_context *ctx_isp; + uint64_t diff = 0; + struct timeval cur_time; + int rc = 0; + uintptr_t cpu_addr; + size_t buf_len; + struct cam_isp_context_dump_header *hdr; + uint64_t *addr, *start; + uint8_t *dst; + bool is_dump_only_event_record = false; + + list_for_each_entry_safe(req, req_temp, + &ctx->active_req_list, list) { + if (req->request_id == dump_info->req_id) { + CAM_DBG(CAM_ISP, "isp active dumping req: %lld", + dump_info->req_id); + goto hw_dump; + } + } + list_for_each_entry_safe(req, req_temp, + &ctx->wait_req_list, list) { + if (req->request_id == dump_info->req_id) { + CAM_ERR(CAM_ISP, "isp dumping wait req: %lld", + dump_info->req_id); + goto hw_dump; + } + } + return rc; +hw_dump: + if (req) { + req_isp = (struct cam_isp_ctx_req *) req->req_priv; + cam_common_util_get_curr_timestamp(&cur_time); + diff = cam_common_util_get_time_diff(&cur_time, + &req_isp->event_timestamp[CAM_ISP_CTX_EVENT_APPLY]); + if (diff < CAM_ISP_CTX_RESPONSE_TIME_THRESHOLD) { + CAM_INFO(CAM_ISP, "req %lld found no error", + req->request_id); + is_dump_only_event_record = true; + } + ctx_isp = (struct cam_isp_context *) ctx->ctx_priv; + rc = cam_mem_get_cpu_buf(dump_info->buf_handle, + &cpu_addr, &buf_len); + if (!cpu_addr || !buf_len || rc) { + CAM_ERR(CAM_ISP, + "lnvalid addr %u len %zu rc %d", + dump_info->buf_handle, buf_len, rc); + return rc; + } + /* we take for isp sw information to be max as 2048*/ + if ((buf_len - dump_info->offset) < + CAM_ISP_CTX_DUMP_MIN_LENGTH) { + CAM_ERR(CAM_ISP, "Dump buffer exhaust %u %u", + buf_len, dump_info->offset); + goto end; + } + dst = (char *)cpu_addr + dump_info->offset; + hdr = (struct cam_isp_context_dump_header *)dst; + snprintf(hdr->tag, CAM_ISP_CONTEXT_DUMP_TAG_MAX_LEN, + "ISP_CTX_DUMP:"); + hdr->word_size = sizeof(uint64_t); + addr = (uint64_t *)(dst + + sizeof(struct cam_isp_context_dump_header)); + start = addr; + *addr++ = req->request_id; + *addr++ = req_isp->event_timestamp + [CAM_ISP_CTX_EVENT_APPLY].tv_sec; + *addr++ = req_isp->event_timestamp + [CAM_ISP_CTX_EVENT_APPLY].tv_usec; + *addr++ = cur_time.tv_sec; + *addr++ = cur_time.tv_usec; + hdr->size = hdr->word_size * (addr - start); + dump_info->offset += hdr->size + + sizeof(struct cam_isp_context_dump_header); + + spin_lock_bh(&ctx->lock); + __cam_isp_ctx_dump_event_record(ctx_isp, cpu_addr, + buf_len, &dump_info->offset); + spin_unlock_bh(&ctx->lock); + if (is_dump_only_event_record) + goto end; + rc = __cam_isp_ctx_dump_req_info(ctx, req, cpu_addr, + buf_len, &dump_info->offset); + if (rc) { + CAM_ERR(CAM_ISP, "Dump Req info fail %lld", + req->request_id); + goto end; + } + if (ctx->hw_mgr_intf->hw_dump) { + dump_args.offset = dump_info->offset; + dump_args.request_id = dump_info->req_id; + dump_args.buf_handle = dump_info->buf_handle; + dump_args.ctxt_to_hw_map = ctx_isp->hw_ctx; + rc = ctx->hw_mgr_intf->hw_dump( + ctx->hw_mgr_intf->hw_mgr_priv, + &dump_args); + dump_info->offset = dump_args.offset; + } +end: + rc = cam_mem_put_cpu_buf(dump_info->buf_handle); + if (rc) + CAM_ERR(CAM_ISP, "Cpu put failed handle %u", + dump_info->buf_handle); + } + return rc; +} + static int __cam_isp_ctx_flush_req(struct cam_context *ctx, struct list_head *req_list, struct cam_req_mgr_flush_request *flush_req) { @@ -2510,7 +2821,7 @@ static int __cam_isp_ctx_rdi_only_sof_in_bubble_state( static int __cam_isp_ctx_rdi_only_reg_upd_in_bubble_applied_state( struct cam_isp_context *ctx_isp, void *evt_data) { - struct cam_ctx_request *req; + struct cam_ctx_request *req = NULL; struct cam_context *ctx = ctx_isp->base; struct cam_isp_ctx_req *req_isp = NULL; struct cam_req_mgr_trigger_notify notify; @@ -2572,6 +2883,8 @@ static int __cam_isp_ctx_rdi_only_reg_upd_in_bubble_applied_state( __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id, CAM_REQ_MGR_SOF_EVENT_SUCCESS); + __cam_isp_ctx_update_event_record(ctx_isp, + CAM_ISP_CTX_EVENT_RUP, req); CAM_DBG(CAM_ISP, "next substate %d", ctx_isp->substate_activated); return 0; @@ -2579,6 +2892,8 @@ error: /* Send SOF event as idle frame*/ __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id, CAM_REQ_MGR_SOF_EVENT_SUCCESS); + __cam_isp_ctx_update_event_record(ctx_isp, + CAM_ISP_CTX_EVENT_RUP, NULL); /* * There is no request in the pending list, move the sub state machine @@ -3839,6 +4154,7 @@ static struct cam_ctx_ops .unlink = __cam_isp_ctx_unlink_in_acquired, .get_dev_info = __cam_isp_ctx_get_dev_info_in_acquired, .flush_req = __cam_isp_ctx_flush_req_in_top_state, + .dump_req = __cam_isp_ctx_dump_in_top_state, }, .irq_ops = NULL, .pagefault_ops = cam_isp_context_dump_active_request, @@ -3854,6 +4170,7 @@ static struct cam_ctx_ops .crm_ops = { .unlink = __cam_isp_ctx_unlink_in_ready, .flush_req = __cam_isp_ctx_flush_req_in_ready, + .dump_req = __cam_isp_ctx_dump_in_top_state, }, .irq_ops = NULL, .pagefault_ops = cam_isp_context_dump_active_request, @@ -3871,6 +4188,7 @@ static struct cam_ctx_ops .apply_req = __cam_isp_ctx_apply_req, .flush_req = __cam_isp_ctx_flush_req_in_top_state, .process_evt = __cam_isp_ctx_process_evt, + .dump_req = __cam_isp_ctx_dump_in_top_state, }, .irq_ops = __cam_isp_ctx_handle_irq_in_activated, .pagefault_ops = cam_isp_context_dump_active_request, diff --git a/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.h b/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.h index cb73252363db..5620e148cb83 100644 --- a/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.h +++ b/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.h @@ -44,6 +44,21 @@ */ #define CAM_ISP_CTX_STATE_MONITOR_MAX_ENTRIES 20 +/* + * Response time in ms threshold beyond which a request is not expected + * to be with IFE hw + */ +#define CAM_ISP_CTX_RESPONSE_TIME_THRESHOLD 100000 + +/* Min length for dumping isp context */ +#define CAM_ISP_CTX_DUMP_MIN_LENGTH 2048 + +/* Maximum entries in event record */ +#define CAM_ISP_CTX_EVENT_RECORD_MAX_ENTRIES 20 + +/* Maximum length of tag while dumping */ +#define CAM_ISP_CONTEXT_DUMP_TAG_MAX_LEN 32 + /* forward declaration */ struct cam_isp_context; @@ -67,6 +82,19 @@ enum cam_isp_ctx_activated_substate { }; /** + * enum cam_isp_ctx_event_type - events for a request + * + */ +enum cam_isp_ctx_event { + CAM_ISP_CTX_EVENT_SUBMIT, + CAM_ISP_CTX_EVENT_APPLY, + CAM_ISP_CTX_EVENT_EPOCH, + CAM_ISP_CTX_EVENT_RUP, + CAM_ISP_CTX_EVENT_BUFDONE, + CAM_ISP_CTX_EVENT_MAX, +}; + +/** * struct cam_isp_ctx_irq_ops - Function table for handling IRQ callbacks * * @irq_ops: Array of handle function pointers. @@ -92,6 +120,8 @@ struct cam_isp_ctx_irq_ops { * @bubble_report: Flag to track if bubble report is active on * current request * @hw_update_data: HW update data for this request + * @event_timestamp: Timestamp for different stage of request + * @bubble_detected: Flag to indicate if bubble detected * */ struct cam_isp_ctx_req { @@ -107,6 +137,8 @@ struct cam_isp_ctx_req { uint32_t num_acked; int32_t bubble_report; struct cam_isp_prepare_hw_update_data hw_update_data; + struct timeval event_timestamp + [CAM_ISP_CTX_EVENT_MAX]; bool bubble_detected; }; @@ -156,6 +188,21 @@ struct cam_isp_context_req_id_info { int64_t last_reported_id_time_stamp; }; + +/** + * struct cam_isp_context_event_record - ISP context request id + * information for last 20 Events. Submit, Applied, SOF, EPOCH, + * RUP, Buf done + * + *@req_id: Last applied request id + *@timestamp: Timestamp for the event + * + */ +struct cam_isp_context_event_record { + int64_t req_id; + struct timeval timestamp; +}; + /** * struct cam_isp_context - ISP context object * @@ -180,6 +227,8 @@ struct cam_isp_context_req_id_info { * @req_info Request id information about last applied, * reported and buf done * @cam_isp_ctx_state_monitor: State monitoring array + * @event_record_head: Write index to the state monitoring array + * @event_record: Event record array * @rdi_only_context: Get context type information. * true, if context is rdi only context * @hw_acquired: Indicate whether HW resources are acquired @@ -213,6 +262,10 @@ struct cam_isp_context { struct cam_isp_context_state_monitor cam_isp_ctx_state_monitor[ CAM_ISP_CTX_STATE_MONITOR_MAX_ENTRIES]; struct cam_isp_context_req_id_info req_info; + atomic64_t event_record_head[ + CAM_ISP_CTX_EVENT_MAX]; + struct cam_isp_context_event_record event_record[ + CAM_ISP_CTX_EVENT_MAX][CAM_ISP_CTX_EVENT_RECORD_MAX_ENTRIES]; bool rdi_only_context; bool hw_acquired; bool init_received; @@ -223,6 +276,19 @@ struct cam_isp_context { }; /** + * struct cam_isp_context_dump_header - ISP context dump header + * @tag: Tag name for the header + * @word_size: Size of word + * @size: Size of data + * + */ +struct cam_isp_context_dump_header { + char tag[CAM_ISP_CONTEXT_DUMP_TAG_MAX_LEN]; + uint64_t size; + uint32_t word_size; +}; + +/** * cam_isp_context_init() * * @brief: Initialization function for the ISP context diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index 30c0d6efac41..199bf24e8e5a 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -2958,8 +2958,11 @@ static int cam_ife_mgr_start_hw(void *hw_mgr_priv, void *start_hw_args) struct cam_isp_stop_args stop_isp; struct cam_ife_hw_mgr_ctx *ctx; struct cam_ife_hw_mgr_res *hw_mgr_res; + struct cam_hw_intf *hw_intf; struct cam_isp_resource_node *rsrc_node = NULL; - uint32_t i, camif_debug; + uint32_t i, j, camif_debug; + uint32_t enable_dmi_dump; + struct cam_isp_hw_get_cmd_update cmd_update; if (!hw_mgr_priv || !start_isp) { CAM_ERR(CAM_ISP, "Invalid arguments"); @@ -3017,6 +3020,24 @@ static int cam_ife_mgr_start_hw(void *hw_mgr_priv, void *start_hw_args) } } + enable_dmi_dump = g_ife_hw_mgr.debug_cfg.enable_dmi_dump; + for (i = 0; i < CAM_IFE_HW_OUT_RES_MAX; i++) { + hw_mgr_res = &ctx->res_list_ife_out[i]; + for (j = 0; j < CAM_ISP_HW_SPLIT_MAX; j++) { + if (!hw_mgr_res->hw_res[j]) + continue; + hw_intf = hw_mgr_res->hw_res[j]->hw_intf; + cmd_update.res = hw_mgr_res->hw_res[j]; + cmd_update.cmd_type = + CAM_ISP_HW_CMD_SET_STATS_DMI_DUMP; + cmd_update.data = &enable_dmi_dump; + hw_intf->hw_ops.process_cmd(hw_intf->hw_priv, + CAM_ISP_HW_CMD_SET_STATS_DMI_DUMP, + &cmd_update, + sizeof(cmd_update)); + } + } + rc = cam_ife_hw_mgr_init_hw(ctx); if (rc) { CAM_ERR(CAM_ISP, "Init failed"); @@ -4576,6 +4597,114 @@ static int cam_ife_mgr_cmd(void *hw_mgr_priv, void *cmd_args) return rc; } +static int cam_ife_mgr_dump(void *hw_mgr_priv, void *args) +{ + struct cam_isp_hw_dump_args isp_hw_dump_args; + struct cam_hw_dump_args *dump_args = (struct cam_hw_dump_args *)args; + struct cam_ife_hw_mgr_res *hw_mgr_res; + struct cam_hw_intf *hw_intf; + struct cam_ife_hw_mgr_ctx *ife_ctx = (struct cam_ife_hw_mgr_ctx *) + dump_args->ctxt_to_hw_map; + int i; + int rc = 0; + + rc = cam_mem_get_cpu_buf(dump_args->buf_handle, + &isp_hw_dump_args.cpu_addr, + &isp_hw_dump_args.buf_len); + if (!isp_hw_dump_args.cpu_addr || + !isp_hw_dump_args.buf_len || rc) { + CAM_ERR(CAM_ISP, + "lnvalid addr %u len %zu rc %d", + dump_args->buf_handle, + isp_hw_dump_args.buf_len, + rc); + return rc; + } + isp_hw_dump_args.offset = dump_args->offset; + isp_hw_dump_args.req_id = dump_args->request_id; + + list_for_each_entry(hw_mgr_res, &ife_ctx->res_list_ife_csid, list) { + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!hw_mgr_res->hw_res[i]) + continue; + hw_intf = hw_mgr_res->hw_res[i]->hw_intf; + switch (hw_mgr_res->hw_res[i]->res_id) { + case CAM_IFE_PIX_PATH_RES_RDI_0: + case CAM_IFE_PIX_PATH_RES_RDI_1: + case CAM_IFE_PIX_PATH_RES_RDI_2: + case CAM_IFE_PIX_PATH_RES_RDI_3: + if (ife_ctx->is_rdi_only_context && + hw_intf->hw_ops.process_cmd) { + rc = hw_intf->hw_ops.process_cmd( + hw_intf->hw_priv, + CAM_ISP_HW_CMD_DUMP_HW, + &isp_hw_dump_args, + sizeof(struct + cam_isp_hw_dump_args)); + } + break; + case CAM_IFE_PIX_PATH_RES_IPP: + if (hw_intf->hw_ops.process_cmd) { + rc = hw_intf->hw_ops.process_cmd( + hw_intf->hw_priv, + CAM_ISP_HW_CMD_DUMP_HW, + &isp_hw_dump_args, + sizeof(struct + cam_isp_hw_dump_args)); + } + break; + default: + CAM_DBG(CAM_ISP, "not a valid res %d", + hw_mgr_res->res_id); + break; + } + } + } + list_for_each_entry(hw_mgr_res, &ife_ctx->res_list_ife_src, list) { + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!hw_mgr_res->hw_res[i]) + continue; + hw_intf = hw_mgr_res->hw_res[i]->hw_intf; + switch (hw_mgr_res->res_id) { + case CAM_ISP_HW_VFE_IN_RDI0: + case CAM_ISP_HW_VFE_IN_RDI1: + case CAM_ISP_HW_VFE_IN_RDI2: + case CAM_ISP_HW_VFE_IN_RDI3: + if (ife_ctx->is_rdi_only_context && + hw_intf->hw_ops.process_cmd) { + rc = hw_intf->hw_ops.process_cmd( + hw_intf->hw_priv, + CAM_ISP_HW_CMD_DUMP_HW, + &isp_hw_dump_args, + sizeof(struct + cam_isp_hw_dump_args)); + } + break; + case CAM_ISP_HW_VFE_IN_CAMIF: + if (hw_intf->hw_ops.process_cmd) { + rc = hw_intf->hw_ops.process_cmd( + hw_intf->hw_priv, + CAM_ISP_HW_CMD_DUMP_HW, + &isp_hw_dump_args, + sizeof(struct + cam_isp_hw_dump_args)); + } + break; + default: + CAM_DBG(CAM_ISP, "not a valid res %d", + hw_mgr_res->res_id); + break; + } + } + } + dump_args->offset = isp_hw_dump_args.offset; + rc = cam_mem_put_cpu_buf(dump_args->buf_handle); + if (rc) + CAM_ERR(CAM_FD, "Cpu put failed handle %u", + dump_args->buf_handle); + return rc; +} + static int cam_ife_mgr_cmd_get_sof_timestamp( struct cam_ife_hw_mgr_ctx *ife_ctx, uint64_t *time_stamp, @@ -5967,6 +6096,27 @@ DEFINE_SIMPLE_ATTRIBUTE(cam_ife_camif_debug, cam_ife_get_camif_debug, cam_ife_set_camif_debug, "%16llu"); +static int cam_ife_set_bus_dmi_debug(void *data, u64 val) +{ + g_ife_hw_mgr.debug_cfg.enable_dmi_dump = val; + CAM_DBG(CAM_ISP, + "Set bus enable_dmi_dump_status value :%lld", val); + return 0; +} + +static int cam_ife_get_bus_dmi_debug(void *data, u64 *val) +{ + *val = g_ife_hw_mgr.debug_cfg.enable_dmi_dump; + CAM_DBG(CAM_ISP, + "Get bus enable_dmi_dump_status value :%lld", + g_ife_hw_mgr.debug_cfg.enable_dmi_dump); + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(cam_ife_bus_dmi_debug, + cam_ife_get_bus_dmi_debug, + cam_ife_set_bus_dmi_debug, "%16llu"); + static int cam_ife_hw_mgr_debug_register(void) { g_ife_hw_mgr.debug_cfg.dentry = debugfs_create_dir("camera_ife", @@ -6008,6 +6158,15 @@ static int cam_ife_hw_mgr_debug_register(void) CAM_ERR(CAM_ISP, "failed to create cam_ife_camif_debug"); goto err; } + + if (!debugfs_create_file("ife_dmi_dump", + 0644, + g_ife_hw_mgr.debug_cfg.dentry, NULL, + &cam_ife_bus_dmi_debug)) { + CAM_ERR(CAM_ISP, "failed to create cam_ife_dmi_dump"); + goto err; + } + g_ife_hw_mgr.debug_cfg.enable_recovery = 0; return 0; @@ -6190,6 +6349,7 @@ int cam_ife_hw_mgr_init(struct cam_hw_mgr_intf *hw_mgr_intf, int *iommu_hdl) hw_mgr_intf->hw_config = cam_ife_mgr_config_hw; hw_mgr_intf->hw_cmd = cam_ife_mgr_cmd; hw_mgr_intf->hw_reset = cam_ife_mgr_reset; + hw_mgr_intf->hw_dump = cam_ife_mgr_dump; if (iommu_hdl) *iommu_hdl = g_ife_hw_mgr.mgr_common.img_iommu_hdl; diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h index 0e6d79b75232..73066c3e0e15 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h @@ -89,6 +89,7 @@ struct ctx_base_info { * @enable_recovery: enable recovery * @enable_diag_sensor_status: enable sensor diagnosis status * @enable_reg_dump: enable register dump on error + * @enable_dmi_dump: enable stats dmi and cfg reg dump * */ struct cam_ife_hw_mgr_debug { @@ -97,6 +98,7 @@ struct cam_ife_hw_mgr_debug { uint32_t enable_recovery; uint32_t camif_debug; uint32_t enable_reg_dump; + uint32_t enable_dmi_dump; }; /** diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c index 5df20d7aefcb..aadb042fc925 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c @@ -3257,7 +3257,54 @@ static int cam_ife_csid_set_sensor_dimension( csid_hw->rdi_path_config[i].height); } } + return 0; +} +static int cam_ife_csid_dump_hw( + struct cam_ife_csid_hw *csid_hw, void *cmd_args) +{ + struct cam_hw_soc_info *soc_info; + struct cam_isp_hw_dump_args *dump_args = + (struct cam_isp_hw_dump_args *)cmd_args; + int i; + uint32_t *addr, *start; + uint32_t num_reg; + struct cam_isp_hw_dump_header *hdr; + uint8_t *dst; + + if (!dump_args->cpu_addr || !dump_args->buf_len) { + CAM_ERR(CAM_ISP, + "lnvalid len %zu ", dump_args->buf_len); + return -EINVAL; + } + soc_info = &csid_hw->hw_info->soc_info; + /*100 bytes we store the meta info of the dump data*/ + if ((dump_args->buf_len - dump_args->offset) < + soc_info->reg_map[0].size + 100) { + CAM_ERR(CAM_ISP, "Dump buffer exhaust"); + return 0; + } + dst = (char *)dump_args->cpu_addr + dump_args->offset; + hdr = (struct cam_isp_hw_dump_header *)dst; + snprintf(hdr->tag, CAM_ISP_HW_DUMP_TAG_MAX_LEN, + "CSID_REG:"); + addr = (uint32_t *)(dst + sizeof(struct cam_isp_hw_dump_header)); + + start = addr; + num_reg = soc_info->reg_map[0].size/4; + hdr->word_size = sizeof(uint32_t); + *addr = soc_info->index; + addr++; + for (i = 0; i < num_reg; i++) { + addr[0] = soc_info->mem_block[0]->start + (i*4); + addr[1] = cam_io_r(soc_info->reg_map[0].mem_base + + (i*4)); + addr += 2; + } + hdr->size = hdr->word_size * (addr - start); + dump_args->offset += hdr->size + + sizeof(struct cam_isp_hw_dump_header); + CAM_DBG(CAM_ISP, "offset %d", dump_args->offset); return 0; } @@ -3301,6 +3348,9 @@ static int cam_ife_csid_process_cmd(void *hw_priv, case CAM_IFE_CSID_SET_SENSOR_DIMENSION_CFG: rc = cam_ife_csid_set_sensor_dimension(csid_hw, cmd_args); break; + case CAM_ISP_HW_CMD_DUMP_HW: + rc = cam_ife_csid_dump_hw(csid_hw, cmd_args); + break; default: CAM_ERR(CAM_ISP, "CSID:%d unsupported cmd:%d", csid_hw->hw_intf->hw_idx, cmd_type); diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h index d90030d9ed16..a793fa76bee2 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h @@ -22,6 +22,9 @@ #define CAM_ISP_FPS_60 60 +/* Maximum length of tag while dumping */ +#define CAM_ISP_HW_DUMP_TAG_MAX_LEN 32 + /* * struct cam_isp_timestamp: * @@ -110,6 +113,8 @@ enum cam_isp_hw_cmd_type { CAM_ISP_HW_CMD_FE_UPDATE_BUS_RD, CAM_ISP_HW_CMD_GET_IRQ_REGISTER_DUMP, CAM_ISP_HW_CMD_FPS_CONFIG, + CAM_ISP_HW_CMD_DUMP_HW, + CAM_ISP_HW_CMD_SET_STATS_DMI_DUMP, CAM_ISP_HW_CMD_MAX, }; @@ -252,4 +257,39 @@ struct cam_isp_hw_dual_isp_update_args { struct cam_isp_resource_node *res; struct cam_isp_dual_config *dual_cfg; }; + +/* + * struct cam_isp_hw_dump_args: + * + * @Brief: isp hw dump args + * + * @ req_id: request id + * @ cpu_addr: cpu address + * @ buf_len: buf len + * @ offset: offset of buffer + * @ ctxt_to_hw_map: ctx to hw map + */ +struct cam_isp_hw_dump_args { + uint64_t req_id; + uintptr_t cpu_addr; + size_t buf_len; + uint32_t offset; + void *ctxt_to_hw_map; +}; + +/** + * struct cam_isp_hw_dump_header - ISP context dump header + * + * @Brief: isp hw dump header + * + * @tag: Tag name for the header + * @word_size: Size of word + * @size: Size of data + * + */ +struct cam_isp_hw_dump_header { + char tag[CAM_ISP_HW_DUMP_TAG_MAX_LEN]; + uint64_t size; + uint32_t word_size; +}; #endif /* _CAM_ISP_HW_H_ */ diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h index 3bcedc948a18..2b073d52778d 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h @@ -283,6 +283,7 @@ struct cam_vfe_bus_irq_evt_payload { uint32_t error_type; struct cam_isp_timestamp ts; void *ctx; + uint32_t enable_dump; }; /* diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c index 162ddadd744f..7fbf1c5b1e22 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c @@ -764,6 +764,7 @@ int cam_vfe_process_cmd(void *hw_priv, uint32_t cmd_type, case CAM_ISP_HW_CMD_BW_CONTROL: case CAM_ISP_HW_CMD_GET_IRQ_REGISTER_DUMP: case CAM_ISP_HW_CMD_FPS_CONFIG: + case CAM_ISP_HW_CMD_DUMP_HW: rc = core_info->vfe_top->hw_ops.process_cmd( core_info->vfe_top->top_priv, cmd_type, cmd_args, arg_size); @@ -773,6 +774,7 @@ int cam_vfe_process_cmd(void *hw_priv, uint32_t cmd_type, case CAM_ISP_HW_CMD_STRIPE_UPDATE: case CAM_ISP_HW_CMD_STOP_BUS_ERR_IRQ: case CAM_ISP_HW_CMD_UBWC_UPDATE: + case CAM_ISP_HW_CMD_SET_STATS_DMI_DUMP: rc = core_info->vfe_bus->hw_ops.process_cmd( core_info->vfe_bus->bus_priv, cmd_type, cmd_args, arg_size); diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170.h index 61c1e9e01ba2..dc1ee4cd4cac 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170.h +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170.h @@ -108,6 +108,169 @@ struct cam_vfe_top_ver2_reg_offset_module_ctrl zoom_170_reg = { .enable = 0x0000004C, }; +static struct cam_vfe_bus_ver2_stats_cfg_info stats_170_info = { + .dmi_offset_info = { + .auto_increment = 0x00000100, + .cfg_offset = 0x00000C24, + .addr_offset = 0x00000C28, + .data_hi_offset = 0x00000C2C, + .data_lo_offset = 0x00000C30, + }, + .stats_cfg_offset = { + /* CAM_VFE_BUS_VER2_VFE_OUT_RDI0 */ + { + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_RDI1 */ + { + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_RDI2 */ + { + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_RDI3 */ + { + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_FULL */ + { + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_DS4 */ + { + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_DS16 */ + { + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_RAW_DUMP */ + { + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_FD */ + { + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_PDAF */ + { + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BE */ + { + .res_index = CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BE, + .cfg_offset = 0x00000AB8, + .num_cfg = 0x00000ABC, + .cfg_size = 0x00000AC0, + .is_lut = 0, + .lut = { + .size = 0, + .bank_0 = 0, + .bank_1 = 0, + }, + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BHIST */ + { + .res_index = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BHIST, + .cfg_offset = 0x00000AD4, + .num_cfg = 0x00000AD8, + .cfg_size = 0x00000000, + .is_lut = 1, + .lut = { + .size = 180, + .bank_0 = 0x36, + .bank_1 = 0x37, + }, + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_STATS_TL_BG */ + { + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_STATS_BF */ + { + .res_index = CAM_VFE_BUS_VER2_VFE_OUT_STATS_BF, + .cfg_offset = 0x00000AE4, + .num_cfg = 0x00000000, + .cfg_size = 0x00000000, + .is_lut = 1, + .lut = { + .size = 180, + .bank_0 = 0x40, + .bank_1 = 0x41, + }, + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_STATS_AWB_BG */ + { + .res_index = CAM_VFE_BUS_VER2_VFE_OUT_STATS_AWB_BG, + .cfg_offset = 0x00000BC8, + .num_cfg = 0x00000BCC, + .cfg_size = 0x00000BD0, + .is_lut = 0, + .lut = { + .size = 0, + .bank_0 = 0, + .bank_1 = 0, + }, + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_STATS_BHIST */ + { + .res_index = CAM_VFE_BUS_VER2_VFE_OUT_STATS_BHIST, + .cfg_offset = 0x00000BE4, + .num_cfg = 0x00000BE8, + .cfg_size = 0x00000000, + .is_lut = 1, + .lut = { + .size = 180, + .bank_0 = 0x3A, + .bank_1 = 0, + }, + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_STATS_RS */ + { + .res_index = CAM_VFE_BUS_VER2_VFE_OUT_STATS_RS, + .cfg_offset = 0x00000BEC, + .num_cfg = 0x00000BF0, + .cfg_size = 0x00000BF4, + .is_lut = 0, + .lut = { + .size = 0, + .bank_0 = 0, + .bank_1 = 0, + }, + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_STATS_CS */ + { + .res_index = CAM_VFE_BUS_VER2_VFE_OUT_STATS_CS, + .cfg_offset = 0x00000BF8, + .num_cfg = 0x00000BFC, + .cfg_size = 0x00000C00, + .is_lut = 0, + .lut = { + .size = 0, + .bank_0 = 0, + .bank_1 = 0, + }, + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_STATS_IHIST */ + { + .res_index = CAM_VFE_BUS_VER2_VFE_OUT_STATS_IHIST, + .cfg_offset = 0x00000C04, + .num_cfg = 0x00000C08, + .cfg_size = 0x00000000, + .is_lut = 1, + .lut = { + .size = 180, + .bank_0 = 0x3B, + .bank_1 = 0x3C, + }, + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_FULL_DISP */ + { + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_DS4_DISP */ + { + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_DS16_DISP */ + { + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_2PD */ + { + }, + }, +}; + + static struct cam_vfe_top_ver2_reg_offset_common vfe170_top_common_reg = { .hw_version = 0x00000000, .hw_capability = 0x00000004, @@ -173,6 +336,31 @@ static struct cam_vfe_top_ver2_hw_info vfe170_top_hw_info = { NULL, }, }, + .dump_data = { + .num_reg_dump_entries = 2, + .num_lut_dump_entries = 1, + .dmi_cfg = 0xc24, + .dmi_addr = 0xc28, + .dmi_data_path_hi = 0xc2C, + .dmi_data_path_lo = 0xc30, + .reg_entry = { + { + .reg_dump_start = 0x0, + .reg_dump_end = 0x1160, + }, + { + .reg_dump_start = 0x2000, + .reg_dump_end = 0x3978, + }, + }, + .lut_entry = { + { + .lut_word_size = 64, + .lut_bank_sel = 0x40, + .lut_addr_size = 180, + }, + }, + }, .mux_type = { CAM_VFE_CAMIF_VER_2_0, CAM_VFE_RDI_VER_1_0, @@ -834,6 +1022,7 @@ static struct cam_vfe_bus_ver2_hw_info vfe170_bus_hw_info = { .ubwc_8bit_threshold_lossy_0 = 0, .ubwc_8bit_threshold_lossy_1 = 0, }, + .stats_data = &stats_170_info, }; struct cam_vfe_hw_info cam_vfe170_hw_info = { diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175.h index edb595e70ad9..2bdbd2435ef0 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175.h +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175.h @@ -131,6 +131,179 @@ struct cam_vfe_top_ver2_reg_offset_module_ctrl zoom_175_reg = { .enable = 0x0000004C, }; + +static struct cam_vfe_bus_ver2_stats_cfg_info stats_175_info = { + .dmi_offset_info = { + .auto_increment = 0x00000100, + .cfg_offset = 0x00000C24, + .addr_offset = 0x00000C28, + .data_hi_offset = 0x00000C2C, + .data_lo_offset = 0x00000C30, + }, + .stats_cfg_offset = { + /* CAM_VFE_BUS_VER2_VFE_OUT_RDI0 */ + { + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_RDI1 */ + { + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_RDI2 */ + { + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_RDI3 */ + { + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_FULL */ + { + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_DS4 */ + { + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_DS16 */ + { + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_RAW_DUMP */ + { + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_FD */ + { + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_PDAF */ + { + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BE */ + { + .res_index = CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BE, + .cfg_offset = 0x00000AB8, + .num_cfg = 0x00000ABC, + .cfg_size = 0x00000AC0, + .is_lut = 0, + .lut = { + .size = -1, + .bank_0 = -1, + .bank_1 = -1, + }, + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BHIST */ + { + .res_index = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BHIST, + .cfg_offset = 0x00000AD4, + .num_cfg = 0x00000AD8, + .cfg_size = 0x00000000, + .is_lut = 1, + .lut = { + .size = 180, + .bank_0 = 0x36, + .bank_1 = 0x37, + }, + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_STATS_TL_BG */ + { + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_STATS_BF */ + { + .res_index = CAM_VFE_BUS_VER2_VFE_OUT_STATS_BF, + .cfg_offset = 0x00000AE4, + .num_cfg = 0x00000000, + .cfg_size = 0x00000000, + .is_lut = 1, + .lut = { + .size = 180, + .bank_0 = 0x40, + .bank_1 = 0x41, + }, + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_STATS_AWB_BG */ + { + .res_index = CAM_VFE_BUS_VER2_VFE_OUT_STATS_AWB_BG, + .cfg_offset = 0x00000BC8, + .num_cfg = 0x00000BCC, + .cfg_size = 0x00000BD0, + .is_lut = 0, + .lut = { + .size = -1, + .bank_0 = -1, + .bank_1 = -1, + }, + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_STATS_BHIST */ + { + .res_index = CAM_VFE_BUS_VER2_VFE_OUT_STATS_BHIST, + .cfg_offset = 0x00000BE4, + .num_cfg = 0x00000BE8, + .cfg_size = 0x00000000, + .is_lut = 1, + .lut = { + .size = 180, + .bank_0 = 0x3A, + .bank_1 = -1, + }, + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_STATS_RS */ + { + .res_index = CAM_VFE_BUS_VER2_VFE_OUT_STATS_RS, + .cfg_offset = 0x00000BEC, + .num_cfg = 0x00000BF0, + .cfg_size = 0x00000BF4, + .is_lut = 0, + .lut = { + .size = -1, + .bank_0 = -1, + .bank_1 = -1, + }, + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_STATS_CS */ + { + .res_index = CAM_VFE_BUS_VER2_VFE_OUT_STATS_CS, + .cfg_offset = 0x00000BF8, + .num_cfg = 0x00000BFC, + .cfg_size = 0x00000C00, + .is_lut = 0, + .lut = { + .size = -1, + .bank_0 = -1, + .bank_1 = -1, + }, + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_STATS_IHIST */ + { + .res_index = CAM_VFE_BUS_VER2_VFE_OUT_STATS_IHIST, + .cfg_offset = 0x00000C04, + .num_cfg = 0x00000C08, + .cfg_size = 0x00000000, + .is_lut = 1, + .lut = { + .size = 180, + .bank_0 = 0x3B, + .bank_1 = 0x3C, + }, + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_FULL_DISP */ + { + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_DS4_DISP */ + { + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_DS16_DISP */ + { + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_2PD */ + { + .res_index = CAM_VFE_BUS_VER2_VFE_OUT_2PD, + .cfg_offset = 0x00000FF0, + .num_cfg = 0x00000FF4, + .cfg_size = 0x00000FF8, + .is_lut = 1, + .lut = { + .size = 180, + .bank_0 = 0x44, + .bank_1 = 0x45, + }, + }, + }, +}; + static struct cam_vfe_top_ver2_reg_offset_common vfe175_top_common_reg = { .hw_version = 0x00000000, .hw_capability = 0x00000004, @@ -196,6 +369,31 @@ static struct cam_vfe_top_ver2_hw_info vfe175_top_hw_info = { NULL, }, }, + .dump_data = { + .num_reg_dump_entries = 2, + .num_lut_dump_entries = 1, + .dmi_cfg = 0xc24, + .dmi_addr = 0xc28, + .dmi_data_path_hi = 0xc2C, + .dmi_data_path_lo = 0xc30, + .reg_entry = { + { + .reg_dump_start = 0x0, + .reg_dump_end = 0x1160, + }, + { + .reg_dump_start = 0x2000, + .reg_dump_end = 0x3978, + }, + }, + .lut_entry = { + { + .lut_word_size = 64, + .lut_bank_sel = 0x40, + .lut_addr_size = 180, + }, + }, + }, .mux_type = { CAM_VFE_CAMIF_VER_2_0, CAM_VFE_RDI_VER_1_0, @@ -1001,6 +1199,7 @@ static struct cam_vfe_bus_ver2_hw_info vfe175_bus_hw_info = { .ubwc_8bit_threshold_lossy_0 = 0x6210022, .ubwc_8bit_threshold_lossy_1 = 0xE0E, }, + .stats_data = &stats_175_info, }; struct cam_vfe_hw_info cam_vfe175_hw_info = { diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175_130.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175_130.h index 3ca5bec71113..0fce972a8410 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175_130.h +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175_130.h @@ -181,6 +181,175 @@ struct cam_vfe_top_ver2_reg_offset_module_ctrl zoom_175_130_reg = { .enable = 0x0000004C, }; +static struct cam_vfe_bus_ver2_stats_cfg_info stats_175_130_info = { + .dmi_offset_info = { + .auto_increment = 0x00000100, + .cfg_offset = 0x00000C24, + .addr_offset = 0x00000C28, + .data_hi_offset = 0x00000C2C, + .data_lo_offset = 0x00000C30, + }, + .stats_cfg_offset = { + /* CAM_VFE_BUS_VER2_VFE_OUT_RDI0 */ + { + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_RDI1 */ + { + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_RDI2 */ + { + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_RDI3 */ + { + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_FULL */ + { + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_DS4 */ + { + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_DS16 */ + { + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_RAW_DUMP */ + { + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_FD */ + { + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_PDAF */ + { + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BE */ + { + .res_index = CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BE, + .cfg_offset = 0x00000AB8, + .num_cfg = 0x00000ABC, + .cfg_size = 0x00000AC0, + .is_lut = 0, + .lut = { + .size = -1, + .bank_0 = -1, + .bank_1 = -1, + }, + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BHIST */ + { + .res_index = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BHIST, + .cfg_offset = 0x00000AD4, + .num_cfg = 0x00000AD8, + .cfg_size = 0x00000000, + .is_lut = 1, + .lut = { + .size = 180, + .bank_0 = 0x36, + .bank_1 = 0x37, + }, + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_STATS_TL_BG */ + { + .res_index = CAM_VFE_BUS_VER2_VFE_OUT_STATS_BF, + .cfg_offset = 0x00000AE4, + .num_cfg = 0x00000000, + .cfg_size = 0x00000000, + .is_lut = 1, + .lut = { + .size = 180, + .bank_0 = 0x40, + .bank_1 = 0x41, + }, + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_STATS_AWB_BG */ + { + .res_index = CAM_VFE_BUS_VER2_VFE_OUT_STATS_AWB_BG, + .cfg_offset = 0x00000BC8, + .num_cfg = 0x00000BCC, + .cfg_size = 0x00000BD0, + .is_lut = 0, + .lut = { + .size = -1, + .bank_0 = -1, + .bank_1 = -1, + }, + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_STATS_BHIST */ + { + .res_index = CAM_VFE_BUS_VER2_VFE_OUT_STATS_BHIST, + .cfg_offset = 0x00000BE4, + .num_cfg = 0x00000BE8, + .cfg_size = 0x00000000, + .is_lut = 1, + .lut = { + .size = 180, + .bank_0 = 0x3A, + .bank_1 = -1, + }, + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_STATS_RS */ + { + .res_index = CAM_VFE_BUS_VER2_VFE_OUT_STATS_RS, + .cfg_offset = 0x00000BEC, + .num_cfg = 0x00000BF0, + .cfg_size = 0x00000BF4, + .is_lut = 0, + .lut = { + .size = -1, + .bank_0 = -1, + .bank_1 = -1, + }, + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_STATS_CS */ + { + .res_index = CAM_VFE_BUS_VER2_VFE_OUT_STATS_CS, + .cfg_offset = 0x00000BF8, + .num_cfg = 0x00000BFC, + .cfg_size = 0x00000C00, + .is_lut = 0, + .lut = { + .size = -1, + .bank_0 = -1, + .bank_1 = -1, + }, + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_STATS_IHIST */ + { + .res_index = CAM_VFE_BUS_VER2_VFE_OUT_STATS_IHIST, + .cfg_offset = 0x00000C04, + .num_cfg = 0x00000C08, + .cfg_size = 0x00000000, + .is_lut = 1, + .lut = { + .size = 180, + .bank_0 = 0x3B, + .bank_1 = 0x3C, + }, + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_FULL_DISP */ + { + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_DS4_DISP */ + { + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_DS16_DISP */ + { + }, + /* CAM_VFE_BUS_VER2_VFE_OUT_2PD */ + { + .res_index = CAM_VFE_BUS_VER2_VFE_OUT_2PD, + .cfg_offset = 0x00000FF0, + .num_cfg = 0x00000FF4, + .cfg_size = 0x00000FF8, + .is_lut = 1, + .lut = { + .size = 180, + .bank_0 = 0x44, + .bank_1 = 0x45, + }, + }, + }, +}; + static struct cam_vfe_top_ver2_reg_offset_common vfe175_130_top_common_reg = { .hw_version = 0x00000000, .hw_capability = 0x00000004, @@ -251,6 +420,31 @@ static struct cam_vfe_top_ver2_hw_info vfe175_130_top_hw_info = { .fe_reg = &vfe175_130_fe_reg, .reg_data = &vfe_175_130_fe_reg_data, }, + .dump_data = { + .num_reg_dump_entries = 2, + .num_lut_dump_entries = 1, + .dmi_cfg = 0xc24, + .dmi_addr = 0xc28, + .dmi_data_path_hi = 0xc2C, + .dmi_data_path_lo = 0xc30, + .reg_entry = { + { + .reg_dump_start = 0x0, + .reg_dump_end = 0x1160, + }, + { + .reg_dump_start = 0x2000, + .reg_dump_end = 0x3978, + }, + }, + .lut_entry = { + { + .lut_word_size = 64, + .lut_bank_sel = 0x40, + .lut_addr_size = 180, + }, + }, + }, .mux_type = { CAM_VFE_CAMIF_VER_2_0, CAM_VFE_RDI_VER_1_0, @@ -1106,6 +1300,7 @@ static struct cam_vfe_bus_ver2_hw_info vfe175_130_bus_hw_info = { .ubwc_8bit_threshold_lossy_0 = 0x6210022, .ubwc_8bit_threshold_lossy_1 = 0xE0E, }, + .stats_data = &stats_175_130_info, }; struct cam_vfe_hw_info cam_vfe175_130_hw_info = { diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c index 8ad4d96dcff8..52de7b10cbe6 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c @@ -34,6 +34,9 @@ static const char drv_name[] = "vfe_bus"; #define CAM_VFE_BUS_IRQ_REG2 2 #define CAM_VFE_BUS_IRQ_MAX 3 +#define CAM_VFE_BUS_LUT_WORD_SIZE_64 1 +#define CAM_VFE_BUS_LUT_WORD_SIZE_32 2 + #define CAM_VFE_BUS_VER2_PAYLOAD_MAX 256 #define CAM_VFE_BUS_SET_DEBUG_REG 0x82 @@ -116,6 +119,8 @@ struct cam_vfe_bus_ver2_common_data { uint32_t num_sec_out; uint32_t addr_no_sync; uint32_t camera_hw_version; + struct cam_vfe_bus_ver2_stats_cfg_info *stats_data; + uint32_t enable_dmi_dump; }; struct cam_vfe_bus_ver2_wm_resource_data { @@ -1339,20 +1344,58 @@ static int cam_vfe_bus_handle_wm_done_bottom_half(void *wm_node, return rc; } +static void cam_vfe_bus_dump_dmi_reg( + void __iomem *mem_base, + uint32_t lut_word_size, + uint32_t lut_size, + uint32_t lut_bank_sel, + struct cam_vfe_bus_ver2_dmi_offset_common dmi_cfg) +{ + uint32_t i; + uint32_t val_0; + uint32_t val_1; + + val_0 = dmi_cfg.auto_increment | lut_bank_sel; + cam_io_w_mb(val_0, mem_base + dmi_cfg.cfg_offset); + cam_io_w_mb(0, mem_base + dmi_cfg.addr_offset); + for (i = 0; i < lut_size; i++) { + if (lut_word_size == CAM_VFE_BUS_LUT_WORD_SIZE_64) { + val_0 = cam_io_r_mb(mem_base + + dmi_cfg.data_lo_offset); + val_1 = cam_io_r_mb(mem_base + + dmi_cfg.data_hi_offset); + CAM_INFO(CAM_ISP, + "Bank%d : 0x%x, LO: 0x%x, HI:0x%x", + lut_bank_sel, i, val_0, val_1); + } else { + val_0 = cam_io_r_mb(mem_base + + dmi_cfg.data_lo_offset); + CAM_INFO(CAM_ISP, "Bank%d : 0x%x, LO: 0x%x", + lut_bank_sel, i, val_0); + } + } + cam_io_w_mb(0, mem_base + dmi_cfg.cfg_offset); + cam_io_w_mb(0, mem_base + dmi_cfg.addr_offset); +} static int cam_vfe_bus_err_bottom_half(void *ctx_priv, void *evt_payload_priv) { struct cam_vfe_bus_irq_evt_payload *evt_payload; struct cam_vfe_bus_ver2_common_data *common_data; + struct cam_vfe_bus_ver2_stats_cfg_offset *stats_cfg; + struct cam_vfe_bus_ver2_dmi_offset_common dmi_cfg; uint32_t val = 0; + uint32_t enable_dmi_dump; if (!ctx_priv || !evt_payload_priv) return -EINVAL; evt_payload = evt_payload_priv; common_data = evt_payload->ctx; - + enable_dmi_dump = evt_payload->enable_dump; + stats_cfg = common_data->stats_data->stats_cfg_offset; + dmi_cfg = common_data->stats_data->dmi_offset_info; val = evt_payload->debug_status_0; CAM_ERR(CAM_ISP, "Bus Violation: debug_status_0 = 0x%x", val); @@ -1386,35 +1429,202 @@ static int cam_vfe_bus_err_bottom_half(void *ctx_priv, if (val & 0x0200) CAM_INFO(CAM_ISP, "RAW DUMP violation"); - if (val & 0x0400) + if (val & 0x0400) { CAM_INFO(CAM_ISP, "PDAF violation"); + if (enable_dmi_dump & CAM_VFE_BUS_ENABLE_DMI_DUMP) { + + cam_vfe_bus_dump_dmi_reg( + common_data->mem_base, + CAM_VFE_BUS_LUT_WORD_SIZE_64, + stats_cfg[ + CAM_VFE_BUS_VER2_VFE_OUT_PDAF].lut.size, + stats_cfg[ + CAM_VFE_BUS_VER2_VFE_OUT_PDAF].lut.bank_0, + dmi_cfg); + } + if (enable_dmi_dump & CAM_VFE_BUS_ENABLE_STATS_REG_DUMP) { + CAM_INFO(CAM_ISP, "RGN offset cfg 0x%08x", + cam_io_r_mb(common_data->mem_base + + stats_cfg[ + CAM_VFE_BUS_VER2_VFE_OUT_PDAF].cfg_offset)); + } + } - if (val & 0x0800) + if (val & 0x0800) { CAM_INFO(CAM_ISP, "STATs HDR BE violation"); + if (enable_dmi_dump & CAM_VFE_BUS_ENABLE_STATS_REG_DUMP) { + + CAM_INFO(CAM_ISP, "RGN offset cfg 0x%08x", + cam_io_r_mb(common_data->mem_base + + stats_cfg[ + CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BE].cfg_offset)); - if (val & 0x01000) + CAM_INFO(CAM_ISP, "RGN num cfg 0x%08x", + cam_io_r_mb(common_data->mem_base + + stats_cfg[ + CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BE].num_cfg)); + } + } + + if (val & 0x01000) { CAM_INFO(CAM_ISP, "STATs HDR BHIST violation"); + if (enable_dmi_dump & CAM_VFE_BUS_ENABLE_DMI_DUMP) { + + cam_vfe_bus_dump_dmi_reg( + common_data->mem_base, + CAM_VFE_BUS_LUT_WORD_SIZE_64, + stats_cfg[ + CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BHIST].lut.size, + stats_cfg[ + CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BHIST].lut.bank_0, + dmi_cfg); + + cam_vfe_bus_dump_dmi_reg( + common_data->mem_base, + CAM_VFE_BUS_LUT_WORD_SIZE_64, + stats_cfg[ + CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BHIST].lut.size, + stats_cfg[ + CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BHIST].lut.bank_1, + dmi_cfg); + } + if (enable_dmi_dump & CAM_VFE_BUS_ENABLE_STATS_REG_DUMP) { + + CAM_INFO(CAM_ISP, "RGN offset cfg 0x%08x", + cam_io_r_mb(common_data->mem_base + + stats_cfg[ + CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BHIST].cfg_offset)); + + CAM_INFO(CAM_ISP, "RGN num cfg 0x%08x", + cam_io_r_mb(common_data->mem_base + + stats_cfg[ + CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BHIST].num_cfg)); + } + } if (val & 0x02000) CAM_INFO(CAM_ISP, "STATs TINTLESS BG violation"); - if (val & 0x04000) + if (val & 0x04000) { CAM_INFO(CAM_ISP, "STATs BF violation"); - - if (val & 0x08000) + if (enable_dmi_dump & CAM_VFE_BUS_ENABLE_DMI_DUMP) { + + cam_vfe_bus_dump_dmi_reg( + common_data->mem_base, + CAM_VFE_BUS_LUT_WORD_SIZE_64, + stats_cfg[ + CAM_VFE_BUS_VER2_VFE_OUT_STATS_BF].lut.size, + stats_cfg[ + CAM_VFE_BUS_VER2_VFE_OUT_STATS_BF].lut.bank_0, + dmi_cfg); + + cam_vfe_bus_dump_dmi_reg( + common_data->mem_base, + CAM_VFE_BUS_LUT_WORD_SIZE_64, + stats_cfg[ + CAM_VFE_BUS_VER2_VFE_OUT_STATS_BF].lut.size, + stats_cfg[ + CAM_VFE_BUS_VER2_VFE_OUT_STATS_BF].lut.bank_1, + dmi_cfg); + } + if (enable_dmi_dump & CAM_VFE_BUS_ENABLE_STATS_REG_DUMP) { + CAM_INFO(CAM_ISP, "RGN offset cfg 0x%08x", + cam_io_r_mb(common_data->mem_base + + stats_cfg[ + CAM_VFE_BUS_VER2_VFE_OUT_STATS_BF].cfg_offset)); + } + } + + if (val & 0x08000) { CAM_INFO(CAM_ISP, "STATs AWB BG UBWC violation"); + if (enable_dmi_dump & CAM_VFE_BUS_ENABLE_STATS_REG_DUMP) { - if (val & 0x010000) + CAM_INFO(CAM_ISP, "RGN offset cfg 0x%08x", + cam_io_r_mb(common_data->mem_base + + stats_cfg[ + CAM_VFE_BUS_VER2_VFE_OUT_STATS_AWB_BG].cfg_offset)); + + CAM_INFO(CAM_ISP, "RGN num cfg 0x%08x", + cam_io_r_mb(common_data->mem_base + + stats_cfg[ + CAM_VFE_BUS_VER2_VFE_OUT_STATS_AWB_BG].num_cfg)); + } + } + + if (val & 0x010000) { CAM_INFO(CAM_ISP, "STATs BHIST violation"); + if (enable_dmi_dump & CAM_VFE_BUS_ENABLE_DMI_DUMP) { + + cam_vfe_bus_dump_dmi_reg( + common_data->mem_base, + CAM_VFE_BUS_LUT_WORD_SIZE_64, + stats_cfg[ + CAM_VFE_BUS_VER2_VFE_OUT_STATS_BHIST].lut.size, + stats_cfg[ + CAM_VFE_BUS_VER2_VFE_OUT_STATS_BHIST].lut.bank_0, + dmi_cfg); + } + if (enable_dmi_dump & CAM_VFE_BUS_ENABLE_STATS_REG_DUMP) { - if (val & 0x020000) + CAM_INFO(CAM_ISP, "RGN offset cfg 0x%08x", + cam_io_r_mb(common_data->mem_base + + stats_cfg[ + CAM_VFE_BUS_VER2_VFE_OUT_STATS_BHIST].cfg_offset)); + + CAM_INFO(CAM_ISP, "RGN num cfg 0x%08x", + cam_io_r_mb(common_data->mem_base + + stats_cfg[ + CAM_VFE_BUS_VER2_VFE_OUT_STATS_BHIST].num_cfg)); + } + } + + if (val & 0x020000) { CAM_INFO(CAM_ISP, "STATs RS violation"); + if (enable_dmi_dump & CAM_VFE_BUS_ENABLE_STATS_REG_DUMP) { + + CAM_INFO(CAM_ISP, "RGN offset cfg 0x%08x", + cam_io_r_mb(common_data->mem_base + + stats_cfg[ + CAM_VFE_BUS_VER2_VFE_OUT_STATS_RS].cfg_offset)); - if (val & 0x040000) + CAM_INFO(CAM_ISP, "RGN num cfg 0x%08x", + cam_io_r_mb(common_data->mem_base + + stats_cfg[ + CAM_VFE_BUS_VER2_VFE_OUT_STATS_RS].num_cfg)); + } + } + + if (val & 0x040000) { CAM_INFO(CAM_ISP, "STATs CS violation"); + if (enable_dmi_dump & CAM_VFE_BUS_ENABLE_STATS_REG_DUMP) { + + CAM_INFO(CAM_ISP, "RGN offset cfg 0x%08x", + cam_io_r_mb(common_data->mem_base + + stats_cfg[ + CAM_VFE_BUS_VER2_VFE_OUT_STATS_CS].cfg_offset)); + + CAM_INFO(CAM_ISP, "RGN num cfg 0x%08x", + cam_io_r_mb(common_data->mem_base + + stats_cfg[ + CAM_VFE_BUS_VER2_VFE_OUT_STATS_CS].num_cfg)); + } + } - if (val & 0x080000) + if (val & 0x080000) { CAM_INFO(CAM_ISP, "STATs IHIST violation"); + if (enable_dmi_dump & CAM_VFE_BUS_ENABLE_STATS_REG_DUMP) { + + CAM_INFO(CAM_ISP, "RGN offset cfg 0x%08x", + cam_io_r_mb(common_data->mem_base + + stats_cfg[ + CAM_VFE_BUS_VER2_VFE_OUT_STATS_IHIST].cfg_offset)); + + CAM_INFO(CAM_ISP, "RGN num cfg 0x%08x", + cam_io_r_mb(common_data->mem_base + + stats_cfg[ + CAM_VFE_BUS_VER2_VFE_OUT_STATS_IHIST].num_cfg)); + } + } if (val & 0x0100000) CAM_INFO(CAM_ISP, "DISP Y 1:1 UBWC violation"); @@ -2504,6 +2714,7 @@ static int cam_vfe_bus_error_irq_top_half(uint32_t evt_id, evt_payload->debug_status_0 = cam_io_r_mb( bus_priv->common_data.mem_base + bus_priv->common_data.common_reg->debug_status_0); + evt_payload->enable_dump = bus_priv->common_data.enable_dmi_dump; th_payload->evt_payload_priv = evt_payload; @@ -3319,6 +3530,7 @@ static int cam_vfe_bus_process_cmd( { int rc = -EINVAL; struct cam_vfe_bus_ver2_priv *bus_priv; + struct cam_isp_hw_get_cmd_update *cmd_update; if (!priv || !cmd_args) { CAM_ERR_RATE_LIMIT(CAM_ISP, "Invalid input arguments"); @@ -3356,6 +3568,12 @@ static int cam_vfe_bus_process_cmd( case CAM_ISP_HW_CMD_UBWC_UPDATE: rc = cam_vfe_bus_update_ubwc_config(cmd_args); break; + case CAM_ISP_HW_CMD_SET_STATS_DMI_DUMP: + bus_priv = (struct cam_vfe_bus_ver2_priv *) priv; + cmd_update = (struct cam_isp_hw_get_cmd_update *) cmd_args; + bus_priv->common_data.enable_dmi_dump = + *((uint32_t *)cmd_update->data); + break; default: CAM_ERR_RATE_LIMIT(CAM_ISP, "Invalid camif process command:%d", cmd_type); @@ -3427,6 +3645,7 @@ int cam_vfe_bus_ver2_init( bus_priv->common_data.addr_no_sync = CAM_VFE_BUS_ADDR_NO_SYNC_DEFAULT_VAL; bus_priv->common_data.camera_hw_version = camera_hw_version; + bus_priv->common_data.stats_data = ver2_hw_info->stats_data; mutex_init(&bus_priv->common_data.bus_mutex); diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.h index 39d8fa561590..fb52335ae0d5 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.h +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.h @@ -18,6 +18,9 @@ #define CAM_VFE_BUS_VER2_MAX_CLIENTS 24 +#define CAM_VFE_BUS_ENABLE_DMI_DUMP BIT(0) +#define CAM_VFE_BUS_ENABLE_STATS_REG_DUMP BIT(1) + enum cam_vfe_bus_ver2_vfe_core_id { CAM_VFE_BUS_VER2_VFE_CORE_0, CAM_VFE_BUS_VER2_VFE_CORE_1, @@ -67,6 +70,36 @@ enum cam_vfe_bus_ver2_vfe_out_type { CAM_VFE_BUS_VER2_VFE_OUT_MAX, }; +struct cam_vfe_bus_ver2_dmi_lut_bank_info { + uint32_t size; + uint32_t bank_0; + uint32_t bank_1; +}; + +struct cam_vfe_bus_ver2_stats_cfg_offset { + uint32_t res_index; + uint32_t cfg_offset; + uint32_t num_cfg; + uint32_t cfg_size; + uint32_t is_lut; + struct cam_vfe_bus_ver2_dmi_lut_bank_info lut; +}; + +struct cam_vfe_bus_ver2_dmi_offset_common { + uint32_t auto_increment; + uint32_t cfg_offset; + uint32_t addr_offset; + uint32_t data_hi_offset; + uint32_t data_lo_offset; +}; + +struct cam_vfe_bus_ver2_stats_cfg_info { + struct cam_vfe_bus_ver2_dmi_offset_common + dmi_offset_info; + struct cam_vfe_bus_ver2_stats_cfg_offset + stats_cfg_offset[CAM_VFE_BUS_VER2_VFE_OUT_MAX]; +}; + /* * struct cam_vfe_bus_ver2_reg_offset_common: * @@ -211,6 +244,7 @@ struct cam_vfe_bus_ver2_hw_info { struct cam_vfe_bus_ver2_vfe_out_hw_info vfe_out_hw_info[CAM_VFE_BUS_VER2_VFE_OUT_MAX]; struct cam_vfe_bus_ver2_reg_data reg_data; + struct cam_vfe_bus_ver2_stats_cfg_info *stats_data; }; /* diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c index 0461b0820b4f..cfc67c676cee 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c @@ -28,6 +28,7 @@ struct cam_vfe_top_ver2_common_data { struct cam_hw_soc_info *soc_info; struct cam_hw_intf *hw_intf; struct cam_vfe_top_ver2_reg_offset_common *common_reg; + struct cam_vfe_top_dump_data *dump_data; }; struct cam_vfe_top_ver2_priv { @@ -467,6 +468,117 @@ static int cam_vfe_get_irq_register_dump( return 0; } +static int cam_vfe_hw_dump( + struct cam_vfe_top_ver2_priv *top_priv, + void *cmd_args, + uint32_t arg_size) +{ + struct cam_isp_hw_dump_args *dump_args = + (struct cam_isp_hw_dump_args *)cmd_args; + struct cam_hw_soc_info *soc_info; + uint32_t i, j; + struct cam_vfe_top_dump_data *dump_data; + uint32_t reg_dump_size = 0, lut_dump_size = 0; + uint32_t reg_start_offset; + uint32_t val = 0; + uint32_t num_reg; + void __iomem *reg_base; + uint32_t *addr, *start; + struct cam_isp_hw_dump_header *hdr; + uint8_t *dst; + + if (!dump_args->cpu_addr || !dump_args->buf_len) { + CAM_ERR(CAM_ISP, + "lnvalid addr len %zu", dump_args->buf_len); + return -EINVAL; + } + dump_data = top_priv->common_data.dump_data; + soc_info = top_priv->common_data.soc_info; + + /*Dump registers */ + for (i = 0; i < dump_data->num_reg_dump_entries; i++) + reg_dump_size += (dump_data->reg_entry[i].reg_dump_end - + dump_data->reg_entry[i].reg_dump_start); + /* + * We dump the offset as well, so the total size dumped becomes + * multiplied by 2 + */ + reg_dump_size *= 2; + for (i = 0; i < dump_data->num_lut_dump_entries; i++) + lut_dump_size += ((dump_data->lut_entry[i].lut_addr_size) * + (dump_data->lut_entry[i].lut_word_size/8)); + + if ((dump_args->buf_len - dump_args->offset) < + (lut_dump_size + reg_dump_size + + sizeof(struct cam_isp_hw_dump_header))) { + CAM_ERR(CAM_ISP, "Dump buffer exhaust"); + return 0; + } + dst = (char *)dump_args->cpu_addr + dump_args->offset; + hdr = (struct cam_isp_hw_dump_header *)dst; + hdr->word_size = sizeof(uint32_t); + snprintf(hdr->tag, CAM_ISP_HW_DUMP_TAG_MAX_LEN, "VFE_REG:"); + addr = (uint32_t *)(dst + sizeof(struct cam_isp_hw_dump_header)); + start = addr; + *addr++ = soc_info->index; + for (i = 0; i < dump_data->num_reg_dump_entries; i++) { + num_reg = (dump_data->reg_entry[i].reg_dump_end - + dump_data->reg_entry[i].reg_dump_start)/4; + reg_start_offset = dump_data->reg_entry[i].reg_dump_start; + reg_base = soc_info->reg_map[0].mem_base + reg_start_offset; + for (j = 0; j < num_reg; j++) { + addr[0] = soc_info->mem_block[0]->start + + reg_start_offset + (j*4); + addr[1] = cam_io_r(reg_base + (j*4)); + addr += 2; + } + } + hdr->size = hdr->word_size * (addr - start); + dump_args->offset += hdr->size + + sizeof(struct cam_isp_hw_dump_header); + + /*dump LUT*/ + for (i = 0; i < dump_data->num_lut_dump_entries; i++) { + + dst = (char *)dump_args->cpu_addr + dump_args->offset; + hdr = (struct cam_isp_hw_dump_header *)dst; + snprintf(hdr->tag, CAM_ISP_HW_DUMP_TAG_MAX_LEN, "LUT_REG:"); + hdr->word_size = dump_data->lut_entry[i].lut_word_size/8; + addr = (uint32_t *)(dst + + sizeof(struct cam_isp_hw_dump_header)); + start = addr; + *addr++ = dump_data->lut_entry[i].lut_bank_sel; + *addr++ = soc_info->index; + val = 0x100 | dump_data->lut_entry[i].lut_bank_sel; + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + dump_data->dmi_cfg); + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + dump_data->dmi_addr); + for (j = 0; j < dump_data->lut_entry[i].lut_addr_size; + j++) { + if (dump_data->lut_entry[i].lut_word_size == 64) { + addr[0] = cam_io_r( + soc_info->reg_map[0].mem_base + + dump_data->dmi_data_path_lo); + addr[1] = cam_io_r( + soc_info->reg_map[0].mem_base + + dump_data->dmi_data_path_hi); + addr += 2; + } else { + *addr = cam_io_r( + soc_info->reg_map[0].mem_base + + dump_data->dmi_data_path_lo); + addr++; + } + } + hdr->size = hdr->word_size * (addr - start); + dump_args->offset += hdr->size + + sizeof(struct cam_isp_hw_dump_header); + } + CAM_DBG(CAM_ISP, "offset %d", dump_args->offset); + return 0; +} + int cam_vfe_top_get_hw_caps(void *device_priv, void *get_hw_cap_args, uint32_t arg_size) { @@ -760,6 +872,10 @@ int cam_vfe_top_process_cmd(void *device_priv, uint32_t cmd_type, rc = cam_vfe_top_fps_config(top_priv, cmd_args, arg_size); break; + case CAM_ISP_HW_CMD_DUMP_HW: + rc = cam_vfe_hw_dump(top_priv, + cmd_args, arg_size); + break; default: rc = -EINVAL; CAM_ERR(CAM_ISP, "Error! Invalid cmd:%d", cmd_type); @@ -903,6 +1019,7 @@ int cam_vfe_top_ver2_init( top_priv->common_data.soc_info = soc_info; top_priv->common_data.hw_intf = hw_intf; top_priv->common_data.common_reg = ver2_hw_info->common_reg; + top_priv->common_data.dump_data = &ver2_hw_info->dump_data; return rc; diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.h index 86f0d8c26ff5..7cfc023fed12 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.h +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.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 @@ -20,6 +20,10 @@ #define CAM_VFE_TOP_VER2_MUX_MAX 6 +#define CAM_VFE_MAX_REG_DUMP_ENTRIES 5 + +#define CAM_VFE_MAX_LUT_DUMP_ENTRIES 6 + enum cam_vfe_top_ver2_module_type { CAM_VFE_TOP_VER2_MODULE_LENS, CAM_VFE_TOP_VER2_MODULE_STATS, @@ -34,6 +38,30 @@ struct cam_vfe_top_ver2_reg_offset_module_ctrl { uint32_t enable; }; +struct cam_vfe_top_reg_dump_entry { + uint32_t reg_dump_start; + uint32_t reg_dump_end; +}; + +struct cam_vfe_top_lut_dump_entry { + uint32_t lut_word_size; + uint32_t lut_bank_sel; + uint32_t lut_addr_size; +}; + +struct cam_vfe_top_dump_data { + uint32_t num_reg_dump_entries; + uint32_t num_lut_dump_entries; + uint32_t dmi_cfg; + uint32_t dmi_addr; + uint32_t dmi_data_path_hi; + uint32_t dmi_data_path_lo; + struct cam_vfe_top_reg_dump_entry + reg_entry[CAM_VFE_MAX_REG_DUMP_ENTRIES]; + struct cam_vfe_top_lut_dump_entry + lut_entry[CAM_VFE_MAX_LUT_DUMP_ENTRIES]; +}; + struct cam_vfe_top_ver2_reg_offset_common { uint32_t hw_version; uint32_t hw_capability; @@ -57,6 +85,7 @@ struct cam_vfe_top_ver2_hw_info { struct cam_vfe_camif_lite_ver2_hw_info camif_lite_hw_info; struct cam_vfe_rdi_ver2_hw_info rdi_hw_info; struct cam_vfe_fe_ver1_hw_info fe_hw_info; + struct cam_vfe_top_dump_data dump_data; uint32_t mux_type[CAM_VFE_TOP_VER2_MUX_MAX]; }; diff --git a/drivers/media/platform/msm/camera/cam_jpeg/cam_jpeg_context.c b/drivers/media/platform/msm/camera/cam_jpeg/cam_jpeg_context.c index 1c910621b655..e151a7ebd74f 100644 --- a/drivers/media/platform/msm/camera/cam_jpeg/cam_jpeg_context.c +++ b/drivers/media/platform/msm/camera/cam_jpeg/cam_jpeg_context.c @@ -91,6 +91,18 @@ static int __cam_jpeg_ctx_release_dev_in_acquired(struct cam_context *ctx, return rc; } +static int __cam_jpeg_ctx_dump_dev_in_acquired(struct cam_context *ctx, + struct cam_dump_req_cmd *cmd) +{ + int rc; + + rc = cam_context_dump_dev_to_hw(ctx, cmd); + if (rc) + CAM_ERR(CAM_ICP, "Failed to dump device, rc=%d", rc); + + return rc; +} + static int __cam_jpeg_ctx_flush_dev_in_acquired(struct cam_context *ctx, struct cam_flush_dev_cmd *cmd) { @@ -153,6 +165,7 @@ static struct cam_ctx_ops .config_dev = __cam_jpeg_ctx_config_dev_in_acquired, .stop_dev = __cam_jpeg_ctx_stop_dev_in_acquired, .flush_dev = __cam_jpeg_ctx_flush_dev_in_acquired, + .dump_dev = __cam_jpeg_ctx_dump_dev_in_acquired, }, .crm_ops = { }, .irq_ops = __cam_jpeg_ctx_handle_buf_done_in_acquired, diff --git a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c index 696566d6a37a..1a995646a947 100644 --- a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c +++ b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c @@ -492,7 +492,7 @@ static int cam_jpeg_mgr_process_cmd(void *priv, void *data) rc); goto rel_cpu_buf; } - + cam_common_util_get_curr_timestamp(&p_cfg_req->submit_timestamp); if (cam_mem_put_cpu_buf( config_args->hw_update_entries[CAM_JPEG_CHBASE].handle)) CAM_WARN(CAM_JPEG, "unable to put info for cmd buf: 0x%x", @@ -1043,6 +1043,116 @@ static int cam_jpeg_mgr_hw_flush(void *hw_mgr_priv, void *flush_hw_args) return rc; } +static int cam_jpeg_mgr_hw_dump(void *hw_mgr_priv, void *dump_hw_args) +{ + int rc = 0; + struct cam_hw_dump_args *dump_args = + (struct cam_hw_dump_args *)dump_hw_args; + struct cam_jpeg_hw_mgr *hw_mgr = hw_mgr_priv; + struct cam_jpeg_hw_ctx_data *ctx_data = NULL; + struct cam_jpeg_hw_cfg_req *p_cfg_req = NULL; + struct timeval cur_time; + uint32_t dev_type; + uint64_t diff; + uint64_t *addr, *start; + char *dst; + struct cam_jpeg_hw_dump_header *hdr; + uint32_t min_len, remain_len; + struct cam_jpeg_hw_dump_args jpeg_dump_args; + + if (!hw_mgr || !dump_args || !dump_args->ctxt_to_hw_map) { + CAM_ERR(CAM_JPEG, "Invalid args"); + return -EINVAL; + } + mutex_lock(&hw_mgr->hw_mgr_mutex); + ctx_data = (struct cam_jpeg_hw_ctx_data *)dump_args->ctxt_to_hw_map; + if (!ctx_data->in_use) { + CAM_ERR(CAM_JPEG, "ctx is not in use"); + mutex_unlock(&hw_mgr->hw_mgr_mutex); + return -EINVAL; + } + dev_type = ctx_data->jpeg_dev_acquire_info.dev_type; + if (true == hw_mgr->device_in_use[dev_type][0]) { + p_cfg_req = hw_mgr->dev_hw_cfg_args[dev_type][0]; + if (p_cfg_req && p_cfg_req->req_id == + (uintptr_t)dump_args->request_id) + goto hw_dump; + } + mutex_unlock(&hw_mgr->hw_mgr_mutex); + return 0; + +hw_dump: + cam_common_util_get_curr_timestamp(&cur_time); + diff = cam_common_util_get_time_diff(&cur_time, + &p_cfg_req->submit_timestamp); + if (diff < CAM_JPEG_RESPONSE_TIME_THRESHOLD) { + CAM_INFO(CAM_JPEG, + "No error req %lld %ld:%06ld %ld:%06ld", + dump_args->request_id, + p_cfg_req->submit_timestamp.tv_sec, + p_cfg_req->submit_timestamp.tv_usec, + cur_time.tv_sec, + cur_time.tv_usec); + mutex_unlock(&hw_mgr->hw_mgr_mutex); + return 0; + } + CAM_INFO(CAM_JPEG, + "Error req %lld %ld:%06ld %ld:%06ld", + dump_args->request_id, + p_cfg_req->submit_timestamp.tv_sec, + p_cfg_req->submit_timestamp.tv_usec, + cur_time.tv_sec, + cur_time.tv_usec); + rc = cam_mem_get_cpu_buf(dump_args->buf_handle, + &jpeg_dump_args.cpu_addr, &jpeg_dump_args.buf_len); + if (!jpeg_dump_args.cpu_addr || !jpeg_dump_args.buf_len || rc) { + CAM_ERR(CAM_JPEG, + "lnvalid addr %u len %zu rc %d", + dump_args->buf_handle, jpeg_dump_args.buf_len, rc); + goto end; + } + remain_len = jpeg_dump_args.buf_len - dump_args->offset; + min_len = 2 * (sizeof(struct cam_jpeg_hw_dump_header) + + CAM_JPEG_HW_DUMP_TAG_MAX_LEN); + if (remain_len < min_len) { + CAM_ERR(CAM_JPEG, "dump buffer exhaust %d %d", + remain_len, min_len); + goto end; + } + dst = (char *)jpeg_dump_args.cpu_addr + dump_args->offset; + hdr = (struct cam_jpeg_hw_dump_header *)dst; + snprintf(hdr->tag, CAM_JPEG_HW_DUMP_TAG_MAX_LEN, + "JPEG_REQ:"); + hdr->word_size = sizeof(uint64_t); + addr = (uint64_t *)(dst + sizeof(struct cam_jpeg_hw_dump_header)); + start = addr; + *addr++ = dump_args->request_id; + *addr++ = p_cfg_req->submit_timestamp.tv_sec; + *addr++ = p_cfg_req->submit_timestamp.tv_usec; + *addr++ = cur_time.tv_sec; + *addr++ = cur_time.tv_usec; + hdr->size = hdr->word_size * (addr - start); + dump_args->offset += hdr->size + + sizeof(struct cam_jpeg_hw_dump_header); + jpeg_dump_args.request_id = dump_args->request_id; + jpeg_dump_args.offset = dump_args->offset; + + if (hw_mgr->devices[dev_type][0]->hw_ops.process_cmd) { + rc = hw_mgr->devices[dev_type][0]->hw_ops.process_cmd( + hw_mgr->devices[dev_type][0]->hw_priv, + CAM_JPEG_CMD_HW_DUMP, + &jpeg_dump_args, sizeof(jpeg_dump_args)); + } + dump_args->offset = jpeg_dump_args.offset; +end: + rc = cam_mem_put_cpu_buf(dump_args->buf_handle); + if (rc) + CAM_ERR(CAM_JPEG, "Cpu put failed handle %u", + dump_args->buf_handle); + mutex_unlock(&hw_mgr->hw_mgr_mutex); + return rc; +} + static int cam_jpeg_mgr_hw_stop(void *hw_mgr_priv, void *stop_hw_args) { int rc; @@ -1564,6 +1674,7 @@ int cam_jpeg_hw_mgr_init(struct device_node *of_node, uint64_t *hw_mgr_hdl, hw_mgr_intf->hw_flush = cam_jpeg_mgr_hw_flush; hw_mgr_intf->hw_stop = cam_jpeg_mgr_hw_stop; hw_mgr_intf->hw_cmd = cam_jpeg_mgr_cmd; + hw_mgr_intf->hw_dump = cam_jpeg_mgr_hw_dump; mutex_init(&g_jpeg_hw_mgr.hw_mgr_mutex); spin_lock_init(&g_jpeg_hw_mgr.hw_mgr_lock); diff --git a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.h b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.h index 82022ec24a77..2dc11dfa0746 100644 --- a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.h +++ b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/cam_jpeg_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 @@ -28,6 +28,12 @@ #define CAM_JPEG_WORKQ_TASK_MSG_TYPE 2 #define CAM_JPEG_HW_CFG_Q_MAX 50 +/* + * Response time threshold in ms beyond which a request is not expected + * to be with JPEG hw + */ +#define CAM_JPEG_RESPONSE_TIME_THRESHOLD 100000 + /** * struct cam_jpeg_process_frame_work_data_t * @@ -76,12 +82,14 @@ struct cam_jpeg_hw_cdm_info_t { * @hw_cfg_args: Hw config args * @dev_type: Dev type for cfg request * @req_id: Request Id + * @submit_timestamp: Timestamp of submitting request */ struct cam_jpeg_hw_cfg_req { struct list_head list; struct cam_hw_config_args hw_cfg_args; uint32_t dev_type; uintptr_t req_id; + struct timeval submit_timestamp; }; /** diff --git a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/include/cam_jpeg_hw_intf.h b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/include/cam_jpeg_hw_intf.h index 48d8f14d243d..06fafae792f1 100644 --- a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/include/cam_jpeg_hw_intf.h +++ b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/include/cam_jpeg_hw_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 @@ -23,6 +23,8 @@ #define JPEG_VOTE 640000000 +#define CAM_JPEG_HW_DUMP_TAG_MAX_LEN 32 + enum cam_jpeg_hw_type { CAM_JPEG_DEV_ENC, CAM_JPEG_DEV_DMA, @@ -35,9 +37,23 @@ struct cam_jpeg_set_irq_cb { uint32_t b_set_cb; }; +struct cam_jpeg_hw_dump_args { + uintptr_t cpu_addr; + uint64_t offset; + uint64_t request_id; + size_t buf_len; +}; + +struct cam_jpeg_hw_dump_header { + char tag[CAM_JPEG_HW_DUMP_TAG_MAX_LEN]; + uint64_t size; + uint32_t word_size; +}; + enum cam_jpeg_cmd_type { CAM_JPEG_CMD_CDM_CFG, CAM_JPEG_CMD_SET_IRQ_CB, + CAM_JPEG_CMD_HW_DUMP, CAM_JPEG_CMD_MAX, }; diff --git a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_enc_hw/cam_jpeg_enc_hw_info_ver_4_2_0.h b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_enc_hw/cam_jpeg_enc_hw_info_ver_4_2_0.h index c6017afd3c37..8cdf59b70ef4 100644 --- a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_enc_hw/cam_jpeg_enc_hw_info_ver_4_2_0.h +++ b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_enc_hw/cam_jpeg_enc_hw_info_ver_4_2_0.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 @@ -73,6 +73,10 @@ static struct cam_jpeg_enc_device_hw_info cam_jpeg_enc_hw_info = { .resetdone = CAM_JPEG_HW_MASK_COMP_RESET_ACK, .iserror = CAM_JPEG_HW_MASK_COMP_ERR, .stopdone = CAM_JPEG_HW_IRQ_STATUS_STOP_DONE_MASK, + }, + .reg_dump = { + .start_offset = 0x0, + .end_offset = 0x33C, } }; diff --git a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.c b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.c index 225f859674f1..54dd62c44f67 100644 --- a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.c +++ b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.c @@ -410,6 +410,64 @@ int cam_jpeg_enc_stop_hw(void *data, return 0; } +int cam_jpeg_enc_hw_dump( + struct cam_hw_info *jpeg_enc_dev, + struct cam_jpeg_hw_dump_args *dump_args) +{ + + struct cam_hw_soc_info *soc_info = NULL; + int i; + char *dst; + uint32_t *addr, *start; + struct cam_jpeg_hw_dump_header *hdr; + uint32_t num_reg, min_len, remain_len, reg_start_offset; + struct cam_jpeg_enc_device_core_info *core_info; + struct cam_jpeg_enc_device_hw_info *hw_info = NULL; + + soc_info = &jpeg_enc_dev->soc_info; + core_info = (struct cam_jpeg_enc_device_core_info *) + jpeg_enc_dev->core_info; + hw_info = core_info->jpeg_enc_hw_info; + spin_lock(&jpeg_enc_dev->hw_lock); + if (jpeg_enc_dev->hw_state == CAM_HW_STATE_POWER_DOWN) { + CAM_ERR(CAM_JPEG, "JPEG HW is in off state"); + spin_unlock(&jpeg_enc_dev->hw_lock); + return -EINVAL; + } + spin_unlock(&jpeg_enc_dev->hw_lock); + remain_len = dump_args->buf_len - dump_args->offset; + min_len = 2 * (sizeof(struct cam_jpeg_hw_dump_header) + + CAM_JPEG_HW_DUMP_TAG_MAX_LEN) + + soc_info->reg_map[0].size; + if (remain_len < min_len) { + CAM_ERR(CAM_JPEG, "dump buffer exhaust %d %d", + remain_len, min_len); + return 0; + } + dst = (char *)dump_args->cpu_addr + dump_args->offset; + hdr = (struct cam_jpeg_hw_dump_header *)dst; + snprintf(hdr->tag, CAM_JPEG_HW_DUMP_TAG_MAX_LEN, + "JPEG_REG:"); + hdr->word_size = sizeof(uint32_t); + addr = (uint32_t *)(dst + sizeof(struct cam_jpeg_hw_dump_header)); + start = addr; + *addr++ = soc_info->index; + num_reg = (hw_info->reg_dump.end_offset - + hw_info->reg_dump.start_offset)/4; + reg_start_offset = hw_info->reg_dump.start_offset; + for (i = 0; i < num_reg; i++) { + *addr++ = soc_info->mem_block[0]->start + + reg_start_offset + i*4; + *addr++ = cam_io_r(soc_info->reg_map[0].mem_base + (i*4)); + } + hdr->size = hdr->word_size * (addr - start); + dump_args->offset += hdr->size + + sizeof(struct cam_jpeg_hw_dump_header); + CAM_DBG(CAM_JPEG, "offset %d", dump_args->offset); + + return 0; +} + int cam_jpeg_enc_process_cmd(void *device_priv, uint32_t cmd_type, void *cmd_args, uint32_t arg_size) { @@ -450,6 +508,12 @@ int cam_jpeg_enc_process_cmd(void *device_priv, uint32_t cmd_type, rc = 0; break; } + case CAM_JPEG_CMD_HW_DUMP: + { + rc = cam_jpeg_enc_hw_dump(jpeg_enc_dev, + cmd_args); + break; + } default: rc = -EINVAL; break; diff --git a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.h b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.h index 5c571ab893f8..0013dbee1681 100644 --- a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.h +++ b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_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 @@ -47,10 +47,16 @@ struct cam_jpeg_enc_int_status { uint32_t stopdone; }; +struct cam_jpeg_enc_reg_dump { + uint32_t start_offset; + uint32_t end_offset; +}; + struct cam_jpeg_enc_device_hw_info { struct cam_jpeg_enc_reg_offsets reg_offset; struct cam_jpeg_enc_regval reg_val; struct cam_jpeg_enc_int_status int_status; + struct cam_jpeg_enc_reg_dump reg_dump; }; enum cam_jpeg_enc_core_state { diff --git a/drivers/media/platform/msm/camera/cam_lrme/cam_lrme_context.c b/drivers/media/platform/msm/camera/cam_lrme/cam_lrme_context.c index 26bdc31250d1..7f677a1bfc4d 100644 --- a/drivers/media/platform/msm/camera/cam_lrme/cam_lrme_context.c +++ b/drivers/media/platform/msm/camera/cam_lrme/cam_lrme_context.c @@ -93,6 +93,20 @@ static int __cam_lrme_ctx_config_dev_in_activated(struct cam_context *ctx, return rc; } +static int __cam_lrme_ctx_dump_dev_in_activated(struct cam_context *ctx, + struct cam_dump_req_cmd *cmd) +{ + int rc = 0; + + CAM_DBG(CAM_LRME, "Enter ctx %d", ctx->ctx_id); + + rc = cam_context_dump_dev_to_hw(ctx, cmd); + if (rc) + CAM_ERR(CAM_LRME, "Failed to dump device"); + + return rc; +} + static int __cam_lrme_ctx_flush_dev_in_activated(struct cam_context *ctx, struct cam_flush_dev_cmd *cmd) { @@ -204,6 +218,7 @@ static struct cam_ctx_ops .release_dev = __cam_lrme_ctx_release_dev_in_activated, .stop_dev = __cam_lrme_ctx_stop_dev_in_activated, .flush_dev = __cam_lrme_ctx_flush_dev_in_activated, + .dump_dev = __cam_lrme_ctx_dump_dev_in_activated, }, .crm_ops = {}, .irq_ops = __cam_lrme_ctx_handle_irq_in_activated, diff --git a/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c index f46426f50e97..d87ce0202ecf 100644 --- a/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c +++ b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c @@ -656,6 +656,54 @@ static int cam_lrme_mgr_hw_release(void *hw_mgr_priv, void *hw_release_args) return rc; } +static int cam_lrme_mgr_hw_dump(void *hw_mgr_priv, void *hw_dump_args) +{ + struct cam_hw_dump_args *dump_args = hw_dump_args; + struct cam_lrme_hw_mgr *hw_mgr = hw_mgr_priv; + struct cam_lrme_device *hw_device; + int rc = 0; + uint32_t device_index; + struct cam_lrme_hw_dump_args lrme_dump_args; + + device_index = CAM_LRME_DECODE_DEVICE_INDEX(dump_args->ctxt_to_hw_map); + if (device_index >= hw_mgr->device_count) { + CAM_ERR(CAM_LRME, "Invalid device index %d", device_index); + return -EPERM; + } + + CAM_DBG(CAM_LRME, "Start device index %d", device_index); + + rc = cam_lrme_mgr_util_get_device(hw_mgr, device_index, &hw_device); + if (rc) { + CAM_ERR(CAM_LRME, "Failed to get hw device"); + return rc; + } + rc = cam_mem_get_cpu_buf(dump_args->buf_handle, + &lrme_dump_args.cpu_addr, + &lrme_dump_args.buf_len); + if (!lrme_dump_args.cpu_addr || !lrme_dump_args.buf_len || rc) { + CAM_ERR(CAM_LRME, + "lnvalid addr %u len %zu rc %d", + dump_args->buf_handle, lrme_dump_args.buf_len, rc); + return rc; + } + lrme_dump_args.offset = dump_args->offset; + lrme_dump_args.request_id = dump_args->request_id; + + rc = hw_device->hw_intf.hw_ops.process_cmd( + hw_device->hw_intf.hw_priv, + CAM_LRME_HW_CMD_DUMP, + &lrme_dump_args, + sizeof(struct cam_lrme_hw_dump_args)); + dump_args->offset = lrme_dump_args.offset; + + rc = cam_mem_put_cpu_buf(dump_args->buf_handle); + if (rc) + CAM_ERR(CAM_LRME, "Cpu put failed handle %u", + dump_args->buf_handle); + return rc; +} + static int cam_lrme_mgr_hw_flush(void *hw_mgr_priv, void *hw_flush_args) { int rc = 0, i; struct cam_lrme_hw_mgr *hw_mgr = hw_mgr_priv; @@ -1153,6 +1201,7 @@ int cam_lrme_hw_mgr_init(struct cam_hw_mgr_intf *hw_mgr_intf, hw_mgr_intf->hw_write = NULL; hw_mgr_intf->hw_close = NULL; hw_mgr_intf->hw_flush = cam_lrme_mgr_hw_flush; + hw_mgr_intf->hw_dump = cam_lrme_mgr_hw_dump; g_lrme_hw_mgr.event_cb = cam_lrme_dev_buf_done_cb; diff --git a/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c index 9e14f1b2958d..880eaa4c20a6 100644 --- a/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c +++ b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c @@ -10,6 +10,7 @@ * GNU General Public License for more details. */ +#include <linux/timer.h> #include "cam_lrme_hw_core.h" #include "cam_lrme_hw_soc.h" #include "cam_smmu_api.h" @@ -28,6 +29,124 @@ static void cam_lrme_dump_registers(void __iomem *base) cam_io_dump(base, 0x900, (0x928 - 0x900) / 0x4); } +static int cam_lrme_dump_regs_to_buf( + struct cam_lrme_frame_request *req, + struct cam_hw_info *lrme_hw, + struct cam_lrme_hw_dump_args *dump_args) +{ + struct cam_hw_soc_info *soc_info = &lrme_hw->soc_info; + int i; + char *dst; + uint32_t *addr, *start; + uint32_t num_reg, min_len, remain_len; + struct cam_lrme_hw_dump_header *hdr; + + soc_info = &lrme_hw->soc_info; + remain_len = dump_args->buf_len - dump_args->offset; + min_len = 2 * (sizeof(struct cam_lrme_hw_dump_header) + + CAM_LRME_HW_DUMP_TAG_MAX_LEN) + + soc_info->reg_map[0].size; + if (remain_len < min_len) { + CAM_ERR(CAM_LRME, "dump buffer exhaust %d %d", + remain_len, min_len); + return 0; + } + dst = (char *)dump_args->cpu_addr + dump_args->offset; + hdr = (struct cam_lrme_hw_dump_header *)dst; + snprintf(hdr->tag, CAM_LRME_HW_DUMP_TAG_MAX_LEN, + "LRME_REG:"); + hdr->word_size = sizeof(uint32_t); + addr = (uint32_t *)(dst + sizeof(struct cam_lrme_hw_dump_header)); + start = addr; + *addr++ = soc_info->index; + num_reg = soc_info->reg_map[0].size/4; + for (i = 0; i < num_reg; i++) { + *addr++ = soc_info->mem_block[0]->start + (i*4); + *addr++ = cam_io_r(soc_info->reg_map[0].mem_base + (i*4)); + } + hdr->size = hdr->word_size * (addr - start); + dump_args->offset += hdr->size + + sizeof(struct cam_lrme_hw_dump_header); + CAM_DBG(CAM_LRME, "offset %d", dump_args->offset); + return 0; +} + +static int cam_lrme_hw_dump(struct cam_hw_info *lrme_hw, + struct cam_lrme_hw_dump_args *dump_args) +{ + struct cam_lrme_core *lrme_core = + (struct cam_lrme_core *)lrme_hw->core_info; + struct cam_lrme_frame_request *req = NULL; + struct timeval cur_time; + uint64_t diff = 0; + char *dst; + uint64_t *addr, *start; + uint32_t min_len, remain_len; + struct cam_lrme_hw_dump_header *hdr; + + 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"); + mutex_unlock(&lrme_hw->hw_mutex); + return 0; + } + mutex_unlock(&lrme_hw->hw_mutex); + if (lrme_core->req_submit && + lrme_core->req_submit->req_id == dump_args->request_id) + req = lrme_core->req_submit; + else if (lrme_core->req_proc && + lrme_core->req_proc->req_id == dump_args->request_id) + req = lrme_core->req_proc; + if (!req) { + CAM_DBG(CAM_LRME, "LRME req %lld not with hw", + dump_args->request_id); + return 0; + } + cam_common_util_get_curr_timestamp(&cur_time); + diff = cam_common_util_get_time_diff(&cur_time, + &req->submit_timestamp); + if (diff < CAM_LRME_RESPONSE_TIME_THRESHOLD) { + CAM_INFO(CAM_LRME, "No error req %lld %ld:%06ld %ld:%06ld", + dump_args->request_id, + req->submit_timestamp.tv_sec, + req->submit_timestamp.tv_usec, + cur_time.tv_sec, + cur_time.tv_usec); + return 0; + } + CAM_INFO(CAM_LRME, "Error req %lld %ld:%06ld %ld:%06ld", + dump_args->request_id, + req->submit_timestamp.tv_sec, + req->submit_timestamp.tv_usec, + cur_time.tv_sec, + cur_time.tv_usec); + remain_len = dump_args->buf_len - dump_args->offset; + min_len = 2 * (sizeof(struct cam_lrme_hw_dump_header) + + CAM_LRME_HW_DUMP_TAG_MAX_LEN); + if (remain_len < min_len) { + CAM_ERR(CAM_LRME, "dump buffer exhaust %d %d", + remain_len, min_len); + return 0; + } + dst = (char *)dump_args->cpu_addr + dump_args->offset; + hdr = (struct cam_lrme_hw_dump_header *)dst; + snprintf(hdr->tag, CAM_LRME_HW_DUMP_TAG_MAX_LEN, + "LRME_REQ:"); + hdr->word_size = sizeof(uint64_t); + addr = (uint64_t *)(dst + sizeof(struct cam_lrme_hw_dump_header)); + start = addr; + *addr++ = req->req_id; + *addr++ = req->submit_timestamp.tv_sec; + *addr++ = req->submit_timestamp.tv_usec; + *addr++ = cur_time.tv_sec; + *addr++ = cur_time.tv_usec; + hdr->size = hdr->word_size * (addr - start); + dump_args->offset += hdr->size + + sizeof(struct cam_lrme_hw_dump_header); + cam_lrme_dump_regs_to_buf(req, lrme_hw, dump_args); + return 0; +} + static void cam_lrme_cdm_write_reg_val_pair(uint32_t *buffer, uint32_t *index, uint32_t reg_offset, uint32_t reg_value) { @@ -964,7 +1083,7 @@ int cam_lrme_hw_submit_req(void *hw_priv, void *hw_submit_args, CAM_ERR(CAM_LRME, "Submit req failed"); goto error; } - + cam_common_util_get_curr_timestamp(&frame_req->submit_timestamp); switch (lrme_core->state) { case CAM_LRME_CORE_STATE_PROCESSING: lrme_core->state = CAM_LRME_CORE_STATE_REQ_PROC_PEND; @@ -1274,6 +1393,12 @@ int cam_lrme_hw_process_cmd(void *hw_priv, uint32_t cmd_type, break; } + case CAM_LRME_HW_CMD_DUMP: { + struct cam_lrme_hw_dump_args *dump_args = + (struct cam_lrme_hw_dump_args *)cmd_args; + rc = cam_lrme_hw_dump(lrme_hw, dump_args); + break; + } default: break; } diff --git a/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.h b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.h index c0786f53c19c..1cb6e34f5c69 100644 --- a/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.h +++ b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_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 @@ -41,6 +41,8 @@ #define CAM_LRME_FE_IRQ_MASK 0x0 #define CAM_LRME_MAX_REG_PAIR_NUM 60 +#define CAM_LRME_RESPONSE_TIME_THRESHOLD 100000 +#define CAM_LRME_HW_DUMP_TAG_MAX_LEN 32 /** * enum cam_lrme_irq_set @@ -439,6 +441,20 @@ struct cam_lrme_hw_info { struct cam_lrme_titan_reg titan_reg; }; +/** + * struct cam_lrme_hw_dump_header : LRME hw dump header + * + * @tag : LRME hw dump header tag + * @size : Size of data + * @word_size : size of each word + */ + +struct cam_lrme_hw_dump_header { + char tag[CAM_LRME_HW_DUMP_TAG_MAX_LEN]; + uint64_t size; + uint32_t word_size; +}; + int cam_lrme_hw_process_irq(void *priv, void *data); int cam_lrme_hw_submit_req(void *hw_priv, void *hw_submit_args, uint32_t arg_size); diff --git a/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_intf.h b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_intf.h index 4cd643f0413a..89485e1deeda 100644 --- a/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_intf.h +++ b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_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 @@ -66,12 +66,14 @@ enum cam_lrme_cb_type { * @CAM_LRME_HW_CMD_REGISTER_CB : register HW manager callback * @CAM_LRME_HW_CMD_SUBMIT : Submit frame to HW * @CAM_LRME_HW_CMD_DUMP_REGISTER : dump register values + * @CAM_LRME_HW_CMD_DUMP : dump register values to buffer */ enum cam_lrme_hw_cmd_type { CAM_LRME_HW_CMD_PREPARE_HW_UPDATE, CAM_LRME_HW_CMD_REGISTER_CB, CAM_LRME_HW_CMD_SUBMIT, CAM_LRME_HW_CMD_DUMP_REGISTER, + CAM_LRME_HW_CMD_DUMP, }; /** @@ -94,6 +96,7 @@ enum cam_lrme_hw_reset_type { * @hw_device : Pointer to HW device * @hw_update_entries : List of hw_update_entries * @num_hw_update_entries : number of hw_update_entries + * @submit_timestamp : timestamp of submitting request with hw */ struct cam_lrme_frame_request { struct list_head frame_list; @@ -102,6 +105,7 @@ struct cam_lrme_frame_request { struct cam_lrme_device *hw_device; struct cam_hw_update_entry hw_update_entries[CAM_LRME_MAX_HW_ENTRIES]; uint32_t num_hw_update_entries; + struct timeval submit_timestamp; }; /** @@ -199,4 +203,19 @@ struct cam_lrme_hw_submit_args { struct cam_lrme_frame_request *frame_req; }; +/** + * struct cam_lrme_hw_dump_args : Args for dump request + * + * @cpu_addr : start address of the target buffer + * @offset : offset of the buffer + * @request_id : Issue request id + * @buf_len : Length of target buffer + */ +struct cam_lrme_hw_dump_args { + uintptr_t cpu_addr; + uint64_t offset; + uint64_t request_id; + size_t buf_len; +}; + #endif /* _CAM_LRME_HW_INTF_H_ */ diff --git a/drivers/media/platform/msm/npu/npu_common.h b/drivers/media/platform/msm/npu/npu_common.h index a62af58e22cf..9481582da38d 100644 --- a/drivers/media/platform/msm/npu/npu_common.h +++ b/drivers/media/platform/msm/npu/npu_common.h @@ -102,8 +102,6 @@ struct npu_debugfs_ctx { struct dentry *root; uint32_t reg_off; uint32_t reg_cnt; - char *buf; - size_t buf_len; uint8_t *log_buf; struct mutex log_lock; uint32_t log_num_bytes_buffered; @@ -112,6 +110,12 @@ struct npu_debugfs_ctx { uint32_t log_buf_size; }; +struct npu_debugfs_reg_ctx { + char *buf; + size_t buf_len; + struct npu_device *npu_dev; +}; + struct npu_mbox { struct mbox_client client; struct mbox_chan *chan; diff --git a/drivers/media/platform/msm/npu/npu_debugfs.c b/drivers/media/platform/msm/npu/npu_debugfs.c index 90308bf846e2..df76f16f6404 100644 --- a/drivers/media/platform/msm/npu/npu_debugfs.c +++ b/drivers/media/platform/msm/npu/npu_debugfs.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 @@ -34,6 +34,8 @@ */ static int npu_debug_open(struct inode *inode, struct file *file); static int npu_debug_release(struct inode *inode, struct file *file); +static int npu_debug_reg_open(struct inode *inode, struct file *file); +static int npu_debug_reg_release(struct inode *inode, struct file *file); static ssize_t npu_debug_reg_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos); static ssize_t npu_debug_reg_read(struct file *file, @@ -54,8 +56,8 @@ static ssize_t npu_debug_ctrl_write(struct file *file, struct npu_device *g_npu_dev; static const struct file_operations npu_reg_fops = { - .open = npu_debug_open, - .release = npu_debug_release, + .open = npu_debug_reg_open, + .release = npu_debug_reg_release, .read = npu_debug_reg_read, .write = npu_debug_reg_write, }; @@ -95,14 +97,31 @@ static int npu_debug_open(struct inode *inode, struct file *file) static int npu_debug_release(struct inode *inode, struct file *file) { - struct npu_device *npu_dev = file->private_data; - struct npu_debugfs_ctx *debugfs; + return 0; +} - debugfs = &npu_dev->debugfs_ctx; +static int npu_debug_reg_open(struct inode *inode, struct file *file) +{ + struct npu_debugfs_reg_ctx *reg_ctx; + + reg_ctx = kzalloc(sizeof(*reg_ctx), GFP_KERNEL); + if (!reg_ctx) + return -ENOMEM; - kfree(debugfs->buf); - debugfs->buf_len = 0; - debugfs->buf = NULL; + /* non-seekable */ + file->f_mode &= ~(FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE); + reg_ctx->npu_dev = inode->i_private; + file->private_data = reg_ctx; + return 0; +} + +static int npu_debug_reg_release(struct inode *inode, struct file *file) +{ + struct npu_debugfs_reg_ctx *reg_ctx = file->private_data; + + kfree(reg_ctx->buf); + kfree(reg_ctx); + file->private_data = NULL; return 0; } @@ -148,7 +167,8 @@ static ssize_t npu_debug_reg_write(struct file *file, static ssize_t npu_debug_reg_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { - struct npu_device *npu_dev = file->private_data; + struct npu_debugfs_reg_ctx *reg_ctx = file->private_data; + struct npu_device *npu_dev = reg_ctx->npu_dev; struct npu_debugfs_ctx *debugfs; size_t len; @@ -157,16 +177,16 @@ static ssize_t npu_debug_reg_read(struct file *file, if (debugfs->reg_cnt == 0) return 0; - if (!debugfs->buf) { + if (!reg_ctx->buf) { char dump_buf[64]; char *ptr; int cnt, tot, off; - debugfs->buf_len = sizeof(dump_buf) * + reg_ctx->buf_len = sizeof(dump_buf) * DIV_ROUND_UP(debugfs->reg_cnt, ROW_BYTES); - debugfs->buf = kzalloc(debugfs->buf_len, GFP_KERNEL); + reg_ctx->buf = kzalloc(reg_ctx->buf_len, GFP_KERNEL); - if (!debugfs->buf) + if (!reg_ctx->buf) return -ENOMEM; ptr = npu_dev->core_io.base + debugfs->reg_off; @@ -180,28 +200,28 @@ static ssize_t npu_debug_reg_read(struct file *file, hex_dump_to_buffer(ptr, min(cnt, ROW_BYTES), ROW_BYTES, GROUP_BYTES, dump_buf, sizeof(dump_buf), false); - len = scnprintf(debugfs->buf + tot, - debugfs->buf_len - tot, "0x%08x: %s\n", + len = scnprintf(reg_ctx->buf + tot, + reg_ctx->buf_len - tot, "0x%08x: %s\n", ((int) (unsigned long) ptr) - ((int) (unsigned long) npu_dev->core_io.base), dump_buf); ptr += ROW_BYTES; tot += len; - if (tot >= debugfs->buf_len) + if (tot >= reg_ctx->buf_len) break; } npu_disable_core_power(npu_dev); - debugfs->buf_len = tot; + reg_ctx->buf_len = tot; } - if (*ppos >= debugfs->buf_len) + if (*ppos >= reg_ctx->buf_len) return 0; /* done reading */ - len = min(count, debugfs->buf_len - (size_t) *ppos); - pr_debug("read %zi %zi\n", count, debugfs->buf_len - (size_t) *ppos); - if (copy_to_user(user_buf, debugfs->buf + *ppos, len)) { + len = min(count, reg_ctx->buf_len - (size_t) *ppos); + pr_debug("read %zi %zi\n", count, reg_ctx->buf_len - (size_t) *ppos); + if (copy_to_user(user_buf, reg_ctx->buf + *ppos, len)) { pr_err("failed to copy to user\n"); return -EFAULT; } diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c index 59247e73cf52..435731233e87 100644 --- a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c +++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c @@ -3325,6 +3325,7 @@ int sde_rotator_runtime_idle(struct device *dev) int sde_rotator_pm_suspend(struct device *dev) { struct sde_rot_mgr *mgr; + int i; mgr = sde_rot_mgr_from_device(dev); @@ -3339,8 +3340,20 @@ int sde_rotator_pm_suspend(struct device *dev) sde_rotator_suspend_cancel_rot_work(mgr); mgr->minimum_bw_vote = 0; sde_rotator_update_perf(mgr); + mgr->pm_rot_enable_clk_cnt = mgr->rot_enable_clk_cnt; + + if (mgr->pm_rot_enable_clk_cnt) { + for (i = 0; i < mgr->pm_rot_enable_clk_cnt; i++) + sde_rotator_clk_ctrl(mgr, false); + + sde_rotator_update_clk(mgr); + } + ATRACE_END("pm_active"); - SDEROT_DBG("end pm active %d\n", atomic_read(&mgr->device_suspended)); + SDEROT_DBG("end pm active %d clk_cnt %d\n", + atomic_read(&mgr->device_suspended), mgr->pm_rot_enable_clk_cnt); + SDEROT_EVTLOG(mgr->pm_rot_enable_clk_cnt, + atomic_read(&mgr->device_suspended)); sde_rot_mgr_unlock(mgr); return 0; } @@ -3352,6 +3365,7 @@ int sde_rotator_pm_suspend(struct device *dev) int sde_rotator_pm_resume(struct device *dev) { struct sde_rot_mgr *mgr; + int i; mgr = sde_rot_mgr_from_device(dev); @@ -3371,10 +3385,20 @@ int sde_rotator_pm_resume(struct device *dev) pm_runtime_enable(dev); sde_rot_mgr_lock(mgr); - SDEROT_DBG("begin pm active %d\n", atomic_read(&mgr->device_suspended)); + SDEROT_DBG("begin pm active %d clk_cnt %d\n", + atomic_read(&mgr->device_suspended), mgr->pm_rot_enable_clk_cnt); ATRACE_BEGIN("pm_active"); + SDEROT_EVTLOG(mgr->pm_rot_enable_clk_cnt, + atomic_read(&mgr->device_suspended)); atomic_dec(&mgr->device_suspended); sde_rotator_update_perf(mgr); + + if (mgr->pm_rot_enable_clk_cnt) { + sde_rotator_update_clk(mgr); + for (i = 0; i < mgr->pm_rot_enable_clk_cnt; i++) + sde_rotator_clk_ctrl(mgr, true); + } + sde_rot_mgr_unlock(mgr); return 0; } diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.h b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.h index eca54ee1bfa6..4689d7f649ef 100644 --- a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.h +++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.h @@ -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 @@ -393,6 +393,7 @@ struct sde_rot_bus_data_type { * @regulator_enable: true if foot switch is enabled; false otherwise * @res_ref_cnt: reference count of how many times resource is requested * @rot_enable_clk_cnt: reference count of how many times clock is requested + * @pm_rot_enable_clk_cnt : tracks the clock enable count on pm suspend * @rot_clk: array of rotator and periphery clocks * @num_rot_clk: size of the rotator clock array * @rdot_limit: current read OT limit @@ -439,6 +440,7 @@ struct sde_rot_mgr { int res_ref_cnt; int rot_enable_clk_cnt; + int pm_rot_enable_clk_cnt; struct sde_rot_clk *rot_clk; int num_rot_clk; u32 rdot_limit; diff --git a/drivers/power/supply/qcom/smb5-lib.c b/drivers/power/supply/qcom/smb5-lib.c index 58d68d2d3f11..cb6f17a92d51 100644 --- a/drivers/power/supply/qcom/smb5-lib.c +++ b/drivers/power/supply/qcom/smb5-lib.c @@ -1942,7 +1942,7 @@ int smblib_get_prop_batt_status(struct smb_charger *chg, * If charge termination WA is active and has suspended charging, then * continue reporting charging status as FULL. */ - if (is_client_vote_enabled(chg->usb_icl_votable, + if (is_client_vote_enabled_locked(chg->usb_icl_votable, CHG_TERMINATION_VOTER)) { val->intval = POWER_SUPPLY_STATUS_FULL; return 0; @@ -3054,7 +3054,7 @@ int smblib_get_prop_usb_online(struct smb_charger *chg, return rc; } - if (is_client_vote_enabled(chg->usb_icl_votable, + if (is_client_vote_enabled_locked(chg->usb_icl_votable, CHG_TERMINATION_VOTER)) { rc = smblib_get_prop_usb_present(chg, val); return rc; diff --git a/drivers/scsi/ufs/ufs-qcom-ice.c b/drivers/scsi/ufs/ufs-qcom-ice.c index c5fe4784fa21..8bb1f54455d1 100644 --- a/drivers/scsi/ufs/ufs-qcom-ice.c +++ b/drivers/scsi/ufs/ufs-qcom-ice.c @@ -179,7 +179,8 @@ static void ufs_qcom_ice_cfg_work(struct work_struct *work) return; spin_lock_irqsave(&qcom_host->ice_work_lock, flags); - if (!qcom_host->req_pending) { + if (!qcom_host->req_pending || + ufshcd_is_shutdown_ongoing(qcom_host->hba)) { qcom_host->work_pending = false; spin_unlock_irqrestore(&qcom_host->ice_work_lock, flags); return; @@ -227,7 +228,7 @@ int ufs_qcom_ice_init(struct ufs_qcom_host *qcom_host) qcom_host->dbg_print_en |= UFS_QCOM_ICE_DEFAULT_DBG_PRINT_EN; if (!ice_workqueue) { ice_workqueue = alloc_workqueue("ice-set-key", - WQ_MEM_RECLAIM | WQ_HIGHPRI, 0); + WQ_MEM_RECLAIM | WQ_HIGHPRI | WQ_FREEZABLE, 0); if (!ice_workqueue) { dev_err(ufs_dev, "%s: workqueue allocation failed.\n", __func__); @@ -610,6 +611,7 @@ out: return err; } + /** * ufs_qcom_ice_resume() - resumes UFS-ICE interface and ICE device from power * collapse @@ -654,6 +656,28 @@ out: } /** + * ufs_qcom_is_ice_busy() - lets the caller of the function know if + * there is any ongoing operation in ICE in workqueue context. + * @qcom_host: Pointer to a UFS QCom internal host structure. + * qcom_host should be a valid pointer. + * + * Return: 1 if ICE is busy, 0 if it is free. + * -EINVAL in case of error. + */ +int ufs_qcom_is_ice_busy(struct ufs_qcom_host *qcom_host) +{ + if (!qcom_host) { + pr_err("%s: invalid qcom_host %pK", __func__, qcom_host); + return -EINVAL; + } + + if (qcom_host->req_pending) + return 1; + else + return 0; +} + +/** * ufs_qcom_ice_suspend() - suspends UFS-ICE interface and ICE device * @qcom_host: Pointer to a UFS QCom internal host structure. * qcom_host, qcom_host->hba and qcom_host->hba->dev should all diff --git a/drivers/scsi/ufs/ufs-qcom-ice.h b/drivers/scsi/ufs/ufs-qcom-ice.h index eb0291612049..88ffeb35f9f3 100644 --- a/drivers/scsi/ufs/ufs-qcom-ice.h +++ b/drivers/scsi/ufs/ufs-qcom-ice.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2016, 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 @@ -83,6 +83,7 @@ int ufs_qcom_ice_resume(struct ufs_qcom_host *qcom_host); int ufs_qcom_ice_suspend(struct ufs_qcom_host *qcom_host); int ufs_qcom_ice_get_status(struct ufs_qcom_host *qcom_host, int *ice_status); void ufs_qcom_ice_print_regs(struct ufs_qcom_host *qcom_host); +int ufs_qcom_is_ice_busy(struct ufs_qcom_host *qcom_host); #else inline int ufs_qcom_ice_get_dev(struct ufs_qcom_host *qcom_host) { @@ -127,6 +128,10 @@ inline void ufs_qcom_ice_print_regs(struct ufs_qcom_host *qcom_host) { return; } +inline int ufs_qcom_is_ice_busy(struct ufs_qcom_host *qcom_host) +{ + return 0; +} #endif /* CONFIG_SCSI_UFS_QCOM_ICE */ #endif /* UFS_QCOM_ICE_H_ */ diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c index 349a993dc419..b679aadc092e 100644 --- a/drivers/scsi/ufs/ufs-qcom.c +++ b/drivers/scsi/ufs/ufs-qcom.c @@ -1015,12 +1015,27 @@ static int ufs_qcom_crypto_engine_get_status(struct ufs_hba *hba, u32 *status) return ufs_qcom_ice_get_status(host, status); } + +static int ufs_qcom_crypto_get_pending_req_status(struct ufs_hba *hba) +{ + struct ufs_qcom_host *host = ufshcd_get_variant(hba); + int err = 0; + + if (!host->ice.pdev) + goto out; + + err = ufs_qcom_is_ice_busy(host); +out: + return err; +} + #else /* !CONFIG_SCSI_UFS_QCOM_ICE */ #define ufs_qcom_crypto_req_setup NULL #define ufs_qcom_crytpo_engine_cfg_start NULL #define ufs_qcom_crytpo_engine_cfg_end NULL #define ufs_qcom_crytpo_engine_reset NULL #define ufs_qcom_crypto_engine_get_status NULL +#define ufs_qcom_crypto_get_pending_req_status NULL #endif /* CONFIG_SCSI_UFS_QCOM_ICE */ struct ufs_qcom_dev_params { @@ -2804,6 +2819,7 @@ static struct ufs_hba_crypto_variant_ops ufs_hba_crypto_variant_ops = { .crypto_engine_cfg_end = ufs_qcom_crytpo_engine_cfg_end, .crypto_engine_reset = ufs_qcom_crytpo_engine_reset, .crypto_engine_get_status = ufs_qcom_crypto_engine_get_status, + .crypto_get_req_status = ufs_qcom_crypto_get_pending_req_status, }; static struct ufs_hba_pm_qos_variant_ops ufs_hba_pm_qos_variant_ops = { diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 3b0dcdef99b3..b547a67411bf 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -3696,9 +3696,13 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) err = ufshcd_get_read_lock(hba, cmd->device->lun); if (unlikely(err < 0)) { if (err == -EPERM) { - set_host_byte(cmd, DID_ERROR); - cmd->scsi_done(cmd); - return 0; + if (!ufshcd_vops_crypto_engine_get_req_status(hba)) { + set_host_byte(cmd, DID_ERROR); + cmd->scsi_done(cmd); + return 0; + } else { + return SCSI_MLQUEUE_HOST_BUSY; + } } if (err == -EAGAIN) return SCSI_MLQUEUE_HOST_BUSY; diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index b1e7b49958a3..3c63fdb3da87 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -3,7 +3,7 @@ * * This code is based on drivers/scsi/ufs/ufshcd.h * 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> @@ -377,6 +377,7 @@ struct ufs_hba_variant_ops { * according to tag parameter * @crypto_engine_reset: perform reset to the cryptographic engine * @crypto_engine_get_status: get errors status of the cryptographic engine + * @crypto_get_req_status: Check if crypto driver still holds request or not */ struct ufs_hba_crypto_variant_ops { int (*crypto_req_setup)(struct ufs_hba *, struct ufshcd_lrb *lrbp, @@ -386,6 +387,7 @@ struct ufs_hba_crypto_variant_ops { struct request *); int (*crypto_engine_reset)(struct ufs_hba *); int (*crypto_engine_get_status)(struct ufs_hba *, u32 *); + int (*crypto_get_req_status)(struct ufs_hba *); }; /** @@ -1528,7 +1530,6 @@ static inline int ufshcd_vops_crypto_engine_reset(struct ufs_hba *hba) static inline int ufshcd_vops_crypto_engine_get_status(struct ufs_hba *hba, u32 *status) - { if (hba->var && hba->var->crypto_vops && hba->var->crypto_vops->crypto_engine_get_status) @@ -1552,4 +1553,13 @@ static inline void ufshcd_vops_pm_qos_req_end(struct ufs_hba *hba, hba->var->pm_qos_vops->req_end(hba, req, lock); } +static inline int ufshcd_vops_crypto_engine_get_req_status(struct ufs_hba *hba) + +{ + if (hba->var && hba->var->crypto_vops && + hba->var->crypto_vops->crypto_get_req_status) + return hba->var->crypto_vops->crypto_get_req_status(hba); + return 0; +} + #endif /* End of Header */ diff --git a/drivers/soc/qcom/mem-offline.c b/drivers/soc/qcom/mem-offline.c index 3396d87bf3e2..048153e46a0b 100644 --- a/drivers/soc/qcom/mem-offline.c +++ b/drivers/soc/qcom/mem-offline.c @@ -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 @@ -22,6 +22,7 @@ #include <linux/kobject.h> #include <linux/platform_device.h> #include <linux/of.h> +#include <linux/bootmem.h> #include <linux/mailbox_client.h> #include <linux/mailbox/qmp.h> @@ -220,6 +221,8 @@ static int mem_online_remaining_blocks(void) fail = 1; } } + + max_pfn = PFN_DOWN(memblock_end_of_DRAM()); return fail; } diff --git a/drivers/soc/qcom/peripheral-loader.c b/drivers/soc/qcom/peripheral-loader.c index 7611b2540b0e..45c920e60db8 100644 --- a/drivers/soc/qcom/peripheral-loader.c +++ b/drivers/soc/qcom/peripheral-loader.c @@ -59,10 +59,29 @@ #define PIL_NUM_DESC 10 #define MAX_LEN 96 #define NUM_OF_ENCRYPTED_KEY 3 +#define MINIDUMP_DEBUG_PROP "qcom,msm-imem-minidump-debug" static void __iomem *pil_info_base; +static void __iomem *minidump_debug; static struct md_global_toc *g_md_toc; +static void *map_prop(const char *propname) +{ + struct device_node *np = of_find_compatible_node(NULL, NULL, propname); + void *addr; + + if (!np) { + pr_err("Unable to find DT property: %s\n", propname); + return NULL; + } + + addr = of_iomap(np, 0); + if (!addr) + pr_err("Unable to map memory for DT property: %s\n", propname); + + return addr; +} + /** * proxy_timeout - Override for proxy vote timeouts * -1: Use driver-specified timeout @@ -463,6 +482,9 @@ int pil_do_ramdump(struct pil_desc *desc, print_aux_minidump_tocs(desc); + if (minidump_debug) + pr_info("Minidump debug cookie=%x\n", + __raw_readl(minidump_debug)); /** * Collect minidump if SS ToC is valid and segment table * is initialized in memory and encryption status is set. @@ -1676,6 +1698,8 @@ static int __init msm_pil_init(void) return -EPROBE_DEFER; } + minidump_debug = map_prop(MINIDUMP_DEBUG_PROP); + pil_wq = alloc_workqueue("pil_workqueue", WQ_HIGHPRI | WQ_UNBOUND, 0); if (!pil_wq) pr_warn("pil: Defaulting to sequential firmware loading.\n"); @@ -1692,6 +1716,8 @@ static void __exit msm_pil_exit(void) unregister_pm_notifier(&pil_pm_notifier); if (pil_info_base) iounmap(pil_info_base); + if (minidump_debug) + iounmap(minidump_debug); } module_exit(msm_pil_exit); diff --git a/security/pfe/pfk.c b/security/pfe/pfk.c index 5ca170a0bb7b..85a0e7448d2c 100644 --- a/security/pfe/pfk.c +++ b/security/pfe/pfk.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 @@ -197,6 +197,8 @@ static inline bool pfk_is_ready(void) */ static struct inode *pfk_bio_get_inode(const struct bio *bio) { + struct address_space *mapping = NULL; + if (!bio) return NULL; if (!bio_has_data((struct bio *)bio)) @@ -216,10 +218,11 @@ static struct inode *pfk_bio_get_inode(const struct bio *bio) return inode; } - if (!page_mapping(bio->bi_io_vec->bv_page)) + mapping = page_mapping(bio->bi_io_vec->bv_page); + if (!mapping) return NULL; - return page_mapping(bio->bi_io_vec->bv_page)->host; + return mapping->host; } /** |