Loading drivers/cam_cdm/cam_cdm.h +2 −0 Original line number Diff line number Diff line Loading @@ -373,6 +373,7 @@ enum cam_cdm_hw_process_intf_cmd { CAM_CDM_HW_INTF_CMD_RESET_HW, CAM_CDM_HW_INTF_CMD_FLUSH_HW, CAM_CDM_HW_INTF_CMD_HANDLE_ERROR, CAM_CDM_HW_INTF_CMD_HANG_DETECT, CAM_CDM_HW_INTF_CMD_INVALID, }; Loading Loading @@ -469,6 +470,7 @@ struct cam_cdm_bl_fifo { uint8_t bl_tag; uint32_t bl_depth; uint8_t last_bl_tag_done; uint32_t work_record; }; /** Loading drivers/cam_cdm/cam_cdm_core_common.c +35 −0 Original line number Diff line number Diff line Loading @@ -785,6 +785,41 @@ int cam_cdm_process_cmd(void *hw_priv, mutex_unlock(&cdm_hw->hw_mutex); break; } case CAM_CDM_HW_INTF_CMD_HANG_DETECT: { uint32_t *handle = cmd_args; int idx; struct cam_cdm_client *client; if (sizeof(uint32_t) != arg_size) { CAM_ERR(CAM_CDM, "Invalid CDM cmd %d size=%x for handle=%x", cmd, arg_size, *handle); return -EINVAL; } idx = CAM_CDM_GET_CLIENT_IDX(*handle); mutex_lock(&cdm_hw->hw_mutex); client = core->clients[idx]; if (!client) { CAM_ERR(CAM_CDM, "Client not present for handle %d", *handle); mutex_unlock(&cdm_hw->hw_mutex); break; } if (*handle != client->handle) { CAM_ERR(CAM_CDM, "handle mismatch, client handle %d index %d received handle %d", client->handle, idx, *handle); mutex_unlock(&cdm_hw->hw_mutex); break; } rc = cam_hw_cdm_hang_detect(cdm_hw, *handle); mutex_unlock(&cdm_hw->hw_mutex); break; } default: CAM_ERR(CAM_CDM, "CDM HW intf command not valid =%d", cmd); break; Loading drivers/cam_cdm/cam_cdm_core_common.h +2 −1 Original line number Diff line number Diff line /* 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_CDM_CORE_COMMON_H_ Loading Loading @@ -50,6 +50,7 @@ int cam_hw_cdm_submit_bl(struct cam_hw_info *cdm_hw, int cam_hw_cdm_reset_hw(struct cam_hw_info *cdm_hw, uint32_t handle); int cam_hw_cdm_flush_hw(struct cam_hw_info *cdm_hw, uint32_t handle); int cam_hw_cdm_handle_error(struct cam_hw_info *cdm_hw, uint32_t handle); int cam_hw_cdm_hang_detect(struct cam_hw_info *cdm_hw, uint32_t handle); struct cam_cdm_bl_cb_request_entry *cam_cdm_find_request_by_bl_tag( uint32_t tag, struct list_head *bl_list); void cam_cdm_notify_clients(struct cam_hw_info *cdm_hw, Loading drivers/cam_cdm/cam_cdm_hw_core.c +53 −4 Original line number Diff line number Diff line Loading @@ -301,7 +301,11 @@ void cam_hw_cdm_dump_core_debug_registers( struct cam_cdm *core = (struct cam_cdm *)cdm_hw->core_info; cam_cdm_read_hw_reg(cdm_hw, core->offsets->cmn_reg->core_en, &dump_reg); CAM_ERR(CAM_CDM, "CDM HW core status=%x", dump_reg); CAM_INFO(CAM_CDM, "CDM HW core status=%x", dump_reg); cam_cdm_read_hw_reg(cdm_hw, core->offsets->cmn_reg->usr_data, &dump_reg); CAM_INFO(CAM_CDM, "CDM HW core userdata=0x%x", dump_reg); usleep_range(1000, 1010); Loading Loading @@ -1076,6 +1080,7 @@ static void cam_hw_cdm_reset_cleanup( } core->bl_fifo[i].bl_tag = 0; core->bl_fifo[i].last_bl_tag_done = -1; core->bl_fifo[i].work_record = 0; } } Loading @@ -1102,8 +1107,10 @@ static void cam_hw_cdm_work(struct work_struct *work) CAM_CDM_IRQ_STATUS_INLINE_IRQ_MASK) { struct cam_cdm_bl_cb_request_entry *node, *tnode; CAM_DBG(CAM_CDM, "inline IRQ data=0x%x", payload->irq_data); CAM_DBG(CAM_CDM, "inline IRQ data=0x%x last tag: 0x%x", payload->irq_data, core->bl_fifo[payload->fifo_idx] .last_bl_tag_done); if (payload->irq_data == 0xff) { CAM_INFO(CAM_CDM, "Debug genirq received"); Loading @@ -1114,6 +1121,10 @@ static void cam_hw_cdm_work(struct work_struct *work) mutex_lock(&core->bl_fifo[payload->fifo_idx] .fifo_lock); if (core->bl_fifo[payload->fifo_idx].work_record) core->bl_fifo[payload->fifo_idx].work_record--; if (core->bl_fifo[payload->fifo_idx] .last_bl_tag_done != payload->irq_data) { Loading Loading @@ -1145,6 +1156,10 @@ static void cam_hw_cdm_work(struct work_struct *work) kfree(node); node = NULL; } } else { CAM_DBG(CAM_CDM, "Skip GenIRQ, tag 0x%x fifo %d", payload->irq_data, payload->fifo_idx); } mutex_unlock(&core->bl_fifo[payload->fifo_idx] .fifo_lock); Loading Loading @@ -1297,6 +1312,10 @@ irqreturn_t cam_hw_cdm_irq(int irq_num, void *data) CAM_CDM_IRQ_STATUS_USR_DATA_MASK; } CAM_DBG(CAM_CDM, "Rcvd of fifo %d userdata 0x%x tag 0x%x irq_stat 0x%x", i, user_data, payload[i]->irq_data, irq_status[i]); payload[i]->fifo_idx = i; payload[i]->irq_status = irq_status[i]; payload[i]->hw = cdm_hw; Loading @@ -1308,6 +1327,7 @@ irqreturn_t cam_hw_cdm_irq(int irq_num, void *data) payload[i]->irq_status, cdm_hw->soc_info.index); cdm_core->bl_fifo[i].work_record++; work_status = queue_work( cdm_core->bl_fifo[i].work_queue, &payload[i]->work); Loading Loading @@ -1603,6 +1623,33 @@ int cam_hw_cdm_handle_error( return rc; } int cam_hw_cdm_hang_detect( struct cam_hw_info *cdm_hw, uint32_t handle) { struct cam_cdm *cdm_core = NULL; int i, rc = -1; cdm_core = (struct cam_cdm *)cdm_hw->core_info; for (i = 0; i < cdm_core->offsets->reg_data->num_bl_fifo; i++) mutex_lock(&cdm_core->bl_fifo[i].fifo_lock); for (i = 0; i < cdm_core->offsets->reg_data->num_bl_fifo; i++) if (cdm_core->bl_fifo[i].work_record) { CAM_WARN(CAM_CDM, "workqueue got delayed, work_record :%u", cdm_core->bl_fifo[i].work_record); rc = 0; break; } for (i = 0; i < cdm_core->offsets->reg_data->num_bl_fifo; i++) mutex_unlock(&cdm_core->bl_fifo[i].fifo_lock); return rc; } int cam_hw_cdm_get_cdm_config(struct cam_hw_info *cdm_hw) { struct cam_hw_soc_info *soc_info = NULL; Loading Loading @@ -1702,8 +1749,10 @@ int cam_hw_cdm_init(void *hw_priv, clear_bit(i, &cdm_core->cdm_status); reinit_completion(&cdm_core->bl_fifo[i].bl_complete); } for (i = 0; i < cdm_core->offsets->reg_data->num_bl_fifo; i++) for (i = 0; i < cdm_core->offsets->reg_data->num_bl_fifo; i++) { cdm_core->bl_fifo[i].last_bl_tag_done = -1; cdm_core->bl_fifo[i].work_record = 0; } rc = cam_hw_cdm_reset_hw(cdm_hw, reset_hw_hdl); Loading drivers/cam_cdm/cam_cdm_intf.c +28 −1 Original line number Diff line number Diff line // 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/delay.h> Loading Loading @@ -479,6 +479,33 @@ int cam_cdm_handle_error(uint32_t handle) } EXPORT_SYMBOL(cam_cdm_handle_error); int cam_cdm_detect_hang_error(uint32_t handle) { uint32_t hw_index; int rc = -EINVAL; struct cam_hw_intf *hw; if (get_cdm_mgr_refcount()) { CAM_ERR(CAM_CDM, "CDM intf mgr get refcount failed"); rc = -EPERM; return rc; } hw_index = CAM_CDM_GET_HW_IDX(handle); if (hw_index < CAM_CDM_INTF_MGR_MAX_SUPPORTED_CDM) { hw = cdm_mgr.nodes[hw_index].device; if (hw && hw->hw_ops.process_cmd) rc = hw->hw_ops.process_cmd(hw->hw_priv, CAM_CDM_HW_INTF_CMD_HANG_DETECT, &handle, sizeof(handle)); } put_cdm_mgr_refcount(); return rc; } EXPORT_SYMBOL(cam_cdm_detect_hang_error); int cam_cdm_intf_register_hw_cdm(struct cam_hw_intf *hw, struct cam_cdm_private_dt_data *data, enum cam_cdm_type type, uint32_t *index) Loading Loading
drivers/cam_cdm/cam_cdm.h +2 −0 Original line number Diff line number Diff line Loading @@ -373,6 +373,7 @@ enum cam_cdm_hw_process_intf_cmd { CAM_CDM_HW_INTF_CMD_RESET_HW, CAM_CDM_HW_INTF_CMD_FLUSH_HW, CAM_CDM_HW_INTF_CMD_HANDLE_ERROR, CAM_CDM_HW_INTF_CMD_HANG_DETECT, CAM_CDM_HW_INTF_CMD_INVALID, }; Loading Loading @@ -469,6 +470,7 @@ struct cam_cdm_bl_fifo { uint8_t bl_tag; uint32_t bl_depth; uint8_t last_bl_tag_done; uint32_t work_record; }; /** Loading
drivers/cam_cdm/cam_cdm_core_common.c +35 −0 Original line number Diff line number Diff line Loading @@ -785,6 +785,41 @@ int cam_cdm_process_cmd(void *hw_priv, mutex_unlock(&cdm_hw->hw_mutex); break; } case CAM_CDM_HW_INTF_CMD_HANG_DETECT: { uint32_t *handle = cmd_args; int idx; struct cam_cdm_client *client; if (sizeof(uint32_t) != arg_size) { CAM_ERR(CAM_CDM, "Invalid CDM cmd %d size=%x for handle=%x", cmd, arg_size, *handle); return -EINVAL; } idx = CAM_CDM_GET_CLIENT_IDX(*handle); mutex_lock(&cdm_hw->hw_mutex); client = core->clients[idx]; if (!client) { CAM_ERR(CAM_CDM, "Client not present for handle %d", *handle); mutex_unlock(&cdm_hw->hw_mutex); break; } if (*handle != client->handle) { CAM_ERR(CAM_CDM, "handle mismatch, client handle %d index %d received handle %d", client->handle, idx, *handle); mutex_unlock(&cdm_hw->hw_mutex); break; } rc = cam_hw_cdm_hang_detect(cdm_hw, *handle); mutex_unlock(&cdm_hw->hw_mutex); break; } default: CAM_ERR(CAM_CDM, "CDM HW intf command not valid =%d", cmd); break; Loading
drivers/cam_cdm/cam_cdm_core_common.h +2 −1 Original line number Diff line number Diff line /* 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_CDM_CORE_COMMON_H_ Loading Loading @@ -50,6 +50,7 @@ int cam_hw_cdm_submit_bl(struct cam_hw_info *cdm_hw, int cam_hw_cdm_reset_hw(struct cam_hw_info *cdm_hw, uint32_t handle); int cam_hw_cdm_flush_hw(struct cam_hw_info *cdm_hw, uint32_t handle); int cam_hw_cdm_handle_error(struct cam_hw_info *cdm_hw, uint32_t handle); int cam_hw_cdm_hang_detect(struct cam_hw_info *cdm_hw, uint32_t handle); struct cam_cdm_bl_cb_request_entry *cam_cdm_find_request_by_bl_tag( uint32_t tag, struct list_head *bl_list); void cam_cdm_notify_clients(struct cam_hw_info *cdm_hw, Loading
drivers/cam_cdm/cam_cdm_hw_core.c +53 −4 Original line number Diff line number Diff line Loading @@ -301,7 +301,11 @@ void cam_hw_cdm_dump_core_debug_registers( struct cam_cdm *core = (struct cam_cdm *)cdm_hw->core_info; cam_cdm_read_hw_reg(cdm_hw, core->offsets->cmn_reg->core_en, &dump_reg); CAM_ERR(CAM_CDM, "CDM HW core status=%x", dump_reg); CAM_INFO(CAM_CDM, "CDM HW core status=%x", dump_reg); cam_cdm_read_hw_reg(cdm_hw, core->offsets->cmn_reg->usr_data, &dump_reg); CAM_INFO(CAM_CDM, "CDM HW core userdata=0x%x", dump_reg); usleep_range(1000, 1010); Loading Loading @@ -1076,6 +1080,7 @@ static void cam_hw_cdm_reset_cleanup( } core->bl_fifo[i].bl_tag = 0; core->bl_fifo[i].last_bl_tag_done = -1; core->bl_fifo[i].work_record = 0; } } Loading @@ -1102,8 +1107,10 @@ static void cam_hw_cdm_work(struct work_struct *work) CAM_CDM_IRQ_STATUS_INLINE_IRQ_MASK) { struct cam_cdm_bl_cb_request_entry *node, *tnode; CAM_DBG(CAM_CDM, "inline IRQ data=0x%x", payload->irq_data); CAM_DBG(CAM_CDM, "inline IRQ data=0x%x last tag: 0x%x", payload->irq_data, core->bl_fifo[payload->fifo_idx] .last_bl_tag_done); if (payload->irq_data == 0xff) { CAM_INFO(CAM_CDM, "Debug genirq received"); Loading @@ -1114,6 +1121,10 @@ static void cam_hw_cdm_work(struct work_struct *work) mutex_lock(&core->bl_fifo[payload->fifo_idx] .fifo_lock); if (core->bl_fifo[payload->fifo_idx].work_record) core->bl_fifo[payload->fifo_idx].work_record--; if (core->bl_fifo[payload->fifo_idx] .last_bl_tag_done != payload->irq_data) { Loading Loading @@ -1145,6 +1156,10 @@ static void cam_hw_cdm_work(struct work_struct *work) kfree(node); node = NULL; } } else { CAM_DBG(CAM_CDM, "Skip GenIRQ, tag 0x%x fifo %d", payload->irq_data, payload->fifo_idx); } mutex_unlock(&core->bl_fifo[payload->fifo_idx] .fifo_lock); Loading Loading @@ -1297,6 +1312,10 @@ irqreturn_t cam_hw_cdm_irq(int irq_num, void *data) CAM_CDM_IRQ_STATUS_USR_DATA_MASK; } CAM_DBG(CAM_CDM, "Rcvd of fifo %d userdata 0x%x tag 0x%x irq_stat 0x%x", i, user_data, payload[i]->irq_data, irq_status[i]); payload[i]->fifo_idx = i; payload[i]->irq_status = irq_status[i]; payload[i]->hw = cdm_hw; Loading @@ -1308,6 +1327,7 @@ irqreturn_t cam_hw_cdm_irq(int irq_num, void *data) payload[i]->irq_status, cdm_hw->soc_info.index); cdm_core->bl_fifo[i].work_record++; work_status = queue_work( cdm_core->bl_fifo[i].work_queue, &payload[i]->work); Loading Loading @@ -1603,6 +1623,33 @@ int cam_hw_cdm_handle_error( return rc; } int cam_hw_cdm_hang_detect( struct cam_hw_info *cdm_hw, uint32_t handle) { struct cam_cdm *cdm_core = NULL; int i, rc = -1; cdm_core = (struct cam_cdm *)cdm_hw->core_info; for (i = 0; i < cdm_core->offsets->reg_data->num_bl_fifo; i++) mutex_lock(&cdm_core->bl_fifo[i].fifo_lock); for (i = 0; i < cdm_core->offsets->reg_data->num_bl_fifo; i++) if (cdm_core->bl_fifo[i].work_record) { CAM_WARN(CAM_CDM, "workqueue got delayed, work_record :%u", cdm_core->bl_fifo[i].work_record); rc = 0; break; } for (i = 0; i < cdm_core->offsets->reg_data->num_bl_fifo; i++) mutex_unlock(&cdm_core->bl_fifo[i].fifo_lock); return rc; } int cam_hw_cdm_get_cdm_config(struct cam_hw_info *cdm_hw) { struct cam_hw_soc_info *soc_info = NULL; Loading Loading @@ -1702,8 +1749,10 @@ int cam_hw_cdm_init(void *hw_priv, clear_bit(i, &cdm_core->cdm_status); reinit_completion(&cdm_core->bl_fifo[i].bl_complete); } for (i = 0; i < cdm_core->offsets->reg_data->num_bl_fifo; i++) for (i = 0; i < cdm_core->offsets->reg_data->num_bl_fifo; i++) { cdm_core->bl_fifo[i].last_bl_tag_done = -1; cdm_core->bl_fifo[i].work_record = 0; } rc = cam_hw_cdm_reset_hw(cdm_hw, reset_hw_hdl); Loading
drivers/cam_cdm/cam_cdm_intf.c +28 −1 Original line number Diff line number Diff line // 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/delay.h> Loading Loading @@ -479,6 +479,33 @@ int cam_cdm_handle_error(uint32_t handle) } EXPORT_SYMBOL(cam_cdm_handle_error); int cam_cdm_detect_hang_error(uint32_t handle) { uint32_t hw_index; int rc = -EINVAL; struct cam_hw_intf *hw; if (get_cdm_mgr_refcount()) { CAM_ERR(CAM_CDM, "CDM intf mgr get refcount failed"); rc = -EPERM; return rc; } hw_index = CAM_CDM_GET_HW_IDX(handle); if (hw_index < CAM_CDM_INTF_MGR_MAX_SUPPORTED_CDM) { hw = cdm_mgr.nodes[hw_index].device; if (hw && hw->hw_ops.process_cmd) rc = hw->hw_ops.process_cmd(hw->hw_priv, CAM_CDM_HW_INTF_CMD_HANG_DETECT, &handle, sizeof(handle)); } put_cdm_mgr_refcount(); return rc; } EXPORT_SYMBOL(cam_cdm_detect_hang_error); int cam_cdm_intf_register_hw_cdm(struct cam_hw_intf *hw, struct cam_cdm_private_dt_data *data, enum cam_cdm_type type, uint32_t *index) Loading