Loading drivers/media/platform/msm/camera_v2/common/cam_smmu_api.c +69 −10 Original line number Diff line number Diff line Loading @@ -98,6 +98,7 @@ struct scratch_mapping { struct cam_context_bank_info { struct device *dev; struct dma_iommu_mapping *mapping; enum iommu_attr attr; dma_addr_t va_start; size_t va_len; const char *name; Loading @@ -108,9 +109,8 @@ struct cam_context_bank_info { struct mutex lock; int handle; enum cam_smmu_ops_param state; void (*handler[CAM_SMMU_CB_MAX])(struct iommu_domain *, struct device *, unsigned long, int, void*); client_handler handler[CAM_SMMU_CB_MAX]; client_reset_handler hw_reset_handler[CAM_SMMU_CB_MAX]; void *token[CAM_SMMU_CB_MAX]; int cb_count; int ref_cnt; Loading Loading @@ -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 (*client_page_fault_handler)(struct iommu_domain *, struct device *, unsigned long, int, void*), void *token) client_handler page_fault_handler, client_reset_handler hw_reset_handler, void *token) { int idx, i = 0; Loading @@ -380,7 +380,7 @@ void cam_smmu_reg_client_page_fault_handler(int handle, return; } if (client_page_fault_handler) { if (page_fault_handler) { if (iommu_cb_set.cb_info[idx].cb_count == CAM_SMMU_CB_MAX) { pr_err("%s Should not regiester more handlers\n", iommu_cb_set.cb_info[idx].name); Loading @@ -392,7 +392,9 @@ void cam_smmu_reg_client_page_fault_handler(int handle, 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].handler[i] = client_page_fault_handler; page_fault_handler; iommu_cb_set.cb_info[idx].hw_reset_handler[i] = hw_reset_handler; break; } } Loading Loading @@ -420,6 +422,7 @@ static int cam_smmu_iommu_fault_handler(struct iommu_domain *domain, { char *cb_name; int idx; int j; struct cam_smmu_work_payload *payload; if (!token) { Loading Loading @@ -453,6 +456,18 @@ static int cam_smmu_iommu_fault_handler(struct iommu_domain *domain, payload->token = token; 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); list_add_tail(&payload->list, &iommu_cb_set.payload_list); mutex_unlock(&iommu_cb_set.payload_list_lock); Loading Loading @@ -1038,7 +1053,8 @@ static int cam_smmu_map_buffer_and_add_to_list(int idx, int ion_fd, buf = dma_buf_get(ion_fd); if (IS_ERR_OR_NULL(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; } Loading Loading @@ -1103,7 +1119,9 @@ static int cam_smmu_map_buffer_and_add_to_list(int idx, int ion_fd, rc = -ENOSPC; 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 *)*paddr_ptr, (unsigned int)*len_ptr); Loading Loading @@ -1312,6 +1330,47 @@ int cam_smmu_get_handle(char *identifier, int *handle_ptr) } 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 ret = 0, idx; Loading drivers/media/platform/msm/camera_v2/common/cam_smmu_api.h +22 −4 Original line number Diff line number Diff line /* 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 * it under the terms of the GNU General Public License version 2 and Loading Loading @@ -49,6 +49,13 @@ enum cam_smmu_map_dir { 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 * should get from device tree. CAM SMMU driver will Loading @@ -61,6 +68,16 @@ enum cam_smmu_map_dir { */ 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 op : Operation to be performed. Can be either CAM_SMMU_ATTACH Loading Loading @@ -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 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 */ void cam_smmu_reg_client_page_fault_handler(int handle, void (*client_page_fault_handler)(struct iommu_domain *, struct device *, unsigned long, int, void*), void *token); client_handler page_fault_handler, client_reset_handler hw_reset_handler, void *token); #endif /* _CAM_SMMU_API_H_ */ drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c +4 −2 Original line number Diff line number Diff line Loading @@ -2318,7 +2318,9 @@ int msm_isp_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) cam_smmu_reg_client_page_fault_handler( 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->realtime_mutex); return 0; Loading Loading @@ -2367,7 +2369,7 @@ int msm_isp_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) /* Unregister page fault handler */ cam_smmu_reg_client_page_fault_handler( 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); if (rc <= 0) Loading drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c +132 −21 Original line number Diff line number Diff line Loading @@ -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) { 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; } } Loading @@ -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.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) rc = cam_smmu_get_stage2_phy_addr(cpp_dev->iommu_hdl, buffer_info->fd, CAM_SMMU_MAP_RW, Loading Loading @@ -469,6 +484,11 @@ static void msm_cpp_dequeue_buffer_info(struct cpp_device *cpp_dev, { 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) ret = cam_smmu_put_stage2_phy_addr(cpp_dev->iommu_hdl, buff->map_info.buf_fd); Loading Loading @@ -770,6 +790,36 @@ static int msm_cpp_dump_addr(struct cpp_device *cpp_dev, 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, struct device *dev, unsigned long iova, int flags, void *token) { Loading @@ -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]; int32_t i = 0, queue_len = 0; struct msm_device_queue *queue = NULL; int32_t rc = 0; int32_t ifd, ofd, dfd, t0fd, t1fd; int counter = 0; u32 result; if (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); if (atomic_read(&cpp_timer.used)) { atomic_set(&cpp_timer.used, 0); del_timer_sync(&cpp_timer.cpp_timer); } mutex_lock(&cpp_dev->mutex); tasklet_kill(&cpp_dev->cpp_tasklet); rc = cpp_load_fw(cpp_dev, cpp_dev->fw_name_bin); if (rc < 0) { pr_err("load fw failure %d-retry\n", rc); rc = msm_cpp_reset_vbif_and_load_fw(cpp_dev); if (rc < 0) { msm_cpp_set_micro_irq_mask(cpp_dev, 1, 0x8); mutex_unlock(&cpp_dev->mutex); return; pr_err("in recovery, HALT status = 0x%x\n", msm_camera_io_r(cpp_dev->cpp_hw_base + 0x10)); while (counter < MSM_CPP_POLL_RETRIES) { result = msm_camera_io_r(cpp_dev->cpp_hw_base + 0x10); if (result & 0x2) 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_len = queue->len; if (!queue_len) { 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++) { if (cpp_timer.data.processed_frame[i]) { processed_frame[i] = cpp_timer.data.processed_frame[i]; 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]->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_frame_cmd(processed_frame[i]); } } msm_cpp_flush_queue_and_release_buffer(cpp_dev, queue_len); msm_cpp_set_micro_irq_mask(cpp_dev, 1, 0x8); mutex_unlock(&cpp_dev->mutex); cpp_dev->fault_status = CPP_IOMMU_FAULT_RECOVERED; pr_err("fault recovery successful\n"); } return; } static int cpp_init_mem(struct cpp_device *cpp_dev) Loading @@ -842,7 +936,9 @@ static int cpp_init_mem(struct cpp_device *cpp_dev) cpp_dev->iommu_hdl = iommu_hdl; cam_smmu_reg_client_page_fault_handler( 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; } Loading Loading @@ -981,6 +1077,7 @@ static int cpp_init_hardware(struct cpp_device *cpp_dev) int rc = 0; uint32_t vbif_version; cpp_dev->turbo_vote = 0; cpp_dev->fault_status = CPP_IOMMU_FAULT_NONE; rc = msm_camera_regulator_enable(cpp_dev->cpp_vdd, cpp_dev->num_reg, true); Loading Loading @@ -1115,7 +1212,7 @@ static void cpp_release_hardware(struct cpp_device *cpp_dev) rc = msm_cpp_update_bandwidth_setting(cpp_dev, 0, 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) Loading Loading @@ -2536,6 +2633,16 @@ static int msm_cpp_cfg_frame(struct cpp_device *cpp_dev, 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] != MSM_CPP_MSG_ID_TRAILER) { pr_err("Invalid frame message\n"); Loading Loading @@ -3523,6 +3630,7 @@ STREAM_BUFF_END: break; case VIDIOC_MSM_CPP_IOMMU_ATTACH: { if (cpp_dev->iommu_state == CPP_IOMMU_STATE_DETACHED) { int32_t stall_disable; struct msm_camera_smmu_attach_type cpp_attach_info; if (ioctl_ptr->len != Loading @@ -3540,7 +3648,10 @@ STREAM_BUFF_END: } 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) { rc = cam_smmu_ops(cpp_dev->iommu_hdl, CAM_SMMU_ATTACH_SEC_CPP); Loading drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h +7 −0 Original line number Diff line number Diff line Loading @@ -130,6 +130,12 @@ enum cpp_iommu_state { CPP_IOMMU_STATE_ATTACHED, }; enum cpp_iommu_fault_state { CPP_IOMMU_FAULT_NONE, CPP_IOMMU_FAULT_DETECTED, CPP_IOMMU_FAULT_RECOVERED, }; enum msm_queue { MSM_CAM_Q_CTRL, /* control command or control command status */ MSM_CAM_Q_VFE_EVT, /* adsp event */ Loading Loading @@ -287,6 +293,7 @@ struct cpp_device { struct msm_cpp_vbif_data *vbif_data; bool turbo_vote; 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); Loading Loading
drivers/media/platform/msm/camera_v2/common/cam_smmu_api.c +69 −10 Original line number Diff line number Diff line Loading @@ -98,6 +98,7 @@ struct scratch_mapping { struct cam_context_bank_info { struct device *dev; struct dma_iommu_mapping *mapping; enum iommu_attr attr; dma_addr_t va_start; size_t va_len; const char *name; Loading @@ -108,9 +109,8 @@ struct cam_context_bank_info { struct mutex lock; int handle; enum cam_smmu_ops_param state; void (*handler[CAM_SMMU_CB_MAX])(struct iommu_domain *, struct device *, unsigned long, int, void*); client_handler handler[CAM_SMMU_CB_MAX]; client_reset_handler hw_reset_handler[CAM_SMMU_CB_MAX]; void *token[CAM_SMMU_CB_MAX]; int cb_count; int ref_cnt; Loading Loading @@ -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 (*client_page_fault_handler)(struct iommu_domain *, struct device *, unsigned long, int, void*), void *token) client_handler page_fault_handler, client_reset_handler hw_reset_handler, void *token) { int idx, i = 0; Loading @@ -380,7 +380,7 @@ void cam_smmu_reg_client_page_fault_handler(int handle, return; } if (client_page_fault_handler) { if (page_fault_handler) { if (iommu_cb_set.cb_info[idx].cb_count == CAM_SMMU_CB_MAX) { pr_err("%s Should not regiester more handlers\n", iommu_cb_set.cb_info[idx].name); Loading @@ -392,7 +392,9 @@ void cam_smmu_reg_client_page_fault_handler(int handle, 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].handler[i] = client_page_fault_handler; page_fault_handler; iommu_cb_set.cb_info[idx].hw_reset_handler[i] = hw_reset_handler; break; } } Loading Loading @@ -420,6 +422,7 @@ static int cam_smmu_iommu_fault_handler(struct iommu_domain *domain, { char *cb_name; int idx; int j; struct cam_smmu_work_payload *payload; if (!token) { Loading Loading @@ -453,6 +456,18 @@ static int cam_smmu_iommu_fault_handler(struct iommu_domain *domain, payload->token = token; 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); list_add_tail(&payload->list, &iommu_cb_set.payload_list); mutex_unlock(&iommu_cb_set.payload_list_lock); Loading Loading @@ -1038,7 +1053,8 @@ static int cam_smmu_map_buffer_and_add_to_list(int idx, int ion_fd, buf = dma_buf_get(ion_fd); if (IS_ERR_OR_NULL(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; } Loading Loading @@ -1103,7 +1119,9 @@ static int cam_smmu_map_buffer_and_add_to_list(int idx, int ion_fd, rc = -ENOSPC; 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 *)*paddr_ptr, (unsigned int)*len_ptr); Loading Loading @@ -1312,6 +1330,47 @@ int cam_smmu_get_handle(char *identifier, int *handle_ptr) } 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 ret = 0, idx; Loading
drivers/media/platform/msm/camera_v2/common/cam_smmu_api.h +22 −4 Original line number Diff line number Diff line /* 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 * it under the terms of the GNU General Public License version 2 and Loading Loading @@ -49,6 +49,13 @@ enum cam_smmu_map_dir { 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 * should get from device tree. CAM SMMU driver will Loading @@ -61,6 +68,16 @@ enum cam_smmu_map_dir { */ 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 op : Operation to be performed. Can be either CAM_SMMU_ATTACH Loading Loading @@ -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 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 */ void cam_smmu_reg_client_page_fault_handler(int handle, void (*client_page_fault_handler)(struct iommu_domain *, struct device *, unsigned long, int, void*), void *token); client_handler page_fault_handler, client_reset_handler hw_reset_handler, void *token); #endif /* _CAM_SMMU_API_H_ */
drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c +4 −2 Original line number Diff line number Diff line Loading @@ -2318,7 +2318,9 @@ int msm_isp_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) cam_smmu_reg_client_page_fault_handler( 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->realtime_mutex); return 0; Loading Loading @@ -2367,7 +2369,7 @@ int msm_isp_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) /* Unregister page fault handler */ cam_smmu_reg_client_page_fault_handler( 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); if (rc <= 0) Loading
drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c +132 −21 Original line number Diff line number Diff line Loading @@ -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) { 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; } } Loading @@ -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.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) rc = cam_smmu_get_stage2_phy_addr(cpp_dev->iommu_hdl, buffer_info->fd, CAM_SMMU_MAP_RW, Loading Loading @@ -469,6 +484,11 @@ static void msm_cpp_dequeue_buffer_info(struct cpp_device *cpp_dev, { 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) ret = cam_smmu_put_stage2_phy_addr(cpp_dev->iommu_hdl, buff->map_info.buf_fd); Loading Loading @@ -770,6 +790,36 @@ static int msm_cpp_dump_addr(struct cpp_device *cpp_dev, 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, struct device *dev, unsigned long iova, int flags, void *token) { Loading @@ -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]; int32_t i = 0, queue_len = 0; struct msm_device_queue *queue = NULL; int32_t rc = 0; int32_t ifd, ofd, dfd, t0fd, t1fd; int counter = 0; u32 result; if (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); if (atomic_read(&cpp_timer.used)) { atomic_set(&cpp_timer.used, 0); del_timer_sync(&cpp_timer.cpp_timer); } mutex_lock(&cpp_dev->mutex); tasklet_kill(&cpp_dev->cpp_tasklet); rc = cpp_load_fw(cpp_dev, cpp_dev->fw_name_bin); if (rc < 0) { pr_err("load fw failure %d-retry\n", rc); rc = msm_cpp_reset_vbif_and_load_fw(cpp_dev); if (rc < 0) { msm_cpp_set_micro_irq_mask(cpp_dev, 1, 0x8); mutex_unlock(&cpp_dev->mutex); return; pr_err("in recovery, HALT status = 0x%x\n", msm_camera_io_r(cpp_dev->cpp_hw_base + 0x10)); while (counter < MSM_CPP_POLL_RETRIES) { result = msm_camera_io_r(cpp_dev->cpp_hw_base + 0x10); if (result & 0x2) 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_len = queue->len; if (!queue_len) { 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++) { if (cpp_timer.data.processed_frame[i]) { processed_frame[i] = cpp_timer.data.processed_frame[i]; 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]->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_frame_cmd(processed_frame[i]); } } msm_cpp_flush_queue_and_release_buffer(cpp_dev, queue_len); msm_cpp_set_micro_irq_mask(cpp_dev, 1, 0x8); mutex_unlock(&cpp_dev->mutex); cpp_dev->fault_status = CPP_IOMMU_FAULT_RECOVERED; pr_err("fault recovery successful\n"); } return; } static int cpp_init_mem(struct cpp_device *cpp_dev) Loading @@ -842,7 +936,9 @@ static int cpp_init_mem(struct cpp_device *cpp_dev) cpp_dev->iommu_hdl = iommu_hdl; cam_smmu_reg_client_page_fault_handler( 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; } Loading Loading @@ -981,6 +1077,7 @@ static int cpp_init_hardware(struct cpp_device *cpp_dev) int rc = 0; uint32_t vbif_version; cpp_dev->turbo_vote = 0; cpp_dev->fault_status = CPP_IOMMU_FAULT_NONE; rc = msm_camera_regulator_enable(cpp_dev->cpp_vdd, cpp_dev->num_reg, true); Loading Loading @@ -1115,7 +1212,7 @@ static void cpp_release_hardware(struct cpp_device *cpp_dev) rc = msm_cpp_update_bandwidth_setting(cpp_dev, 0, 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) Loading Loading @@ -2536,6 +2633,16 @@ static int msm_cpp_cfg_frame(struct cpp_device *cpp_dev, 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] != MSM_CPP_MSG_ID_TRAILER) { pr_err("Invalid frame message\n"); Loading Loading @@ -3523,6 +3630,7 @@ STREAM_BUFF_END: break; case VIDIOC_MSM_CPP_IOMMU_ATTACH: { if (cpp_dev->iommu_state == CPP_IOMMU_STATE_DETACHED) { int32_t stall_disable; struct msm_camera_smmu_attach_type cpp_attach_info; if (ioctl_ptr->len != Loading @@ -3540,7 +3648,10 @@ STREAM_BUFF_END: } 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) { rc = cam_smmu_ops(cpp_dev->iommu_hdl, CAM_SMMU_ATTACH_SEC_CPP); Loading
drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h +7 −0 Original line number Diff line number Diff line Loading @@ -130,6 +130,12 @@ enum cpp_iommu_state { CPP_IOMMU_STATE_ATTACHED, }; enum cpp_iommu_fault_state { CPP_IOMMU_FAULT_NONE, CPP_IOMMU_FAULT_DETECTED, CPP_IOMMU_FAULT_RECOVERED, }; enum msm_queue { MSM_CAM_Q_CTRL, /* control command or control command status */ MSM_CAM_Q_VFE_EVT, /* adsp event */ Loading Loading @@ -287,6 +293,7 @@ struct cpp_device { struct msm_cpp_vbif_data *vbif_data; bool turbo_vote; 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); Loading