Merge "msm: camera: common: LDAR dump NRT devices information" into camera-kernel.lnx.4.0

Cette révision appartient à :
Camera Software Integration
2020-02-10 11:46:57 -08:00
révisé par Gerrit - the friendly Code Review server
révision 23372b610f
23 fichiers modifiés avec 1030 ajouts et 17 suppressions

Voir le fichier

@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
*/
#include <linux/module.h>
@@ -117,6 +117,19 @@ 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)
{
@@ -198,6 +211,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,

Voir le fichier

@@ -883,6 +883,7 @@ static int cam_fd_mgr_util_submit_frame(void *priv, void *data)
hw_device->cur_hw_ctx = hw_ctx;
hw_device->req_id = frame_req->request_id;
mutex_unlock(&hw_device->lock);
frame_req->submit_timestamp = ktime_get();
rc = cam_fd_mgr_util_put_frame_req(
&hw_mgr->frame_processing_list, &frame_req);
@@ -1514,6 +1515,137 @@ 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)
{
int rc;
uint8_t *dst;
ktime_t cur_time;
size_t remain_len;
uint32_t min_len;
uint64_t diff;
uint64_t *addr, *start;
struct timespec64 cur_ts;
struct timespec64 req_ts;
struct cam_fd_hw_mgr *hw_mgr;
struct cam_hw_dump_args *dump_args;
struct cam_fd_hw_mgr_ctx *hw_ctx;
struct cam_fd_device *hw_device;
struct cam_fd_hw_dump_args fd_dump_args;
struct cam_fd_hw_dump_header *hdr;
struct cam_fd_mgr_frame_request *frame_req, *req_temp;
hw_mgr = (struct cam_fd_hw_mgr *)hw_mgr_priv;
dump_args = (struct cam_hw_dump_args *)hw_dump_args;
if (!hw_mgr || !dump_args) {
CAM_ERR(CAM_FD, "Invalid args %pK %pK",
hw_mgr, dump_args);
return -EINVAL;
}
hw_ctx = (struct cam_fd_hw_mgr_ctx *)dump_args->ctxt_to_hw_map;
if (!hw_ctx) {
CAM_ERR(CAM_FD, "Invalid ctx");
return -EINVAL;
}
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;
}
CAM_DBG(CAM_FD, "fd dump cannot find req %llu",
dump_args->request_id);
return rc;
hw_dump:
cur_time = ktime_get();
diff = ktime_us_delta(frame_req->submit_timestamp, cur_time);
cur_ts = ktime_to_timespec64(cur_time);
req_ts = ktime_to_timespec64(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,
req_ts.tv_sec,
req_ts.tv_nsec/NSEC_PER_USEC,
cur_ts.tv_sec,
cur_ts.tv_nsec/NSEC_PER_USEC);
return 0;
}
CAM_INFO(CAM_FD, "Error req %lld %ld:%06ld %ld:%06ld",
dump_args->request_id,
req_ts.tv_sec,
req_ts.tv_nsec/NSEC_PER_USEC,
cur_ts.tv_sec,
cur_ts.tv_nsec/NSEC_PER_USEC);
rc = cam_mem_get_cpu_buf(dump_args->buf_handle,
&fd_dump_args.cpu_addr, &fd_dump_args.buf_len);
if (rc) {
CAM_ERR(CAM_FD, "Invalid handle %u rc %d",
dump_args->buf_handle, rc);
return rc;
}
if (fd_dump_args.buf_len <= dump_args->offset) {
CAM_WARN(CAM_FD, "dump offset overshoot len %zu offset %zu",
fd_dump_args.buf_len, dump_args->offset);
return -ENOSPC;
}
remain_len = fd_dump_args.buf_len - dump_args->offset;
min_len = sizeof(struct cam_fd_hw_dump_header) +
(CAM_FD_HW_DUMP_NUM_WORDS * sizeof(uint64_t));
if (remain_len < min_len) {
CAM_WARN(CAM_FD, "dump buffer exhaust remain %zu min %u",
remain_len, min_len);
return -ENOSPC;
}
dst = (uint8_t *)fd_dump_args.cpu_addr + dump_args->offset;
hdr = (struct cam_fd_hw_dump_header *)dst;
scnprintf(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++ = req_ts.tv_sec;
*addr++ = req_ts.tv_nsec/NSEC_PER_USEC;
*addr++ = cur_ts.tv_sec;
*addr++ = cur_ts.tv_nsec/NSEC_PER_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);
return rc;
}
}
CAM_DBG(CAM_FD, "Offset before %zu after %zu",
dump_args->offset, fd_dump_args.offset);
dump_args->offset = fd_dump_args.offset;
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;
@@ -1954,6 +2086,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;

Voir le fichier

@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
*/
#ifndef _CAM_FD_HW_MGR_H_
@@ -21,6 +21,12 @@
#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;
/**
@@ -100,6 +106,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;
@@ -108,6 +115,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;
ktime_t submit_timestamp;
};
/**

Voir le fichier

@@ -516,6 +516,80 @@ 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)
{
int i, j;
uint8_t *dst;
uint32_t *addr, *start;
uint32_t num_reg, min_len;
uint64_t remain_len;
struct cam_hw_soc_info *soc_info;
struct cam_fd_hw_dump_header *hdr;
struct cam_fd_hw_dump_args *dump_args;
if (!fd_hw || !args) {
CAM_ERR(CAM_FD, "Invalid args %pK %pK",
fd_hw, args);
return -EINVAL;
}
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;
}
dump_args = (struct cam_fd_hw_dump_args *)args;
soc_info = &fd_hw->soc_info;
if (dump_args->buf_len <= dump_args->offset) {
CAM_WARN(CAM_FD, "dump offset overshoot len %zu offset %zu",
dump_args->buf_len, dump_args->offset);
mutex_unlock(&fd_hw->hw_mutex);
return -ENOSPC;
}
remain_len = dump_args->buf_len - dump_args->offset;
min_len = sizeof(struct cam_fd_hw_dump_header) +
soc_info->reg_map[0].size + sizeof(uint32_t);
if (remain_len < min_len) {
CAM_WARN(CAM_FD, "dump buffer exhaust remain %zu min %u",
remain_len, min_len);
mutex_unlock(&fd_hw->hw_mutex);
return -ENOSPC;
}
dst = (uint8_t *)dump_args->cpu_addr + dump_args->offset;
hdr = (struct cam_fd_hw_dump_header *)dst;
scnprintf(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;
for (j = 0; j < soc_info->num_reg_map; j++) {
num_reg = soc_info->reg_map[j].size/4;
for (i = 0; i < num_reg; i++) {
*addr++ = soc_info->mem_block[j]->start + i*4;
*addr++ = cam_io_r(soc_info->reg_map[j].mem_base +
(i*4));
}
}
mutex_unlock(&fd_hw->hw_mutex);
hdr->size = hdr->word_size * (addr - start);
dump_args->offset += hdr->size +
sizeof(struct cam_fd_hw_dump_header);
CAM_DBG(CAM_FD, "%zu", 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;
@@ -1161,6 +1235,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;
}

Voir le fichier

@@ -24,6 +24,8 @@
#define CAM_FD_MAX_IO_BUFFERS 5
#define CAM_FD_MAX_HW_ENTRIES 5
#define CAM_FD_HW_DUMP_TAG_MAX_LEN 32
#define CAM_FD_HW_DUMP_NUM_WORDS 5
/**
* enum cam_fd_hw_type - Enum for FD HW type
@@ -81,12 +83,14 @@ enum cam_fd_hw_irq_type {
* @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_MAX : Indicates max cmd
* @CAM_FD_HW_CMD_HW_DUMP : Command to dump fd hw information
*/
enum cam_fd_hw_cmd_type {
CAM_FD_HW_CMD_PRESTART,
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,
};
@@ -281,6 +285,34 @@ struct cam_fd_hw_cmd_set_irq_cb {
void *data;
};
/**
* struct cam_fd_hw_dump_args : Args for dump request
*
* @request_id : Issue request id
* @offset : offset of the buffer
* @buf_len : Length of target buffer
* @cpu_addr : start address of the target buffer
*/
struct cam_fd_hw_dump_args {
uint64_t request_id;
size_t offset;
size_t buf_len;
uintptr_t cpu_addr;
};
/**
* 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 {
uint8_t tag[CAM_FD_HW_DUMP_TAG_MAX_LEN];
uint64_t size;
uint32_t word_size;
};
/**
* @brief : API to register FD Hw to platform framework.
* @return struct platform_device pointer on on success, or ERR_PTR() on error.
@@ -293,3 +325,4 @@ int cam_fd_hw_init_module(void);
void cam_fd_hw_exit_module(void);
#endif /* _CAM_FD_HW_INTF_H_ */

Voir le fichier

@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
*/
#include <linux/debugfs.h>
@@ -107,6 +107,19 @@ 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)
{
@@ -230,6 +243,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,
@@ -242,6 +256,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,

Voir le fichier

@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
*/
#include <linux/slab.h>
@@ -235,6 +235,53 @@ 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;
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) {
CAM_WARN(CAM_ICP, "Dump offset overshoot len %zu offset %zu",
dump_args->buf_len, dump_args->offset);
return -ENOSPC;
}
if ((dump_args->buf_len - dump_args->offset) < size_required) {
CAM_WARN(CAM_ICP, "Dump buffer exhaust required %llu len %llu",
size_required, core_info->fw_buf_len);
return -ENOSPC;
}
dest = (u8 *)dump_args->cpu_addr + dump_args->offset;
hdr = (struct cam_icp_dump_header *)dest;
scnprintf(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)
{
@@ -543,6 +590,12 @@ int cam_a5_process_cmd(void *device_priv, uint32_t cmd_type,
core_info->cpas_handle, &ahb_vote);
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;
}

Voir le fichier

@@ -3930,6 +3930,7 @@ static int cam_icp_mgr_config_hw(void *hw_mgr_priv, void *config_hw_args)
cam_icp_mgr_ipe_bps_clk_update(hw_mgr, ctx_data, idx);
ctx_data->hfi_frame_process.fw_process_flag[idx] = true;
ctx_data->hfi_frame_process.submit_timestamp[idx] = ktime_get();
CAM_DBG(CAM_ICP, "req_id %llu, io config %llu", req_id,
frame_info->io_config);
@@ -5038,6 +5039,115 @@ static int cam_icp_mgr_enqueue_abort(
return 0;
}
static int cam_icp_mgr_hw_dump(void *hw_priv, void *hw_dump_args)
{
int rc;
int i;
size_t remain_len;
uint8_t *dst;
uint32_t min_len;
uint64_t diff;
uint64_t *addr, *start;
struct timespec64 cur_ts;
struct timespec64 req_ts;
ktime_t cur_time;
struct cam_hw_intf *a5_dev_intf;
struct cam_icp_hw_mgr *hw_mgr;
struct cam_hw_dump_args *dump_args;
struct cam_icp_hw_ctx_data *ctx_data;
struct cam_icp_dump_header *hdr;
struct cam_icp_hw_dump_args icp_dump_args;
struct hfi_frame_process_info *frm_process;
if ((!hw_priv) || (!hw_dump_args)) {
CAM_ERR(CAM_ICP, "Invalid params %pK %pK",
hw_priv, hw_dump_args);
return -EINVAL;
}
dump_args = (struct cam_hw_dump_args *)hw_dump_args;
hw_mgr = hw_priv;
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:
cur_time = ktime_get();
diff = ktime_us_delta(frm_process->submit_timestamp[i], cur_time);
cur_ts = ktime_to_timespec64(cur_time);
req_ts = ktime_to_timespec64(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,
req_ts.tv_sec,
req_ts.tv_nsec/NSEC_PER_USEC,
cur_ts.tv_sec,
cur_ts.tv_nsec/NSEC_PER_USEC);
return 0;
}
CAM_INFO(CAM_ICP, "Error req %lld %ld:%06ld %ld:%06ld",
dump_args->request_id,
req_ts.tv_sec,
req_ts.tv_nsec/NSEC_PER_USEC,
cur_ts.tv_sec,
cur_ts.tv_nsec/NSEC_PER_USEC);
rc = cam_mem_get_cpu_buf(dump_args->buf_handle,
&icp_dump_args.cpu_addr, &icp_dump_args.buf_len);
if (rc) {
CAM_ERR(CAM_ICP, "Invalid addr %u rc %d",
dump_args->buf_handle, rc);
return rc;
}
if (icp_dump_args.buf_len <= dump_args->offset) {
CAM_WARN(CAM_ICP, "dump buffer overshoot len %zu offset %zu",
icp_dump_args.buf_len, dump_args->offset);
return -ENOSPC;
}
remain_len = icp_dump_args.buf_len - dump_args->offset;
min_len = sizeof(struct cam_icp_dump_header) +
(CAM_ICP_DUMP_NUM_WORDS * sizeof(uint64_t));
if (remain_len < min_len) {
CAM_WARN(CAM_ICP, "dump buffer exhaust remain %zu min %u",
remain_len, min_len);
return -ENOSPC;
}
dst = (uint8_t *)icp_dump_args.cpu_addr + dump_args->offset;
hdr = (struct cam_icp_dump_header *)dst;
scnprintf(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++ = req_ts.tv_sec;
*addr++ = req_ts.tv_nsec/NSEC_PER_USEC;
*addr++ = cur_ts.tv_sec;
*addr++ = cur_ts.tv_nsec/NSEC_PER_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));
CAM_DBG(CAM_ICP, "Offset before %zu after %zu",
dump_args->offset, icp_dump_args.offset);
dump_args->offset = icp_dump_args.offset;
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;
@@ -5850,6 +5960,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);

Voir le fichier

@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
*/
#ifndef CAM_ICP_HW_MGR_H
@@ -67,6 +67,12 @@
/* Current appliacble vote paths, based on number of UAPI definitions */
#define CAM_ICP_MAX_PER_PATH_VOTES 6
/*
* 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
@@ -171,6 +177,7 @@ struct cam_icp_clk_bw_req_internal_v2 {
* @clk_info: Clock information for a request
* @clk_info_v2: Clock info for AXI bw voting v2
* @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];
@@ -186,6 +193,7 @@ struct hfi_frame_process_info {
struct cam_icp_clk_bw_request clk_info[CAM_FRAME_CMD_MAX];
struct cam_icp_clk_bw_req_internal_v2 clk_info_v2[CAM_FRAME_CMD_MAX];
struct icp_frame_info frame_info[CAM_FRAME_CMD_MAX];
ktime_t submit_timestamp[CAM_FRAME_CMD_MAX];
};
/**

Voir le fichier

@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
*/
#ifndef CAM_A5_HW_INTF_H
@@ -27,6 +27,7 @@ enum cam_icp_a5_cmd_type {
CAM_ICP_A5_CMD_UBWC_CFG,
CAM_ICP_A5_CMD_PC_PREP,
CAM_ICP_A5_CMD_CLK_UPDATE,
CAM_ICP_A5_CMD_HW_DUMP,
CAM_ICP_A5_CMD_MAX,
};

Voir le fichier

@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
*/
#ifndef CAM_ICP_HW_MGR_INTF_H
@@ -27,6 +27,9 @@
#define CAM_ICP_DEFAULT_AXI_PATH CAM_AXI_PATH_DATA_ALL
#define CAM_ICP_DEFAULT_AXI_TRANSAC CAM_AXI_TRANSACTION_READ
#define CAM_ICP_DUMP_TAG_MAX_LEN 32
#define CAM_ICP_DUMP_NUM_WORDS 5
int cam_icp_hw_mgr_init(struct device_node *of_node,
uint64_t *hw_mgr_hdl, int *iommu_hdl);
@@ -44,4 +47,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;
size_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 {
uint8_t tag[CAM_ICP_DUMP_TAG_MAX_LEN];
uint64_t size;
int32_t word_size;
};
#endif /* CAM_ICP_HW_MGR_INTF_H */

Voir le fichier

@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
*/
#include <linux/debugfs.h>
@@ -83,6 +83,19 @@ 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_JPEG, "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)
{
@@ -145,6 +158,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,

Voir le fichier

@@ -488,6 +488,7 @@ static int cam_jpeg_mgr_process_cmd(void *priv, void *data)
rc);
goto end_callcb;
}
p_cfg_req->submit_timestamp = ktime_get();
mutex_unlock(&hw_mgr->hw_mgr_mutex);
return rc;
@@ -1491,6 +1492,143 @@ num_dev_failed:
return rc;
}
static int cam_jpeg_mgr_hw_dump(void *hw_mgr_priv, void *dump_hw_args)
{
int rc;
uint8_t *dst;
ktime_t cur_time;
size_t remain_len;
uint32_t min_len;
uint32_t dev_type;
uint64_t diff;
uint64_t *addr, *start;
struct timespec64 cur_ts;
struct timespec64 req_ts;
struct cam_jpeg_hw_mgr *hw_mgr;
struct cam_hw_dump_args *dump_args;
struct cam_jpeg_hw_cfg_req *p_cfg_req;
struct cam_jpeg_hw_ctx_data *ctx_data;
struct cam_jpeg_hw_dump_args jpeg_dump_args;
struct cam_jpeg_hw_dump_header *hdr;
if (!hw_mgr_priv || !dump_hw_args) {
CAM_ERR(CAM_JPEG, "Invalid args %pK %pK",
hw_mgr_priv, dump_hw_args);
return -EINVAL;
}
hw_mgr = hw_mgr_priv;
dump_args = (struct cam_hw_dump_args *)dump_hw_args;
ctx_data = (struct cam_jpeg_hw_ctx_data *)dump_args->ctxt_to_hw_map;
if (!ctx_data) {
CAM_ERR(CAM_JPEG, "Invalid context");
return -EINVAL;
}
mutex_lock(&hw_mgr->hw_mgr_mutex);
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:
cur_time = ktime_get();
diff = ktime_us_delta(p_cfg_req->submit_timestamp, cur_time);
cur_ts = ktime_to_timespec64(cur_time);
req_ts = ktime_to_timespec64(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,
req_ts.tv_sec,
req_ts.tv_nsec/NSEC_PER_USEC,
cur_ts.tv_sec,
cur_ts.tv_nsec/NSEC_PER_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,
req_ts.tv_sec,
req_ts.tv_nsec/NSEC_PER_USEC,
cur_ts.tv_sec,
cur_ts.tv_nsec/NSEC_PER_USEC);
rc = cam_mem_get_cpu_buf(dump_args->buf_handle,
&jpeg_dump_args.cpu_addr, &jpeg_dump_args.buf_len);
if (rc) {
CAM_ERR(CAM_JPEG, "Invalid handle %u rc %d",
dump_args->buf_handle, rc);
mutex_unlock(&hw_mgr->hw_mgr_mutex);
return -rc;
}
if (jpeg_dump_args.buf_len <= dump_args->offset) {
CAM_WARN(CAM_JPEG, "dump offset overshoot len %zu offset %zu",
jpeg_dump_args.buf_len, dump_args->offset);
mutex_unlock(&hw_mgr->hw_mgr_mutex);
return -ENOSPC;
}
remain_len = jpeg_dump_args.buf_len - dump_args->offset;
min_len = sizeof(struct cam_jpeg_hw_dump_header) +
(CAM_JPEG_HW_DUMP_NUM_WORDS * sizeof(uint64_t));
if (remain_len < min_len) {
CAM_WARN(CAM_JPEG, "dump buffer exhaust remain %zu min %u",
remain_len, min_len);
mutex_unlock(&hw_mgr->hw_mgr_mutex);
return -ENOSPC;
}
dst = (uint8_t *)jpeg_dump_args.cpu_addr + dump_args->offset;
hdr = (struct cam_jpeg_hw_dump_header *)dst;
scnprintf(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++ = req_ts.tv_sec;
*addr++ = req_ts.tv_nsec/NSEC_PER_USEC;
*addr++ = cur_ts.tv_sec;
*addr++ = cur_ts.tv_nsec/NSEC_PER_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));
}
mutex_unlock(&hw_mgr->hw_mgr_mutex);
CAM_DBG(CAM_JPEG, "Offset before %u after %u",
dump_args->offset, jpeg_dump_args.offset);
dump_args->offset = jpeg_dump_args.offset;
return rc;
}
static int cam_jpeg_mgr_cmd(void *hw_mgr_priv, void *cmd_args)
{
int rc = 0;
@@ -1544,6 +1682,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);

Voir le fichier

@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
*/
#ifndef CAM_JPEG_HW_MGR_H
@@ -21,6 +21,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
*
@@ -69,12 +75,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;
ktime_t submit_timestamp;
};
/**

Voir le fichier

@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
*/
#ifndef CAM_JPEG_HW_INTF_H
@@ -15,6 +15,9 @@
#define JPEG_VOTE 640000000
#define CAM_JPEG_HW_DUMP_TAG_MAX_LEN 32
#define CAM_JPEG_HW_DUMP_NUM_WORDS 5
enum cam_jpeg_hw_type {
CAM_JPEG_DEV_ENC,
CAM_JPEG_DEV_DMA,
@@ -27,9 +30,23 @@ struct cam_jpeg_set_irq_cb {
uint32_t b_set_cb;
};
struct cam_jpeg_hw_dump_args {
uint64_t request_id;
uintptr_t cpu_addr;
size_t offset;
size_t buf_len;
};
struct cam_jpeg_hw_dump_header {
uint8_t 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,
};

Voir le fichier

@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
*/
#ifndef CAM_JPEG_ENC_HW_INFO_TITAN170_H
@@ -66,6 +66,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,
}
};

Voir le fichier

@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
*/
#include <linux/of.h>
@@ -378,6 +378,81 @@ 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)
{
int i;
uint8_t *dst;
uint32_t *addr, *start;
uint32_t num_reg, min_len;
uint32_t reg_start_offset;
size_t remain_len;
struct cam_hw_soc_info *soc_info;
struct cam_jpeg_hw_dump_header *hdr;
struct cam_jpeg_enc_device_hw_info *hw_info;
struct cam_jpeg_enc_device_core_info *core_info;
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;
mutex_lock(&core_info->core_mutex);
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);
mutex_unlock(&core_info->core_mutex);
return -EINVAL;
}
spin_unlock(&jpeg_enc_dev->hw_lock);
if (dump_args->buf_len <= dump_args->offset) {
CAM_WARN(CAM_JPEG, "dump buffer overshoot %zu %zu",
dump_args->buf_len, dump_args->offset);
mutex_unlock(&core_info->core_mutex);
return -ENOSPC;
}
remain_len = dump_args->buf_len - dump_args->offset;
min_len = sizeof(struct cam_jpeg_hw_dump_header) +
soc_info->reg_map[0].size + sizeof(uint32_t);
if (remain_len < min_len) {
CAM_WARN(CAM_JPEG, "dump buffer exhaust %zu %u",
remain_len, min_len);
mutex_unlock(&core_info->core_mutex);
return -ENOSPC;
}
dst = (uint8_t *)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));
}
mutex_unlock(&core_info->core_mutex);
hdr->size = hdr->word_size * (addr - start);
dump_args->offset += hdr->size +
sizeof(struct cam_jpeg_hw_dump_header);
CAM_DBG(CAM_JPEG, "offset %zu", 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)
{
@@ -418,6 +493,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;

Voir le fichier

@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
*/
#ifndef CAM_JPEG_ENC_CORE_H
@@ -39,10 +39,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 {

Voir le fichier

@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
*/
#include <linux/module.h>
@@ -86,6 +86,21 @@ 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)
{
@@ -199,6 +214,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,

Voir le fichier

@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
*/
#include <linux/module.h>
@@ -649,6 +649,50 @@ 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 (rc) {
CAM_ERR(CAM_LRME, "Invalid handle %u rc %d",
dump_args->buf_handle, 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));
CAM_DBG(CAM_LRME, "Offset before %zu after %zu",
dump_args->offset, lrme_dump_args.offset);
dump_args->offset = lrme_dump_args.offset;
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;
@@ -1147,6 +1191,7 @@ int cam_lrme_hw_mgr_init(struct cam_hw_mgr_intf *hw_mgr_intf,
hw_mgr_intf->hw_flush = cam_lrme_mgr_hw_flush;
g_lrme_hw_mgr.event_cb = cam_lrme_dev_buf_done_cb;
hw_mgr_intf->hw_dump = cam_lrme_mgr_hw_dump;
cam_lrme_mgr_create_debugfs_entry();

Voir le fichier

@@ -3,6 +3,7 @@
* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
*/
#include <linux/timer.h>
#include "cam_lrme_hw_core.h"
#include "cam_lrme_hw_soc.h"
#include "cam_smmu_api.h"
@@ -21,6 +22,159 @@ 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)
{
int i;
uint8_t *dst;
uint32_t *addr, *start;
uint32_t num_reg, min_len;
size_t remain_len;
struct cam_hw_soc_info *soc_info;
struct cam_lrme_hw_dump_header *hdr;
if (!lrme_hw || !req || !dump_args) {
CAM_ERR(CAM_LRME, "Invalid params %pK, %pK, %pK",
lrme_hw, req, dump_args);
return -EINVAL;
}
soc_info = &lrme_hw->soc_info;
if (dump_args->buf_len <= dump_args->offset) {
CAM_WARN(CAM_LRME, "dump buffer overshoot len %zu offset %zu",
dump_args->buf_len, dump_args->offset);
return -ENOSPC;
}
remain_len = dump_args->buf_len - dump_args->offset;
min_len = sizeof(struct cam_lrme_hw_dump_header) +
soc_info->reg_map[0].size + sizeof(uint32_t);
if (remain_len < min_len) {
CAM_WARN(CAM_LRME, "dump buffer exhaust remain %zu min %u",
remain_len, min_len);
return -ENOSPC;
}
dst = (uint8_t *)dump_args->cpu_addr + dump_args->offset;
hdr = (struct cam_lrme_hw_dump_header *)dst;
scnprintf(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 %zu", 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)
{
uint8_t *dst;
ktime_t cur_time;
size_t remain_len;
uint32_t min_len;
uint64_t diff;
uint64_t *addr, *start;
struct timespec64 cur_ts;
struct timespec64 req_ts;
struct cam_lrme_core *lrme_core;
struct cam_lrme_frame_request *req = NULL;
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;
}
lrme_core = (struct cam_lrme_core *)lrme_hw->core_info;
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);
mutex_unlock(&lrme_hw->hw_mutex);
return 0;
}
cur_time = ktime_get();
diff = ktime_us_delta(req->submit_timestamp, cur_time);
cur_ts = ktime_to_timespec64(cur_time);
req_ts = ktime_to_timespec64(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_ts.tv_sec,
req_ts.tv_nsec/NSEC_PER_USEC,
cur_ts.tv_sec,
cur_ts.tv_nsec/NSEC_PER_USEC);
mutex_unlock(&lrme_hw->hw_mutex);
return 0;
}
CAM_INFO(CAM_LRME, "Error req %lld %ld:%06ld %ld:%06ld",
dump_args->request_id,
req_ts.tv_sec,
req_ts.tv_nsec/NSEC_PER_USEC,
cur_ts.tv_sec,
cur_ts.tv_nsec/NSEC_PER_USEC);
if (dump_args->buf_len <= dump_args->offset) {
CAM_WARN(CAM_LRME, "dump buffer overshoot len %zu offset %zu",
dump_args->buf_len, dump_args->offset);
mutex_unlock(&lrme_hw->hw_mutex);
return 0;
}
remain_len = dump_args->buf_len - dump_args->offset;
min_len = sizeof(struct cam_lrme_hw_dump_header) +
(CAM_LRME_HW_DUMP_NUM_WORDS * sizeof(uint64_t));
if (remain_len < min_len) {
CAM_WARN(CAM_LRME, "dump buffer exhaust remain %zu min %u",
remain_len, min_len);
mutex_unlock(&lrme_hw->hw_mutex);
return 0;
}
dst = (uint8_t *)dump_args->cpu_addr + dump_args->offset;
hdr = (struct cam_lrme_hw_dump_header *)dst;
scnprintf(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_ts.tv_sec;
*addr++ = req_ts.tv_nsec/NSEC_PER_USEC;
*addr++ = cur_ts.tv_sec;
*addr++ = cur_ts.tv_nsec/NSEC_PER_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);
mutex_unlock(&lrme_hw->hw_mutex);
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)
{
@@ -959,6 +1113,8 @@ int cam_lrme_hw_submit_req(void *hw_priv, void *hw_submit_args,
goto error;
}
frame_req->submit_timestamp = ktime_get();
switch (lrme_core->state) {
case CAM_LRME_CORE_STATE_PROCESSING:
lrme_core->state = CAM_LRME_CORE_STATE_REQ_PROC_PEND;
@@ -1268,6 +1424,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;
}

Voir le fichier

@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
*/
#ifndef _CAM_LRME_HW_CORE_H_
@@ -35,6 +35,10 @@
#define CAM_LRME_MAX_REG_PAIR_NUM 60
#define CAM_LRME_RESPONSE_TIME_THRESHOLD 100000
#define CAM_LRME_HW_DUMP_TAG_MAX_LEN 32
#define CAM_LRME_HW_DUMP_NUM_WORDS 5
/**
* enum cam_lrme_irq_set
*
@@ -432,6 +436,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 {
uint8_t 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);

Voir le fichier

@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
*/
#ifndef _CAM_LRME_HW_INTF_H_
@@ -59,12 +59,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,
};
/**
@@ -87,6 +89,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;
@@ -95,6 +98,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;
ktime_t submit_timestamp;
};
/**
@@ -192,6 +196,21 @@ struct cam_lrme_hw_submit_args {
struct cam_lrme_frame_request *frame_req;
};
/**
* struct cam_lrme_hw_dump_args : Args for dump request
*
* @request_id : Issue request id
* @cpu_addr : start address of the target buffer
* @offset : offset of the buffer
* @buf_len : Length of target buffer
*/
struct cam_lrme_hw_dump_args {
uint64_t request_id;
uintptr_t cpu_addr;
size_t offset;
size_t buf_len;
};
/**
* @brief : API to register LRME hw to platform framework.
* @return struct platform_device pointer on on success, or ERR_PTR() on error.
@@ -202,4 +221,6 @@ int cam_lrme_hw_init_module(void);
* @brief : API to remove LRME Hw from platform framework.
*/
void cam_lrme_hw_exit_module(void);
#endif /* _CAM_LRME_HW_INTF_H_ */