msm: camera: cpp: Issue CPP HALT on page fault
Issue CPP HALT in SMMU IRQ context and terminate smmu stall on CPP context bank. Debug information captured in cam_smmu worker thread. Drop frames on detecting page fault and report HW error on completion of fault handling. CRs-Fixed: 2042135 Change-Id: I22b8bd2879a9de5e8a92a94ee243604b7623cf27 Signed-off-by: Pratap Nirujogi <pratapn@codeaurora.org>
This commit is contained in:
parent
e3c33c9d53
commit
d8cee3f1eb
5 changed files with 234 additions and 37 deletions
|
@ -98,6 +98,7 @@ struct scratch_mapping {
|
||||||
struct cam_context_bank_info {
|
struct cam_context_bank_info {
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
struct dma_iommu_mapping *mapping;
|
struct dma_iommu_mapping *mapping;
|
||||||
|
enum iommu_attr attr;
|
||||||
dma_addr_t va_start;
|
dma_addr_t va_start;
|
||||||
size_t va_len;
|
size_t va_len;
|
||||||
const char *name;
|
const char *name;
|
||||||
|
@ -108,9 +109,8 @@ struct cam_context_bank_info {
|
||||||
struct mutex lock;
|
struct mutex lock;
|
||||||
int handle;
|
int handle;
|
||||||
enum cam_smmu_ops_param state;
|
enum cam_smmu_ops_param state;
|
||||||
void (*handler[CAM_SMMU_CB_MAX])(struct iommu_domain *,
|
client_handler handler[CAM_SMMU_CB_MAX];
|
||||||
struct device *, unsigned long,
|
client_reset_handler hw_reset_handler[CAM_SMMU_CB_MAX];
|
||||||
int, void*);
|
|
||||||
void *token[CAM_SMMU_CB_MAX];
|
void *token[CAM_SMMU_CB_MAX];
|
||||||
int cb_count;
|
int cb_count;
|
||||||
int ref_cnt;
|
int ref_cnt;
|
||||||
|
@ -354,9 +354,9 @@ static void cam_smmu_check_vaddr_in_range(int idx, void *vaddr)
|
||||||
}
|
}
|
||||||
|
|
||||||
void cam_smmu_reg_client_page_fault_handler(int handle,
|
void cam_smmu_reg_client_page_fault_handler(int handle,
|
||||||
void (*client_page_fault_handler)(struct iommu_domain *,
|
client_handler page_fault_handler,
|
||||||
struct device *, unsigned long,
|
client_reset_handler hw_reset_handler,
|
||||||
int, void*), void *token)
|
void *token)
|
||||||
{
|
{
|
||||||
int idx, i = 0;
|
int idx, i = 0;
|
||||||
|
|
||||||
|
@ -380,7 +380,7 @@ void cam_smmu_reg_client_page_fault_handler(int handle,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (client_page_fault_handler) {
|
if (page_fault_handler) {
|
||||||
if (iommu_cb_set.cb_info[idx].cb_count == CAM_SMMU_CB_MAX) {
|
if (iommu_cb_set.cb_info[idx].cb_count == CAM_SMMU_CB_MAX) {
|
||||||
pr_err("%s Should not regiester more handlers\n",
|
pr_err("%s Should not regiester more handlers\n",
|
||||||
iommu_cb_set.cb_info[idx].name);
|
iommu_cb_set.cb_info[idx].name);
|
||||||
|
@ -392,7 +392,9 @@ void cam_smmu_reg_client_page_fault_handler(int handle,
|
||||||
if (iommu_cb_set.cb_info[idx].token[i] == NULL) {
|
if (iommu_cb_set.cb_info[idx].token[i] == NULL) {
|
||||||
iommu_cb_set.cb_info[idx].token[i] = token;
|
iommu_cb_set.cb_info[idx].token[i] = token;
|
||||||
iommu_cb_set.cb_info[idx].handler[i] =
|
iommu_cb_set.cb_info[idx].handler[i] =
|
||||||
client_page_fault_handler;
|
page_fault_handler;
|
||||||
|
iommu_cb_set.cb_info[idx].hw_reset_handler[i] =
|
||||||
|
hw_reset_handler;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -420,6 +422,7 @@ static int cam_smmu_iommu_fault_handler(struct iommu_domain *domain,
|
||||||
{
|
{
|
||||||
char *cb_name;
|
char *cb_name;
|
||||||
int idx;
|
int idx;
|
||||||
|
int j;
|
||||||
struct cam_smmu_work_payload *payload;
|
struct cam_smmu_work_payload *payload;
|
||||||
|
|
||||||
if (!token) {
|
if (!token) {
|
||||||
|
@ -453,6 +456,18 @@ static int cam_smmu_iommu_fault_handler(struct iommu_domain *domain,
|
||||||
payload->token = token;
|
payload->token = token;
|
||||||
payload->idx = idx;
|
payload->idx = idx;
|
||||||
|
|
||||||
|
/* trigger hw reset handler */
|
||||||
|
mutex_lock(&iommu_cb_set.cb_info[idx].lock);
|
||||||
|
for (j = 0; j < CAM_SMMU_CB_MAX; j++) {
|
||||||
|
if ((iommu_cb_set.cb_info[idx].hw_reset_handler[j])) {
|
||||||
|
iommu_cb_set.cb_info[idx].hw_reset_handler[j](
|
||||||
|
payload->domain,
|
||||||
|
payload->dev,
|
||||||
|
iommu_cb_set.cb_info[idx].token[j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
|
||||||
|
|
||||||
mutex_lock(&iommu_cb_set.payload_list_lock);
|
mutex_lock(&iommu_cb_set.payload_list_lock);
|
||||||
list_add_tail(&payload->list, &iommu_cb_set.payload_list);
|
list_add_tail(&payload->list, &iommu_cb_set.payload_list);
|
||||||
mutex_unlock(&iommu_cb_set.payload_list_lock);
|
mutex_unlock(&iommu_cb_set.payload_list_lock);
|
||||||
|
@ -1031,7 +1046,8 @@ static int cam_smmu_map_buffer_and_add_to_list(int idx, int ion_fd,
|
||||||
buf = dma_buf_get(ion_fd);
|
buf = dma_buf_get(ion_fd);
|
||||||
if (IS_ERR_OR_NULL(buf)) {
|
if (IS_ERR_OR_NULL(buf)) {
|
||||||
rc = PTR_ERR(buf);
|
rc = PTR_ERR(buf);
|
||||||
pr_err("Error: dma get buf failed. fd = %d\n", ion_fd);
|
pr_err("Error: dma get buf failed. fd = %d rc = %d\n",
|
||||||
|
ion_fd, rc);
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1096,7 +1112,9 @@ static int cam_smmu_map_buffer_and_add_to_list(int idx, int ion_fd,
|
||||||
rc = -ENOSPC;
|
rc = -ENOSPC;
|
||||||
goto err_mapping_info;
|
goto err_mapping_info;
|
||||||
}
|
}
|
||||||
CDBG("ion_fd = %d, dev = %pK, paddr= %pK, len = %u\n", ion_fd,
|
CDBG("name %s ion_fd = %d, dev = %pK, paddr= %pK, len = %u\n",
|
||||||
|
iommu_cb_set.cb_info[idx].name,
|
||||||
|
ion_fd,
|
||||||
(void *)iommu_cb_set.cb_info[idx].dev,
|
(void *)iommu_cb_set.cb_info[idx].dev,
|
||||||
(void *)*paddr_ptr, (unsigned int)*len_ptr);
|
(void *)*paddr_ptr, (unsigned int)*len_ptr);
|
||||||
|
|
||||||
|
@ -1305,6 +1323,47 @@ int cam_smmu_get_handle(char *identifier, int *handle_ptr)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(cam_smmu_get_handle);
|
EXPORT_SYMBOL(cam_smmu_get_handle);
|
||||||
|
|
||||||
|
|
||||||
|
int cam_smmu_set_attr(int handle, uint32_t flags, int32_t *data)
|
||||||
|
{
|
||||||
|
int ret = 0, idx;
|
||||||
|
struct cam_context_bank_info *cb = NULL;
|
||||||
|
struct iommu_domain *domain = NULL;
|
||||||
|
|
||||||
|
CDBG("E: set_attr\n");
|
||||||
|
idx = GET_SMMU_TABLE_IDX(handle);
|
||||||
|
if (handle == HANDLE_INIT || idx < 0 || idx >= iommu_cb_set.cb_num) {
|
||||||
|
pr_err("Error: handle or index invalid. idx = %d hdl = %x\n",
|
||||||
|
idx, handle);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
mutex_lock(&iommu_cb_set.cb_info[idx].lock);
|
||||||
|
if (iommu_cb_set.cb_info[idx].handle != handle) {
|
||||||
|
pr_err("Error: hdl is not valid, table_hdl = %x, hdl = %x\n",
|
||||||
|
iommu_cb_set.cb_info[idx].handle, handle);
|
||||||
|
mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (iommu_cb_set.cb_info[idx].state == CAM_SMMU_DETACH) {
|
||||||
|
domain = iommu_cb_set.cb_info[idx].mapping->domain;
|
||||||
|
cb = &iommu_cb_set.cb_info[idx];
|
||||||
|
cb->attr |= flags;
|
||||||
|
/* set attributes */
|
||||||
|
ret = iommu_domain_set_attr(domain, cb->attr, (void *)data);
|
||||||
|
if (ret < 0) {
|
||||||
|
pr_err("Error: set attr\n");
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(cam_smmu_set_attr);
|
||||||
|
|
||||||
|
|
||||||
int cam_smmu_ops(int handle, enum cam_smmu_ops_param ops)
|
int cam_smmu_ops(int handle, enum cam_smmu_ops_param ops)
|
||||||
{
|
{
|
||||||
int ret = 0, idx;
|
int ret = 0, idx;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
|
/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License version 2 and
|
||||||
|
@ -49,6 +49,13 @@ enum cam_smmu_map_dir {
|
||||||
CAM_SMMU_MAP_INVALID
|
CAM_SMMU_MAP_INVALID
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef void (*client_handler)(struct iommu_domain *,
|
||||||
|
struct device *, unsigned long,
|
||||||
|
int, void*);
|
||||||
|
|
||||||
|
typedef void (*client_reset_handler)(struct iommu_domain *,
|
||||||
|
struct device *, void*);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param identifier: Unique identifier to be used by clients which they
|
* @param identifier: Unique identifier to be used by clients which they
|
||||||
* should get from device tree. CAM SMMU driver will
|
* should get from device tree. CAM SMMU driver will
|
||||||
|
@ -61,6 +68,16 @@ enum cam_smmu_map_dir {
|
||||||
*/
|
*/
|
||||||
int cam_smmu_get_handle(char *identifier, int *handle_ptr);
|
int cam_smmu_get_handle(char *identifier, int *handle_ptr);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param handle: Handle to identify the CAM SMMU client (VFE, CPP, FD etc.)
|
||||||
|
* @param flags : SMMU attribute type
|
||||||
|
* @data : Value of attribute
|
||||||
|
* @return Status of operation. Negative in case of error. Zero otherwise.
|
||||||
|
*/
|
||||||
|
int cam_smmu_set_attr(int handle, uint32_t flags, int32_t *data);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param handle: Handle to identify the CAM SMMU client (VFE, CPP, FD etc.)
|
* @param handle: Handle to identify the CAM SMMU client (VFE, CPP, FD etc.)
|
||||||
* @param op : Operation to be performed. Can be either CAM_SMMU_ATTACH
|
* @param op : Operation to be performed. Can be either CAM_SMMU_ATTACH
|
||||||
|
@ -215,11 +232,12 @@ int cam_smmu_find_index_by_handle(int hdl);
|
||||||
/**
|
/**
|
||||||
* @param handle: Handle to identify the CAM SMMU client (VFE, CPP, FD etc.)
|
* @param handle: Handle to identify the CAM SMMU client (VFE, CPP, FD etc.)
|
||||||
* @param client_page_fault_handler: It is triggered in IOMMU page fault
|
* @param client_page_fault_handler: It is triggered in IOMMU page fault
|
||||||
|
* @param client_hw_reset_handler: It is triggered in IOMMU page fault
|
||||||
* @param token: It is input param when trigger page fault handler
|
* @param token: It is input param when trigger page fault handler
|
||||||
*/
|
*/
|
||||||
void cam_smmu_reg_client_page_fault_handler(int handle,
|
void cam_smmu_reg_client_page_fault_handler(int handle,
|
||||||
void (*client_page_fault_handler)(struct iommu_domain *,
|
client_handler page_fault_handler,
|
||||||
struct device *, unsigned long,
|
client_reset_handler hw_reset_handler,
|
||||||
int, void*), void *token);
|
void *token);
|
||||||
|
|
||||||
#endif /* _CAM_SMMU_API_H_ */
|
#endif /* _CAM_SMMU_API_H_ */
|
||||||
|
|
|
@ -2320,7 +2320,9 @@ int msm_isp_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
|
||||||
|
|
||||||
cam_smmu_reg_client_page_fault_handler(
|
cam_smmu_reg_client_page_fault_handler(
|
||||||
vfe_dev->buf_mgr->iommu_hdl,
|
vfe_dev->buf_mgr->iommu_hdl,
|
||||||
msm_vfe_iommu_fault_handler, vfe_dev);
|
msm_vfe_iommu_fault_handler,
|
||||||
|
NULL,
|
||||||
|
vfe_dev);
|
||||||
mutex_unlock(&vfe_dev->core_mutex);
|
mutex_unlock(&vfe_dev->core_mutex);
|
||||||
mutex_unlock(&vfe_dev->realtime_mutex);
|
mutex_unlock(&vfe_dev->realtime_mutex);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -2368,7 +2370,7 @@ int msm_isp_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
|
||||||
/* Unregister page fault handler */
|
/* Unregister page fault handler */
|
||||||
cam_smmu_reg_client_page_fault_handler(
|
cam_smmu_reg_client_page_fault_handler(
|
||||||
vfe_dev->buf_mgr->iommu_hdl,
|
vfe_dev->buf_mgr->iommu_hdl,
|
||||||
NULL, vfe_dev);
|
NULL, NULL, vfe_dev);
|
||||||
|
|
||||||
rc = vfe_dev->hw_info->vfe_ops.axi_ops.halt(vfe_dev, 1);
|
rc = vfe_dev->hw_info->vfe_ops.axi_ops.halt(vfe_dev, 1);
|
||||||
if (rc <= 0)
|
if (rc <= 0)
|
||||||
|
|
|
@ -424,7 +424,17 @@ static unsigned long msm_cpp_queue_buffer_info(struct cpp_device *cpp_dev,
|
||||||
|
|
||||||
list_for_each_entry_safe(buff, save, buff_head, entry) {
|
list_for_each_entry_safe(buff, save, buff_head, entry) {
|
||||||
if (buff->map_info.buff_info.index == buffer_info->index) {
|
if (buff->map_info.buff_info.index == buffer_info->index) {
|
||||||
pr_err("error buffer index already queued\n");
|
pr_err("error buf index already queued\n");
|
||||||
|
pr_err("error buf, fd %d idx %d native %d ssid %d %d\n",
|
||||||
|
buffer_info->fd, buffer_info->index,
|
||||||
|
buffer_info->native_buff,
|
||||||
|
buff_queue->session_id,
|
||||||
|
buff_queue->stream_id);
|
||||||
|
pr_err("existing buf,fd %d idx %d native %d id %x\n",
|
||||||
|
buff->map_info.buff_info.fd,
|
||||||
|
buff->map_info.buff_info.index,
|
||||||
|
buff->map_info.buff_info.native_buff,
|
||||||
|
buff->map_info.buff_info.identity);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -439,6 +449,11 @@ static unsigned long msm_cpp_queue_buffer_info(struct cpp_device *cpp_dev,
|
||||||
buff->map_info.buff_info = *buffer_info;
|
buff->map_info.buff_info = *buffer_info;
|
||||||
buff->map_info.buf_fd = buffer_info->fd;
|
buff->map_info.buf_fd = buffer_info->fd;
|
||||||
|
|
||||||
|
trace_printk("fd %d index %d native_buff %d ssid %d %d\n",
|
||||||
|
buffer_info->fd, buffer_info->index,
|
||||||
|
buffer_info->native_buff, buff_queue->session_id,
|
||||||
|
buff_queue->stream_id);
|
||||||
|
|
||||||
if (buff_queue->security_mode == SECURE_MODE)
|
if (buff_queue->security_mode == SECURE_MODE)
|
||||||
rc = cam_smmu_get_stage2_phy_addr(cpp_dev->iommu_hdl,
|
rc = cam_smmu_get_stage2_phy_addr(cpp_dev->iommu_hdl,
|
||||||
buffer_info->fd, CAM_SMMU_MAP_RW,
|
buffer_info->fd, CAM_SMMU_MAP_RW,
|
||||||
|
@ -469,6 +484,11 @@ static void msm_cpp_dequeue_buffer_info(struct cpp_device *cpp_dev,
|
||||||
{
|
{
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
|
|
||||||
|
trace_printk("fd %d index %d native_buf %d ssid %d %d\n",
|
||||||
|
buff->map_info.buf_fd, buff->map_info.buff_info.index,
|
||||||
|
buff->map_info.buff_info.native_buff, buff_queue->session_id,
|
||||||
|
buff_queue->stream_id);
|
||||||
|
|
||||||
if (buff_queue->security_mode == SECURE_MODE)
|
if (buff_queue->security_mode == SECURE_MODE)
|
||||||
ret = cam_smmu_put_stage2_phy_addr(cpp_dev->iommu_hdl,
|
ret = cam_smmu_put_stage2_phy_addr(cpp_dev->iommu_hdl,
|
||||||
buff->map_info.buf_fd);
|
buff->map_info.buf_fd);
|
||||||
|
@ -770,6 +790,36 @@ static int msm_cpp_dump_addr(struct cpp_device *cpp_dev,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void msm_cpp_iommu_fault_reset_handler(
|
||||||
|
struct iommu_domain *domain, struct device *dev,
|
||||||
|
void *token)
|
||||||
|
{
|
||||||
|
struct cpp_device *cpp_dev = NULL;
|
||||||
|
|
||||||
|
if (!token) {
|
||||||
|
pr_err("Invalid token\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cpp_dev = token;
|
||||||
|
|
||||||
|
if (cpp_dev->fault_status != CPP_IOMMU_FAULT_NONE) {
|
||||||
|
pr_err("fault already detected %d\n", cpp_dev->fault_status);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cpp_dev->fault_status = CPP_IOMMU_FAULT_DETECTED;
|
||||||
|
|
||||||
|
/* mask IRQ status */
|
||||||
|
msm_camera_io_w(0xB, cpp_dev->cpp_hw_base + 0xC);
|
||||||
|
|
||||||
|
pr_err("Issue CPP HALT %d\n", cpp_dev->fault_status);
|
||||||
|
|
||||||
|
/* MMSS_A_CPP_AXI_CMD = 0x16C, reset 0x1*/
|
||||||
|
msm_camera_io_w(0x1, cpp_dev->cpp_hw_base + 0x16C);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
static void msm_cpp_iommu_fault_handler(struct iommu_domain *domain,
|
static void msm_cpp_iommu_fault_handler(struct iommu_domain *domain,
|
||||||
struct device *dev, unsigned long iova, int flags, void *token)
|
struct device *dev, unsigned long iova, int flags, void *token)
|
||||||
{
|
{
|
||||||
|
@ -777,50 +827,94 @@ static void msm_cpp_iommu_fault_handler(struct iommu_domain *domain,
|
||||||
struct msm_cpp_frame_info_t *processed_frame[MAX_CPP_PROCESSING_FRAME];
|
struct msm_cpp_frame_info_t *processed_frame[MAX_CPP_PROCESSING_FRAME];
|
||||||
int32_t i = 0, queue_len = 0;
|
int32_t i = 0, queue_len = 0;
|
||||||
struct msm_device_queue *queue = NULL;
|
struct msm_device_queue *queue = NULL;
|
||||||
int32_t rc = 0;
|
int32_t ifd, ofd, dfd, t0fd, t1fd;
|
||||||
|
int counter = 0;
|
||||||
|
u32 result;
|
||||||
|
|
||||||
if (token) {
|
if (token) {
|
||||||
cpp_dev = token;
|
cpp_dev = token;
|
||||||
|
|
||||||
|
if (cpp_dev->fault_status != CPP_IOMMU_FAULT_DETECTED) {
|
||||||
|
pr_err("fault recovery already done %d\n",
|
||||||
|
cpp_dev->fault_status);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
disable_irq(cpp_dev->irq->start);
|
disable_irq(cpp_dev->irq->start);
|
||||||
if (atomic_read(&cpp_timer.used)) {
|
if (atomic_read(&cpp_timer.used)) {
|
||||||
atomic_set(&cpp_timer.used, 0);
|
atomic_set(&cpp_timer.used, 0);
|
||||||
del_timer_sync(&cpp_timer.cpp_timer);
|
del_timer_sync(&cpp_timer.cpp_timer);
|
||||||
}
|
}
|
||||||
mutex_lock(&cpp_dev->mutex);
|
|
||||||
tasklet_kill(&cpp_dev->cpp_tasklet);
|
tasklet_kill(&cpp_dev->cpp_tasklet);
|
||||||
rc = cpp_load_fw(cpp_dev, cpp_dev->fw_name_bin);
|
|
||||||
if (rc < 0) {
|
pr_err("in recovery, HALT status = 0x%x\n",
|
||||||
pr_err("load fw failure %d-retry\n", rc);
|
msm_camera_io_r(cpp_dev->cpp_hw_base + 0x10));
|
||||||
rc = msm_cpp_reset_vbif_and_load_fw(cpp_dev);
|
|
||||||
if (rc < 0) {
|
while (counter < MSM_CPP_POLL_RETRIES) {
|
||||||
msm_cpp_set_micro_irq_mask(cpp_dev, 1, 0x8);
|
result = msm_camera_io_r(cpp_dev->cpp_hw_base + 0x10);
|
||||||
mutex_unlock(&cpp_dev->mutex);
|
if (result & 0x2)
|
||||||
return;
|
break;
|
||||||
}
|
usleep_range(100, 200);
|
||||||
|
counter++;
|
||||||
}
|
}
|
||||||
|
/* MMSS_A_CPP_IRQ_STATUS_0 = 0x10 */
|
||||||
|
pr_err("counter %d HALT status later = 0x%x\n",
|
||||||
|
counter,
|
||||||
|
msm_camera_io_r(cpp_dev->cpp_hw_base + 0x10));
|
||||||
|
|
||||||
|
/* MMSS_A_CPP_RST_CMD_0 = 0x8 firmware reset = 0x3FFFF */
|
||||||
|
msm_camera_io_w(0x3FFFF, cpp_dev->cpp_hw_base + 0x8);
|
||||||
|
|
||||||
|
counter = 0;
|
||||||
|
while (counter < MSM_CPP_POLL_RETRIES) {
|
||||||
|
result = msm_camera_io_r(cpp_dev->cpp_hw_base + 0x10);
|
||||||
|
if (result & 0x1)
|
||||||
|
break;
|
||||||
|
usleep_range(100, 200);
|
||||||
|
counter++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* MMSS_A_CPP_IRQ_STATUS_0 = 0x10 */
|
||||||
|
pr_err("counter %d after reset IRQ_STATUS_0 = 0x%x\n",
|
||||||
|
counter,
|
||||||
|
msm_camera_io_r(cpp_dev->cpp_hw_base + 0x10));
|
||||||
|
|
||||||
|
/* MMSS_A_CPP_AXI_CMD = 0x16C, reset 0x1*/
|
||||||
|
msm_camera_io_w(0x0, cpp_dev->cpp_hw_base + 0x16C);
|
||||||
|
|
||||||
queue = &cpp_timer.data.cpp_dev->processing_q;
|
queue = &cpp_timer.data.cpp_dev->processing_q;
|
||||||
queue_len = queue->len;
|
queue_len = queue->len;
|
||||||
if (!queue_len) {
|
if (!queue_len) {
|
||||||
pr_err("%s:%d: Invalid queuelen\n", __func__, __LINE__);
|
pr_err("%s:%d: Invalid queuelen\n", __func__, __LINE__);
|
||||||
msm_cpp_set_micro_irq_mask(cpp_dev, 1, 0x8);
|
|
||||||
mutex_unlock(&cpp_dev->mutex);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < queue_len; i++) {
|
for (i = 0; i < queue_len; i++) {
|
||||||
if (cpp_timer.data.processed_frame[i]) {
|
if (cpp_timer.data.processed_frame[i]) {
|
||||||
processed_frame[i] =
|
processed_frame[i] =
|
||||||
cpp_timer.data.processed_frame[i];
|
cpp_timer.data.processed_frame[i];
|
||||||
pr_err("Fault on identity=0x%x, frame_id=%03d\n",
|
ifd = processed_frame[i]->input_buffer_info.fd;
|
||||||
|
ofd = processed_frame[i]->
|
||||||
|
output_buffer_info[0].fd;
|
||||||
|
dfd = processed_frame[i]->
|
||||||
|
duplicate_buffer_info.fd;
|
||||||
|
t0fd = processed_frame[i]->
|
||||||
|
tnr_scratch_buffer_info[0].fd;
|
||||||
|
t1fd = processed_frame[i]->
|
||||||
|
tnr_scratch_buffer_info[1].fd;
|
||||||
|
pr_err("Fault on identity=0x%x, frame_id=%03d\n",
|
||||||
processed_frame[i]->identity,
|
processed_frame[i]->identity,
|
||||||
processed_frame[i]->frame_id);
|
processed_frame[i]->frame_id);
|
||||||
|
pr_err("ifd %d ofd %d dfd %d t0fd %d t1fd %d\n",
|
||||||
|
ifd, ofd, dfd, t0fd, t1fd);
|
||||||
msm_cpp_dump_addr(cpp_dev, processed_frame[i]);
|
msm_cpp_dump_addr(cpp_dev, processed_frame[i]);
|
||||||
msm_cpp_dump_frame_cmd(processed_frame[i]);
|
msm_cpp_dump_frame_cmd(processed_frame[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
msm_cpp_flush_queue_and_release_buffer(cpp_dev, queue_len);
|
msm_cpp_flush_queue_and_release_buffer(cpp_dev, queue_len);
|
||||||
msm_cpp_set_micro_irq_mask(cpp_dev, 1, 0x8);
|
cpp_dev->fault_status = CPP_IOMMU_FAULT_RECOVERED;
|
||||||
mutex_unlock(&cpp_dev->mutex);
|
pr_err("fault recovery successful\n");
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cpp_init_mem(struct cpp_device *cpp_dev)
|
static int cpp_init_mem(struct cpp_device *cpp_dev)
|
||||||
|
@ -842,7 +936,9 @@ static int cpp_init_mem(struct cpp_device *cpp_dev)
|
||||||
cpp_dev->iommu_hdl = iommu_hdl;
|
cpp_dev->iommu_hdl = iommu_hdl;
|
||||||
cam_smmu_reg_client_page_fault_handler(
|
cam_smmu_reg_client_page_fault_handler(
|
||||||
cpp_dev->iommu_hdl,
|
cpp_dev->iommu_hdl,
|
||||||
msm_cpp_iommu_fault_handler, cpp_dev);
|
msm_cpp_iommu_fault_handler,
|
||||||
|
msm_cpp_iommu_fault_reset_handler,
|
||||||
|
cpp_dev);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -981,6 +1077,7 @@ static int cpp_init_hardware(struct cpp_device *cpp_dev)
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
uint32_t vbif_version;
|
uint32_t vbif_version;
|
||||||
cpp_dev->turbo_vote = 0;
|
cpp_dev->turbo_vote = 0;
|
||||||
|
cpp_dev->fault_status = CPP_IOMMU_FAULT_NONE;
|
||||||
|
|
||||||
rc = msm_camera_regulator_enable(cpp_dev->cpp_vdd,
|
rc = msm_camera_regulator_enable(cpp_dev->cpp_vdd,
|
||||||
cpp_dev->num_reg, true);
|
cpp_dev->num_reg, true);
|
||||||
|
@ -1115,7 +1212,7 @@ static void cpp_release_hardware(struct cpp_device *cpp_dev)
|
||||||
rc = msm_cpp_update_bandwidth_setting(cpp_dev, 0, 0);
|
rc = msm_cpp_update_bandwidth_setting(cpp_dev, 0, 0);
|
||||||
}
|
}
|
||||||
cpp_dev->stream_cnt = 0;
|
cpp_dev->stream_cnt = 0;
|
||||||
|
pr_info("cpp hw release done\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t cpp_load_fw(struct cpp_device *cpp_dev, char *fw_name_bin)
|
static int32_t cpp_load_fw(struct cpp_device *cpp_dev, char *fw_name_bin)
|
||||||
|
@ -2536,6 +2633,16 @@ static int msm_cpp_cfg_frame(struct cpp_device *cpp_dev,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (cpp_dev->fault_status == CPP_IOMMU_FAULT_RECOVERED) {
|
||||||
|
pr_err("Error, page fault occurred %d\n",
|
||||||
|
cpp_dev->fault_status);
|
||||||
|
return -EINVAL;
|
||||||
|
} else if (cpp_dev->fault_status == CPP_IOMMU_FAULT_DETECTED) {
|
||||||
|
pr_err("drop frame, page fault occurred %d\n",
|
||||||
|
cpp_dev->fault_status);
|
||||||
|
return -EFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
if (cpp_frame_msg[new_frame->msg_len - 1] !=
|
if (cpp_frame_msg[new_frame->msg_len - 1] !=
|
||||||
MSM_CPP_MSG_ID_TRAILER) {
|
MSM_CPP_MSG_ID_TRAILER) {
|
||||||
pr_err("Invalid frame message\n");
|
pr_err("Invalid frame message\n");
|
||||||
|
@ -3501,6 +3608,7 @@ STREAM_BUFF_END:
|
||||||
break;
|
break;
|
||||||
case VIDIOC_MSM_CPP_IOMMU_ATTACH: {
|
case VIDIOC_MSM_CPP_IOMMU_ATTACH: {
|
||||||
if (cpp_dev->iommu_state == CPP_IOMMU_STATE_DETACHED) {
|
if (cpp_dev->iommu_state == CPP_IOMMU_STATE_DETACHED) {
|
||||||
|
int32_t stall_disable;
|
||||||
struct msm_camera_smmu_attach_type cpp_attach_info;
|
struct msm_camera_smmu_attach_type cpp_attach_info;
|
||||||
|
|
||||||
memset(&cpp_attach_info, 0, sizeof(cpp_attach_info));
|
memset(&cpp_attach_info, 0, sizeof(cpp_attach_info));
|
||||||
|
@ -3513,7 +3621,10 @@ STREAM_BUFF_END:
|
||||||
}
|
}
|
||||||
|
|
||||||
cpp_dev->security_mode = cpp_attach_info.attach;
|
cpp_dev->security_mode = cpp_attach_info.attach;
|
||||||
|
stall_disable = 1;
|
||||||
|
/* disable smmu stall on fault */
|
||||||
|
cam_smmu_set_attr(cpp_dev->iommu_hdl,
|
||||||
|
DOMAIN_ATTR_CB_STALL_DISABLE, &stall_disable);
|
||||||
if (cpp_dev->security_mode == SECURE_MODE) {
|
if (cpp_dev->security_mode == SECURE_MODE) {
|
||||||
rc = cam_smmu_ops(cpp_dev->iommu_hdl,
|
rc = cam_smmu_ops(cpp_dev->iommu_hdl,
|
||||||
CAM_SMMU_ATTACH_SEC_CPP);
|
CAM_SMMU_ATTACH_SEC_CPP);
|
||||||
|
|
|
@ -130,6 +130,12 @@ enum cpp_iommu_state {
|
||||||
CPP_IOMMU_STATE_ATTACHED,
|
CPP_IOMMU_STATE_ATTACHED,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum cpp_iommu_fault_state {
|
||||||
|
CPP_IOMMU_FAULT_NONE,
|
||||||
|
CPP_IOMMU_FAULT_DETECTED,
|
||||||
|
CPP_IOMMU_FAULT_RECOVERED,
|
||||||
|
};
|
||||||
|
|
||||||
enum msm_queue {
|
enum msm_queue {
|
||||||
MSM_CAM_Q_CTRL, /* control command or control command status */
|
MSM_CAM_Q_CTRL, /* control command or control command status */
|
||||||
MSM_CAM_Q_VFE_EVT, /* adsp event */
|
MSM_CAM_Q_VFE_EVT, /* adsp event */
|
||||||
|
@ -287,6 +293,7 @@ struct cpp_device {
|
||||||
struct msm_cpp_vbif_data *vbif_data;
|
struct msm_cpp_vbif_data *vbif_data;
|
||||||
bool turbo_vote;
|
bool turbo_vote;
|
||||||
struct cx_ipeak_client *cpp_cx_ipeak;
|
struct cx_ipeak_client *cpp_cx_ipeak;
|
||||||
|
enum cpp_iommu_fault_state fault_status;
|
||||||
};
|
};
|
||||||
|
|
||||||
int msm_cpp_set_micro_clk(struct cpp_device *cpp_dev);
|
int msm_cpp_set_micro_clk(struct cpp_device *cpp_dev);
|
||||||
|
|
Loading…
Add table
Reference in a new issue