Эх сурвалжийг харах

msm: camera: cre: Fix null pointer dereference in CRE driver

Flush all cmd release all request from CRE request list, once release
these request should not be access by other threads. This commit
add proper mutex lock and conditions to prevent use of released request
from CRE request list. Also change SW reset to HW reset in case of
flush all.

CRs-Fixed: 3583508
Change-Id: I35b38bf5b1771a26bb5a37d3404f6e577abcb66b
Signed-off-by: Ayush Kumar <[email protected]>
Ayush Kumar 1 жил өмнө
parent
commit
cffdf3f9b5

+ 47 - 31
drivers/cam_cre/cam_cre_hw_mgr/cam_cre_hw_mgr.c

@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
  * Copyright (c) 2021, The Linux Foundation. All rights reserved.
- * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #include <linux/mutex.h>
@@ -760,38 +760,38 @@ static int cam_cre_mgr_process_cmd(void *priv, void *data)
 	task_data = (struct cre_cmd_work_data *)data;
 
 	mutex_lock(&hw_mgr->hw_mgr_mutex);
+	mutex_lock(&ctx_data->ctx_mutex);
 
 	if (ctx_data->ctx_state != CRE_CTX_STATE_ACQUIRED) {
-		mutex_unlock(&hw_mgr->hw_mgr_mutex);
 		CAM_ERR(CAM_CRE, "ctx id :%u is not in use",
 			ctx_data->ctx_id);
-		return -EINVAL;
+		rc = -EINVAL;
+		goto err;
 	}
 
 	if (task_data->req_idx >= CAM_CTX_REQ_MAX) {
-		mutex_unlock(&hw_mgr->hw_mgr_mutex);
 		CAM_ERR(CAM_CRE, "Invalid reqIdx = %llu",
-				task_data->req_idx);
-		return -EINVAL;
+			task_data->req_idx);
+		rc = -EINVAL;
+		goto err;
+	}
+
+	if (task_data->request_id <= ctx_data->last_flush_req) {
+		CAM_WARN(CAM_CRE,
+			"request %lld has been flushed, reject packet", task_data->request_id);
+		rc = -EINVAL;
+		goto err;
 	}
 
 	cre_req = ctx_data->req_list[task_data->req_idx];
 	if (cre_req->request_id > ctx_data->last_flush_req)
 		ctx_data->last_flush_req = 0;
 
-	if (cre_req->request_id <= ctx_data->last_flush_req) {
-		CAM_WARN(CAM_CRE,
-			"request %lld has been flushed, reject packet",
-			cre_req->request_id, ctx_data->last_flush_req);
-		mutex_unlock(&hw_mgr->hw_mgr_mutex);
-		return -EINVAL;
-	}
-
 	if (!cam_cre_is_pending_request(ctx_data)) {
 		CAM_WARN(CAM_CRE, "no pending req, req %lld last flush %lld",
 			cre_req->request_id, ctx_data->last_flush_req);
-		mutex_unlock(&hw_mgr->hw_mgr_mutex);
-		return -EINVAL;
+		rc = -EINVAL;
+		goto err;
 	}
 	hw_mgr = task_data->data;
 	num_batch = cre_req->num_batch;
@@ -815,7 +815,8 @@ static int cam_cre_mgr_process_cmd(void *priv, void *data)
 				cam_cre_device_timer_reset(cre_hw_mgr);
 				CAM_ERR(CAM_CRE,
 					"Timedout waiting for bufdone on last frame");
-				return -ETIMEDOUT;
+				rc = -EINVAL;
+				goto err;
 			} else {
 				reinit_completion(&ctx_data->cre_top->bufdone);
 				CAM_INFO(CAM_CRE,
@@ -827,6 +828,8 @@ static int cam_cre_mgr_process_cmd(void *priv, void *data)
 		cam_cre_mgr_update_reg_set(hw_mgr, cre_req, i);
 		cam_cre_ctx_wait_for_idle_irq(ctx_data);
 	}
+err:
+	mutex_unlock(&ctx_data->ctx_mutex);
 	mutex_unlock(&hw_mgr->hw_mgr_mutex);
 
 	return rc;
@@ -857,16 +860,16 @@ static int32_t cam_cre_mgr_process_msg(void *priv, void *data)
 	cfg_req = list_first_entry(&hw_mgr->hw_config_req_list,
 		struct cam_cre_hw_cfg_req, list);
 	if (!cfg_req) {
-		CAM_ERR(CAM_JPEG, "no request");
+		CAM_ERR(CAM_CRE, "Hw config req list empty");
 		rc = -EFAULT;
 		mutex_unlock(&hw_mgr->hw_mgr_mutex);
 		return rc;
 	}
 	list_del_init(&cfg_req->list);
-	mutex_unlock(&hw_mgr->hw_mgr_mutex);
 
 	if (cfg_req->ctx_id < 0) {
 		CAM_ERR(CAM_CRE, "No valid context to handle error");
+		mutex_unlock(&hw_mgr->hw_mgr_mutex);
 		return -EINVAL;
 	}
 
@@ -877,18 +880,25 @@ static int32_t cam_cre_mgr_process_msg(void *priv, void *data)
 	if (ctx->ctx_state != CRE_CTX_STATE_ACQUIRED) {
 		CAM_DBG(CAM_CRE, "ctx id: %d not in right state: %d",
 			cfg_req->ctx_id, ctx->ctx_state);
-		mutex_unlock(&ctx->ctx_mutex);
-		return -EINVAL;
+		rc = -EINVAL;
+		goto end;
 	}
 
 	active_req_idx = find_next_bit(ctx->bitmap, ctx->bits, ctx->last_done_req_idx);
 	CAM_DBG(CAM_CRE, "Ctx %d active_req_idx %d last_done_req_idx %d", ctx->ctx_id,
 		active_req_idx, ctx->last_done_req_idx);
 
+	if (active_req_idx >= CAM_CTX_REQ_MAX) {
+		CAM_WARN(CAM_CRE, "ctx %d not valid req idx active_req_idx %d", active_req_idx);
+		rc = -EINVAL;
+		goto end;
+	}
+
 	active_req = ctx->req_list[active_req_idx];
 	if (!active_req) {
 		CAM_ERR(CAM_CRE, "Active req cannot be null");
-		return -EINVAL;
+		rc = -EINVAL;
+		goto end;
 	}
 
 	if (irq_data.error) {
@@ -924,8 +934,10 @@ static int32_t cam_cre_mgr_process_msg(void *priv, void *data)
 			ctx->req_list[active_req_idx] = NULL;
 		}
 	}
+end:
 	list_add_tail(&cfg_req->list, &hw_mgr->free_req_list);
 	mutex_unlock(&ctx->ctx_mutex);
+	mutex_unlock(&hw_mgr->hw_mgr_mutex);
 	return rc;
 }
 
@@ -2344,6 +2356,7 @@ static int cam_cre_mgr_enqueue_config(struct cam_cre_hw_mgr *hw_mgr,
 	task_data = (struct cre_cmd_work_data *)task->payload;
 	task_data->data = (void *)hw_mgr;
 	task_data->req_idx = cre_req->req_idx;
+	task_data->request_id = cre_req->request_id;
 	task_data->type = CRE_WORKQ_TASK_CMD_TYPE;
 	task->process_cb = cam_cre_mgr_process_cmd;
 
@@ -2366,7 +2379,6 @@ static int cam_cre_mgr_config_hw(void *hw_priv, void *hw_config_args)
 	struct cam_cre_request *cre_req = NULL;
 	struct cam_cre_hw_cfg_req  *cfg_req = NULL;
 
-	CAM_DBG(CAM_CRE, "E");
 	if (!hw_mgr || !config_args) {
 		CAM_ERR(CAM_CRE, "Invalid arguments %pK %pK",
 			hw_mgr, config_args);
@@ -2382,18 +2394,16 @@ static int cam_cre_mgr_config_hw(void *hw_priv, void *hw_config_args)
 	mutex_lock(&hw_mgr->hw_mgr_mutex);
 	mutex_lock(&ctx_data->ctx_mutex);
 	if (ctx_data->ctx_state != CRE_CTX_STATE_ACQUIRED) {
-		mutex_unlock(&ctx_data->ctx_mutex);
-		mutex_unlock(&hw_mgr->hw_mgr_mutex);
 		CAM_ERR(CAM_CRE, "ctx id :%u is not in use",
 			ctx_data->ctx_id);
-		return -EINVAL;
+		rc= -EINVAL;
+		goto end;
 	}
 
 	if (list_empty(&hw_mgr->free_req_list)) {
-		mutex_unlock(&ctx_data->ctx_mutex);
-		mutex_unlock(&hw_mgr->hw_mgr_mutex);
-		CAM_ERR(CAM_JPEG, "list empty");
-		return -ENOMEM;
+		CAM_ERR(CAM_CRE, "No request in free list");
+		rc = -ENOMEM;
+		goto end;
 	}
 
 	cfg_req = list_first_entry(&hw_mgr->free_req_list,
@@ -2405,14 +2415,19 @@ static int cam_cre_mgr_config_hw(void *hw_priv, void *hw_config_args)
 	cam_cre_mgr_cre_clk_update(hw_mgr, ctx_data, cre_req->req_idx);
 	ctx_data->req_list[cre_req->req_idx]->submit_timestamp = ktime_get();
 
+	CAM_DBG(CAM_CRE, "ctx id :%u req id %lld", ctx_data->ctx_id, cre_req->request_id);
+
 	cfg_req->req_id = cre_req->request_id;
 	cfg_req->ctx_id = ctx_data->ctx_id;
 
-	if (cre_req->request_id <= ctx_data->last_flush_req)
+	if (cre_req->request_id <= ctx_data->last_flush_req) {
 		CAM_WARN(CAM_CRE,
 			"Anomaly submitting flushed req %llu [last_flush %llu] in ctx %u",
 			cre_req->request_id, ctx_data->last_flush_req,
 			ctx_data->ctx_id);
+		rc = -EINVAL;
+		goto end;
+	}
 
 	list_add_tail(&cfg_req->list, &hw_mgr->hw_config_req_list);
 
@@ -2429,6 +2444,7 @@ static int cam_cre_mgr_config_hw(void *hw_priv, void *hw_config_args)
 	return rc;
 config_err:
 	cam_cre_mgr_handle_config_err(config_args, ctx_data);
+end:
 	mutex_unlock(&ctx_data->ctx_mutex);
 	mutex_unlock(&hw_mgr->hw_mgr_mutex);
 	return rc;

+ 6 - 4
drivers/cam_cre/cam_cre_hw_mgr/cam_cre_hw_mgr.h

@@ -1,7 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * Copyright (c) 2021, The Linux Foundation. All rights reserved.
- * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #ifndef CAM_CRE_HW_MGR_H
@@ -146,14 +146,16 @@ struct cam_cre_clk_info {
 /**
  * struct cre_cmd_work_data
  *
- * @type:       Type of work data
- * @data:       Private data
- * @req_id:     Request Idx
+ * @type:        Type of work data
+ * @data:        Private data
+ * @req_idx:     Request Idx
+ * @request_id:  Request id
  */
 struct cre_cmd_work_data {
 	uint32_t type;
 	void *data;
 	int64_t req_idx;
+	uint64_t request_id;
 };
 
 /**

+ 3 - 2
drivers/cam_cre/cam_cre_hw_mgr/cre_hw/top/cre_top.c

@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
  * Copyright (c) 2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023-2024, Qualcomm Innovation Center, Inc. All rights reserved.
  */
 #include <linux/platform_device.h>
 #include <linux/delay.h>
@@ -46,8 +47,8 @@ static int cam_cre_top_reset(struct cam_cre_hw *cre_hw_info,
 	cam_io_w_mb(top_reg_val->irq_mask,
 		cre_hw_info->top_reg_offset->base + top_reg->irq_mask);
 
-	/* CRE SW RESET */
-	cam_io_w_mb(top_reg_val->sw_reset_cmd,
+	/* CRE HW RESET */
+	cam_io_w_mb(top_reg_val->hw_reset_cmd,
 		cre_hw_info->top_reg_offset->base + top_reg->reset_cmd);
 
 	rc = wait_for_completion_timeout(