From 7f25abfda5dc2f637aa9d52566a58a87f3528bf9 Mon Sep 17 00:00:00 2001 From: Vikram Sharma Date: Mon, 11 Oct 2021 19:43:00 +0530 Subject: [PATCH 1/3] msm: camera: cdm: handle dead lock scenario This change handles a race condition in which cdm workqueue is scheduled on one of the cores and cdm flush is executing on another core. We come across a dead lock between fifo_lock and hw_mutex lock. CRs-Fixed: 3049531 Change-Id: Ie0b8982a7e55218fc5655f8e3d08a952fd852ed7 Signed-off-by: Vikram Sharma --- drivers/cam_cdm/cam_cdm_core_common.c | 5 ----- drivers/cam_cdm/cam_cdm_hw_core.c | 7 ++++++- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/cam_cdm/cam_cdm_core_common.c b/drivers/cam_cdm/cam_cdm_core_common.c index fd84b8d6866b..6ca94e740013 100644 --- a/drivers/cam_cdm/cam_cdm_core_common.c +++ b/drivers/cam_cdm/cam_cdm_core_common.c @@ -180,12 +180,10 @@ void cam_cdm_notify_clients(struct cam_hw_info *cdm_hw, (struct cam_cdm_bl_cb_request_entry *)data; client_idx = CAM_CDM_GET_CLIENT_IDX(node->client_hdl); - mutex_lock(&cdm_hw->hw_mutex); client = core->clients[client_idx]; if ((!client) || (client->handle != node->client_hdl)) { CAM_ERR(CAM_CDM, "Invalid client %pK hdl=%x", client, node->client_hdl); - mutex_unlock(&cdm_hw->hw_mutex); return; } cam_cdm_get_client_refcount(client); @@ -204,7 +202,6 @@ void cam_cdm_notify_clients(struct cam_hw_info *cdm_hw, } mutex_unlock(&client->lock); cam_cdm_put_client_refcount(client); - mutex_unlock(&cdm_hw->hw_mutex); return; } else if (status == CAM_CDM_CB_STATUS_HW_RESET_DONE || status == CAM_CDM_CB_STATUS_HW_FLUSH || @@ -242,7 +239,6 @@ void cam_cdm_notify_clients(struct cam_hw_info *cdm_hw, for (i = 0; i < CAM_PER_CDM_MAX_REGISTERED_CLIENTS; i++) { if (core->clients[i] != NULL) { - mutex_lock(&cdm_hw->hw_mutex); client = core->clients[i]; cam_cdm_get_client_refcount(client); mutex_lock(&client->lock); @@ -265,7 +261,6 @@ void cam_cdm_notify_clients(struct cam_hw_info *cdm_hw, } mutex_unlock(&client->lock); cam_cdm_put_client_refcount(client); - mutex_unlock(&cdm_hw->hw_mutex); } } } diff --git a/drivers/cam_cdm/cam_cdm_hw_core.c b/drivers/cam_cdm/cam_cdm_hw_core.c index 37f2a0a10967..583963a0d6e2 100644 --- a/drivers/cam_cdm/cam_cdm_hw_core.c +++ b/drivers/cam_cdm/cam_cdm_hw_core.c @@ -1238,6 +1238,7 @@ static void cam_hw_cdm_work(struct work_struct *work) return; } + mutex_lock(&cdm_hw->hw_mutex); mutex_lock(&core->bl_fifo[fifo_idx].fifo_lock); if (atomic_read(&core->bl_fifo[fifo_idx].work_record)) @@ -1251,6 +1252,7 @@ static void cam_hw_cdm_work(struct work_struct *work) core->arbitration); mutex_unlock(&core->bl_fifo[fifo_idx] .fifo_lock); + mutex_unlock(&cdm_hw->hw_mutex); return; } @@ -1289,6 +1291,7 @@ static void cam_hw_cdm_work(struct work_struct *work) } mutex_unlock(&core->bl_fifo[payload->fifo_idx] .fifo_lock); + mutex_unlock(&cdm_hw->hw_mutex); } if (payload->irq_status & @@ -1405,9 +1408,9 @@ handle_cdm_pf: cdm_hw->soc_info.index); for (i = 0; i < core->offsets->reg_data->num_bl_fifo; i++) mutex_unlock(&core->bl_fifo[i].fifo_lock); - mutex_unlock(&cdm_hw->hw_mutex); cam_cdm_notify_clients(cdm_hw, CAM_CDM_CB_STATUS_PAGEFAULT, (void *)pf_info->iova); + mutex_unlock(&cdm_hw->hw_mutex); clear_bit(CAM_CDM_ERROR_HW_STATUS, &core->cdm_status); } else { CAM_ERR(CAM_CDM, "Invalid token"); @@ -1806,9 +1809,11 @@ int cam_hw_cdm_handle_error_info( if (node != NULL) { if (node->request_type == CAM_HW_CDM_BL_CB_CLIENT) { + mutex_lock(&cdm_hw->hw_mutex); cam_cdm_notify_clients(cdm_hw, CAM_CDM_CB_STATUS_HW_ERROR, (void *)node); + mutex_unlock(&cdm_hw->hw_mutex); } else if (node->request_type == CAM_HW_CDM_BL_CB_INTERNAL) { CAM_ERR(CAM_CDM, "Invalid node=%pK %d", node, node->request_type); From 45dbb6c0cde224cb333d62a9111c264367d27df2 Mon Sep 17 00:00:00 2001 From: Trishansh Bhardwaj Date: Fri, 30 Jul 2021 05:22:31 +0000 Subject: [PATCH 2/3] msm: camera: ife: Add ife num outport bound checks Variable num_ports is provided by userspace, it it used to index res_list_isp_out. Big num_ports value can cause out of bound read. Bound check num_ports, to prevent OOB read. CRs-Fixed: 3056360 Change-Id: I86b6cf0419c68af1f510ce166e4964e177367eaf Signed-off-by: Trishansh Bhardwaj --- .../isp_hw_mgr/hw_utils/cam_isp_packet_parser.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c b/drivers/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c index 09b0cdb0e881..7357cfd9f77b 100644 --- a/drivers/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c +++ b/drivers/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c @@ -124,6 +124,12 @@ static int cam_isp_update_dual_config( cpu_addr += (cmd_desc->offset / 4); dual_config = (struct cam_isp_dual_config *)cpu_addr; + if (dual_config->num_ports > size_isp_out) { + CAM_ERR(CAM_ISP, "num_ports %d more than max_vfe_out_res %d", + dual_config->num_ports, size_isp_out); + return -EINVAL; + } + if ((dual_config->num_ports * sizeof(struct cam_isp_dual_stripe_config)) > (remain_len - offsetof(struct cam_isp_dual_config, stripes))) { @@ -132,14 +138,6 @@ static int cam_isp_update_dual_config( } for (i = 0; i < dual_config->num_ports; i++) { - if (i >= CAM_ISP_IFE_OUT_RES_BASE + size_isp_out) { - CAM_ERR(CAM_ISP, - "failed update for i:%d > size_isp_out:%d", - i, size_isp_out); - rc = -EINVAL; - goto end; - } - hw_mgr_res = &res_list_isp_out[i]; if (!hw_mgr_res) { CAM_ERR(CAM_ISP, From 8a251d8af120b79e98a7498e16ff4b77b7d38800 Mon Sep 17 00:00:00 2001 From: Vikram Sharma Date: Thu, 14 Oct 2021 16:56:51 +0530 Subject: [PATCH 3/3] msm: camera: isp: Fix PPI index based on the phy selection 1) There is one to one mapping for ppi index with phy index but phy select is not always equal to phy number,for some targets "phy_sel = phy_idx + 1", and for some targets it is "phy_sel = phy_idx", ppi_index should be updated accordingly. 2) Updated to configure ppi cfg register as. for cphy, disable dphy in config register. for dphy, do nothing (both cphy and dphy will be selected). then enable all lanes. CRs-Fixed: 3057665 Change-Id: I1d5d66034a5563b5adcb8163acf9a668d10d4a19 Signed-off-by: Vikram Sharma --- .../isp_hw/ppi_hw/cam_csid_ppi_core.c | 32 ++++--------------- .../isp_hw/ppi_hw/cam_csid_ppi_core.h | 2 +- .../isp_hw/tfe_csid_hw/cam_tfe_csid530.h | 3 +- .../isp_hw/tfe_csid_hw/cam_tfe_csid_core.c | 10 ++++-- .../isp_hw/tfe_csid_hw/cam_tfe_csid_core.h | 1 + 5 files changed, 19 insertions(+), 29 deletions(-) diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ppi_hw/cam_csid_ppi_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/ppi_hw/cam_csid_ppi_core.c index 42a84af64e24..0fa94fc5fde5 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ppi_hw/cam_csid_ppi_core.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ppi_hw/cam_csid_ppi_core.c @@ -163,9 +163,7 @@ static int cam_csid_ppi_init_hw(void *hw_priv, void *init_args, { int i, rc = 0; uint32_t num_lanes; - uint32_t lanes[CAM_CSID_PPI_HW_MAX] = {0, 0, 0, 0}; uint32_t cphy; - bool dl0, dl1; uint32_t ppi_cfg_val = 0; struct cam_csid_ppi_hw *ppi_hw; struct cam_hw_info *ppi_hw_info; @@ -180,7 +178,6 @@ static int cam_csid_ppi_init_hw(void *hw_priv, void *init_args, goto end; } - dl0 = dl1 = false; ppi_hw_info = (struct cam_hw_info *)hw_priv; ppi_hw = (struct cam_csid_ppi_hw *)ppi_hw_info->core_info; ppi_reg = ppi_hw->ppi_info->ppi_reg; @@ -195,30 +192,15 @@ static int cam_csid_ppi_init_hw(void *hw_priv, void *init_args, CAM_DBG(CAM_ISP, "lane_cfg 0x%x | num_lanes 0x%x | lane_type 0x%x", ppi_cfg.lane_cfg, num_lanes, cphy); - for (i = 0; i < num_lanes; i++) { - lanes[i] = ppi_cfg.lane_cfg & (0x3 << (4 * i)); - (lanes[i] < 2) ? (dl0 = true) : (dl1 = true); - CAM_DBG(CAM_ISP, "lanes[%d] %d", i, lanes[i]); + if (cphy) { + ppi_cfg_val |= PPI_CFG_CPHY_DLX_SEL(0); + ppi_cfg_val |= PPI_CFG_CPHY_DLX_SEL(1); + } else { + ppi_cfg_val = 0; } - if (num_lanes) { - if (cphy) { - for (i = 0; i < num_lanes; i++) { - ppi_cfg_val |= PPI_CFG_CPHY_DLX_SEL(lanes[i]); - ppi_cfg_val |= PPI_CFG_CPHY_DLX_EN(lanes[i]); - } - } else { - if (dl0) - ppi_cfg_val |= PPI_CFG_CPHY_DLX_EN(0); - if (dl1) - ppi_cfg_val |= PPI_CFG_CPHY_DLX_EN(1); - } - } else { - CAM_ERR(CAM_ISP, - "Number of lanes to enable is cannot be zero"); - rc = -1; - goto end; - } + for (i = 0; i < CAM_CSID_PPI_LANES_MAX; i++) + ppi_cfg_val |= PPI_CFG_CPHY_DLX_EN(i); CAM_DBG(CAM_ISP, "ppi_cfg_val 0x%x", ppi_cfg_val); soc_info = &ppi_hw->hw_info->soc_info; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ppi_hw/cam_csid_ppi_core.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/ppi_hw/cam_csid_ppi_core.h index dc0edf7e50ce..5f8873f529a7 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ppi_hw/cam_csid_ppi_core.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ppi_hw/cam_csid_ppi_core.h @@ -25,7 +25,7 @@ /* * Select the PHY (CPHY set '1' or DPHY set '0') */ -#define PPI_CFG_CPHY_DLX_SEL(X) ((X < 2) ? BIT(X) : 0) +#define PPI_CFG_CPHY_DLX_SEL(X) BIT(X) #define PPI_CFG_CPHY_DLX_EN(X) BIT(4+X) diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid530.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid530.h index b0e9dc862c4d..fa54bb4f1c06 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid530.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid530.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. */ #ifndef _CAM_TFE_CSID_530_H_ @@ -134,6 +134,7 @@ static struct cam_tfe_csid_csi2_rx_reg_offset .csid_csi2_rx_irq_set_addr = 0x2c, /*CSI2 rx control */ + .phy_sel_base = 1, .csid_csi2_rx_cfg0_addr = 0x100, .csid_csi2_rx_cfg1_addr = 0x104, .csid_csi2_rx_capture_ctrl_addr = 0x108, diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid_core.c index 7c86db7b8912..c0ef268f4198 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid_core.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid_core.c @@ -960,8 +960,14 @@ static int cam_tfe_csid_enable_csi2( cam_io_w_mb(val, soc_info->reg_map[0].mem_base + csid_reg->csi2_reg->csid_csi2_rx_irq_mask_addr); + /* + * There is one to one mapping for ppi index with phy index + * we do not always update phy sel equal to phy number,for some + * targets "phy_sel = phy_num + 1", and for some targets it is + * "phy_sel = phy_num", ppi_index should be updated accordingly + */ + ppi_index = csid_hw->csi2_rx_cfg.phy_sel - csid_reg->csi2_reg->phy_sel_base; - ppi_index = csid_hw->csi2_rx_cfg.phy_sel; if (csid_hw->ppi_hw_intf[ppi_index] && csid_hw->ppi_enable) { ppi_lane_cfg.lane_type = csid_hw->csi2_rx_cfg.lane_type; ppi_lane_cfg.lane_num = csid_hw->csi2_rx_cfg.lane_num; @@ -1005,7 +1011,7 @@ static int cam_tfe_csid_disable_csi2( cam_io_w_mb(0, soc_info->reg_map[0].mem_base + csid_reg->csi2_reg->csid_csi2_rx_cfg1_addr); - ppi_index = csid_hw->csi2_rx_cfg.phy_sel; + ppi_index = csid_hw->csi2_rx_cfg.phy_sel - csid_reg->csi2_reg->phy_sel_base; if (csid_hw->ppi_hw_intf[ppi_index] && csid_hw->ppi_enable) { /* De-Initialize the PPI bridge */ CAM_DBG(CAM_ISP, "ppi_index to de-init %d\n", ppi_index); diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid_core.h b/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid_core.h index b13d4b0473f8..c2e8d343196b 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid_core.h +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid_core.h @@ -185,6 +185,7 @@ struct cam_tfe_csid_csi2_rx_reg_offset { uint32_t csid_csi2_rx_total_crc_err_addr; /*configurations */ + uint32_t phy_sel_base; uint32_t csi2_rst_srb_all; uint32_t csi2_rst_done_shift_val; uint32_t csi2_irq_mask_all;