Browse Source

msm: camera: isp: Add safety checks for SFE handling

Add checks to avoid KW issues for SFE scratch buffer handling.
Also add check in SFE acquire such that no two streams can
acquire same SFE HW. Update ctx pointer in sfe top struct as
opposed to per path since SFE top will handle for all paths.

CRs-Fixed: 2841729
Change-Id: I9ebbfb54c8be38ca7d2ac223f5fb432bf3307ddd
Signed-off-by: Karthik Anantha Ram <[email protected]>
Karthik Anantha Ram 4 năm trước cách đây
mục cha
commit
72f753f6a8

+ 55 - 12
drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c

@@ -467,7 +467,8 @@ static int cam_ife_mgr_get_hw_caps(void *hw_mgr_priv,
 	return rc;
 }
 
-static int cam_ife_hw_mgr_is_sfe_rdi_for_fetch(uint32_t res_id)
+static inline int cam_ife_hw_mgr_is_sfe_rdi_for_fetch(
+	uint32_t res_id)
 {
 	int rc = 0;
 
@@ -484,6 +485,13 @@ static int cam_ife_hw_mgr_is_sfe_rdi_for_fetch(uint32_t res_id)
 	return rc;
 }
 
+static inline int cam_ife_hw_mgr_is_shdr_fs_rdi_res(
+	uint32_t res_id, bool is_sfe_shdr, bool is_sfe_fs)
+{
+	return (cam_ife_hw_mgr_is_sfe_rdi_for_fetch(res_id) &&
+		(is_sfe_shdr || is_sfe_fs));
+}
+
 static int cam_ife_hw_mgr_is_sfe_rdi_res(uint32_t res_id)
 {
 	int rc = 0;
@@ -3390,9 +3398,11 @@ static int cam_ife_hw_mgr_acquire_res_ife_csid_rdi(
 		csid_acquire.tasklet = ife_ctx->common.tasklet_info;
 		csid_acquire.cb_priv = ife_ctx;
 		csid_acquire.cdm_ops = ife_ctx->cdm_ops;
-		if (cam_ife_hw_mgr_is_sfe_rdi_for_fetch(
-			out_port->res_type)) {
-			CAM_DBG(CAM_ISP, "setting inline shdr mode");
+		if (cam_ife_hw_mgr_is_shdr_fs_rdi_res(
+			out_port->res_type,
+			ife_ctx->flags.is_sfe_shdr, ife_ctx->flags.is_sfe_fs)) {
+			CAM_DBG(CAM_ISP, "setting inline shdr mode for res: 0x%x",
+				out_port->res_type);
 			csid_acquire.sfe_inline_shdr = true;
 		}
 
@@ -7150,7 +7160,7 @@ static inline int __cam_isp_sfe_send_cache_config(
 		sizeof(struct cam_isp_sfe_bus_sys_cache_config));
 	if (rc) {
 		CAM_ERR(CAM_ISP,
-			"Failed in sending cache config for:%d",
+			"Failed in sending cache config for: %u",
 			hw_res->res_id);
 	}
 
@@ -7163,6 +7173,7 @@ static int cam_isp_blob_sfe_exp_order_update(
 	struct cam_hw_prepare_update_args   *prepare)
 {
 	int rc = 0, i, j;
+	bool send_config;
 	uint32_t exp_order_max = 0;
 	uint32_t res_id_out, res_id_in;
 	struct cam_ife_hw_mgr_ctx               *ctx;
@@ -7193,8 +7204,14 @@ static int cam_isp_blob_sfe_exp_order_update(
 			order_cfg->res_type);
 		if (!rc) {
 			CAM_ERR(CAM_ISP,
-				"Not a SFE fetch RDI: 0x%x",
-				order_cfg->res_type);
+				"Not a SFE fetch RDI: 0x%x", order_cfg->res_type);
+			return -EINVAL;
+		}
+
+		if ((order_cfg->res_type - CAM_ISP_SFE_OUT_RES_RDI_0) >=
+			ctx->sfe_info.num_fetches) {
+			CAM_ERR(CAM_ISP, "resource 0x%x active fetches: %u mismatch",
+				order_cfg->res_type, ctx->sfe_info.num_fetches);
 			return -EINVAL;
 		}
 
@@ -7204,6 +7221,7 @@ static int cam_isp_blob_sfe_exp_order_update(
 		wm_rm_cache_cfg.use_cache =
 			(exp_order_max == i) ? true : false;
 		wm_rm_cache_cfg.scid = 0;
+		send_config = false;
 
 		/* Currently using cache for short only */
 		if (wm_rm_cache_cfg.use_cache) {
@@ -7238,10 +7256,18 @@ static int cam_isp_blob_sfe_exp_order_update(
 			rc = __cam_isp_sfe_send_cache_config(
 				CAM_ISP_HW_SFE_SYS_CACHE_WM_CONFIG,
 				&wm_rm_cache_cfg);
-			if (rc)
-				return rc;
+			send_config = true;
+			break;
+		}
+
+		if (rc || !send_config) {
+			CAM_ERR(CAM_ISP,
+				"Failed to send cache config for WR res: 0x%x base_idx: %u send_config: %d rc: %d",
+				order_cfg->res_type, base_idx, send_config, rc);
+			return -EINVAL;
 		}
 
+		send_config = false;
 		/* RDI WMs have been validated find corresponding RM */
 		if (order_cfg->res_type == CAM_ISP_SFE_OUT_RES_RDI_0)
 			res_id_in = CAM_ISP_HW_SFE_IN_RD0;
@@ -7266,11 +7292,18 @@ static int cam_isp_blob_sfe_exp_order_update(
 				rc = __cam_isp_sfe_send_cache_config(
 					CAM_ISP_HW_SFE_SYS_CACHE_RM_CONFIG,
 					&wm_rm_cache_cfg);
-				if (rc)
-					return rc;
+				send_config = true;
+				break;
 			}
 		}
 
+		if (rc || !send_config) {
+			CAM_ERR(CAM_ISP,
+				"Failed to send cache config for RD res: 0x%x base_idx: %u send_config: %d rc: %d",
+				res_id_in, base_idx, send_config, rc);
+			return -EINVAL;
+		}
+
 		if (!wm_rm_cache_cfg.rd_enabled && !wm_rm_cache_cfg.wr_enabled) {
 			wm_rm_cache_cfg.use_cache = false;
 			if (base_idx == CAM_SFE_CORE_0)
@@ -9183,6 +9216,14 @@ static int cam_sfe_packet_generic_blob_handler(void *user_data,
 	case CAM_ISP_GENERIC_BLOB_TYPE_SFE_SCRATCH_BUF_CFG: {
 		struct cam_isp_sfe_init_scratch_buf_config *scratch_config;
 
+		if (!(ife_mgr_ctx->flags.is_sfe_fs ||
+			ife_mgr_ctx->flags.is_sfe_shdr)) {
+			CAM_ERR(CAM_ISP,
+				"Not SFE sHDR/FS context: %u scratch buf blob not supported",
+				ife_mgr_ctx->ctx_index);
+			return -EINVAL;
+		}
+
 		if (blob_size <
 			sizeof(struct cam_isp_sfe_init_scratch_buf_config)) {
 			CAM_ERR(CAM_ISP, "Invalid blob size %u", blob_size);
@@ -11726,7 +11767,9 @@ static int cam_ife_hw_mgr_handle_hw_buf_done(
 		((event_info->hw_type == CAM_ISP_HW_TYPE_SFE) ? "SFE" : "IFE"),
 		event_info->hw_idx, event_info->res_id[i], event_info->last_consumed_addr[i]);
 
-		if (cam_ife_hw_mgr_is_sfe_rdi_for_fetch(event_info->res_id[i])) {
+		if (cam_ife_hw_mgr_is_shdr_fs_rdi_res(event_info->res_id[i],
+			ife_hw_mgr_ctx->flags.is_sfe_shdr,
+			ife_hw_mgr_ctx->flags.is_sfe_fs)) {
 			rc = cam_ife_hw_mgr_check_rdi_scratch_buf_done(
 				ife_hw_mgr_ctx->ctx_index,
 				ife_hw_mgr_ctx->sfe_info.scratch_config,

+ 41 - 26
drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_top/cam_sfe_top.c

@@ -51,14 +51,17 @@ struct cam_sfe_top_priv {
 	uint32_t                        sfe_debug_cfg;
 	uint32_t                        sensor_sel_diag_cfg;
 	int                             error_irq_handle;
+	uint16_t                        reserve_cnt;
+	uint16_t                        start_stop_cnt;
+	void                           *priv_per_stream;
 	spinlock_t                      spin_lock;
+	cam_hw_mgr_event_cb_func        event_cb;
 	struct cam_sfe_top_module_desc *module_desc;
 	struct cam_sfe_wr_client_desc  *wr_client_desc;
 };
 
 struct cam_sfe_path_data {
 	void __iomem                             *mem_base;
-	void                                     *priv;
 	struct cam_hw_intf                       *hw_intf;
 	struct cam_sfe_top_priv                  *top_priv;
 	struct cam_sfe_top_common_reg_offset     *common_reg;
@@ -68,11 +71,8 @@ struct cam_sfe_path_data {
 	struct cam_hw_soc_info                   *soc_info;
 	uint32_t                                  min_hblank_cnt;
 	int                                       sof_eof_handle;
-	cam_hw_mgr_event_cb_func                  event_cb;
 };
 
-static int start_stop_cnt;
-
 struct cam_sfe_top_debug_info {
 	uint32_t  shift;
 	char     *clc_name;
@@ -1318,6 +1318,15 @@ int cam_sfe_top_reserve(void *device_priv,
 	args = (struct cam_sfe_acquire_args *)reserve_args;
 	acquire_args = &args->sfe_in;
 
+	if (top_priv->reserve_cnt) {
+		if (top_priv->priv_per_stream != args->priv) {
+			CAM_ERR(CAM_SFE,
+				"Acquiring same SFE[%u] HW res: %u for different streams");
+			rc = -EINVAL;
+			return rc;
+		}
+	}
+
 	for (i = 0; i < CAM_SFE_TOP_IN_PORT_MAX; i++) {
 		CAM_DBG(CAM_SFE, "i: %d res_id: %d state: %d", i,
 			acquire_args->res_id, top_priv->in_rsrc[i].res_state);
@@ -1327,9 +1336,6 @@ int cam_sfe_top_reserve(void *device_priv,
 			CAM_ISP_RESOURCE_STATE_AVAILABLE)) {
 			path_data = (struct cam_sfe_path_data *)
 				top_priv->in_rsrc[i].res_priv;
-			path_data->event_cb = args->event_cb;
-			path_data->priv = args->priv;
-			path_data->top_priv = top_priv;
 			CAM_DBG(CAM_SFE,
 				"SFE [%u] for rsrc: %u acquired",
 				top_priv->in_rsrc[i].hw_intf->hw_idx,
@@ -1346,6 +1352,12 @@ int cam_sfe_top_reserve(void *device_priv,
 		}
 	}
 
+	if (!rc) {
+		top_priv->reserve_cnt++;
+		top_priv->priv_per_stream = args->priv;
+		top_priv->event_cb = args->event_cb;
+	}
+
 	return rc;
 }
 
@@ -1376,6 +1388,13 @@ int cam_sfe_top_release(void *device_priv,
 	in_res->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE;
 	in_res->cdm_ops = NULL;
 	in_res->tasklet_info = NULL;
+	if (top_priv->reserve_cnt)
+		top_priv->reserve_cnt--;
+
+	if (!top_priv->reserve_cnt) {
+		top_priv->priv_per_stream = NULL;
+		top_priv->event_cb = NULL;
+	}
 
 	return 0;
 }
@@ -1603,20 +1622,9 @@ static int cam_sfe_top_handle_err_irq_bottom_half(
 
 		evt_info.err_type = CAM_SFE_IRQ_STATUS_VIOLATION;
 		cam_sfe_top_print_debug_reg_info(top_priv);
-		for (i = 0; i < CAM_SFE_TOP_IN_PORT_MAX; i++) {
-			if (top_priv->in_rsrc[i].res_state ==
-				CAM_ISP_RESOURCE_STATE_STREAMING) {
-				struct cam_sfe_path_data *path_data;
-
-				path_data = (struct cam_sfe_path_data *)
-					top_priv->in_rsrc[i].res_priv;
-				if (path_data->event_cb) {
-					path_data->event_cb(path_data->priv,
-						CAM_ISP_HW_EVENT_ERROR, (void *)&evt_info);
-					break;
-				}
-			}
-		}
+		if (top_priv->event_cb)
+			top_priv->event_cb(top_priv->priv_per_stream,
+				CAM_ISP_HW_EVENT_ERROR, (void *)&evt_info);
 
 		ret = CAM_SFE_IRQ_STATUS_VIOLATION;
 	}
@@ -1824,7 +1832,7 @@ int cam_sfe_top_start(
 	}
 
 	sfe_res->res_state = CAM_ISP_RESOURCE_STATE_STREAMING;
-	start_stop_cnt++;
+	top_priv->start_stop_cnt++;
 	return 0;
 }
 
@@ -1877,10 +1885,10 @@ int cam_sfe_top_stop(
 		debug_cfg_disable = true;
 	}
 
-	if (start_stop_cnt)
-		start_stop_cnt--;
+	if (top_priv->start_stop_cnt)
+		top_priv->start_stop_cnt--;
 
-	if (!start_stop_cnt &&
+	if (!top_priv->start_stop_cnt &&
 		((top_priv->sfe_debug_cfg &
 		SFE_DEBUG_ENABLE_FRAME_COUNTER) ||
 		(top_priv->sfe_debug_cfg &
@@ -1902,8 +1910,9 @@ int cam_sfe_top_stop(
 	 * Reset clk rate & unsubscribe error irq
 	 * when all resources are streamed off
 	 */
-	if (!start_stop_cnt) {
+	if (!top_priv->start_stop_cnt) {
 		top_priv->applied_clk_rate = 0;
+
 		if (top_priv->error_irq_handle > 0) {
 			cam_irq_controller_unsubscribe_irq(
 				top_priv->common_data.sfe_irq_controller,
@@ -1956,6 +1965,10 @@ int cam_sfe_top_init(
 	}
 
 	top_priv->applied_clk_rate = 0;
+	top_priv->reserve_cnt = 0;
+	top_priv->start_stop_cnt = 0;
+	top_priv->priv_per_stream = NULL;
+	top_priv->event_cb = NULL;
 	top_priv->num_in_ports = sfe_top_hw_info->num_inputs;
 	memset(&top_priv->core_cfg, 0x0,
 		sizeof(struct cam_sfe_core_cfg));
@@ -1995,6 +2008,7 @@ int cam_sfe_top_init(
 				sfe_top_hw_info->common_reg_data;
 			path_data->modules_reg =
 				sfe_top_hw_info->modules_hw_info;
+			path_data->top_priv = top_priv;
 			path_data->hw_intf = hw_intf;
 			path_data->soc_info = soc_info;
 			scnprintf(top_priv->in_rsrc[i].res_name,
@@ -2028,6 +2042,7 @@ int cam_sfe_top_init(
 			path_data->modules_reg =
 				sfe_top_hw_info->modules_hw_info;
 			path_data->soc_info = soc_info;
+			path_data->top_priv = top_priv;
 			path_data->path_reg_data =
 				sfe_top_hw_info->rdi_reg_data[j++];
 		} else {