Răsfoiți Sursa

msm: camera: reqmgr: reset the slot on buf_done

Reset the slot with the valid request on receiving
the buf_done which is reported on next EPOCH.
In case of back to back irqs slot is marked as skip idx
it will apply the request and try to reset a slot based
on MAX_PD + 1 calculation which might have the request
for which we have got a bubble. To make sure this does not
happen, reset a slot only on the buf_done for valid request.

If STOP ioctl is called from UMD for ISP, it will flush all
the lists. But this is not notified to CRM which might have
a stale entry of the half applied request, so on STOP ioctl
clear all the slots.

In case of SAT mode if one of the link has generated bubble,
while the sync_link has the sync_request slot reset sync_link
will not let the link recover of the bubble. To make sure the
recovery sync_mode is set to 0 for two consecutive slots of
the link.

CRs-Fixed: 2551701
Change-Id: If4b6f8a4a831ffddcef2cae6292d066778c18b04
Signed-off-by: Tejas Prajapati <[email protected]>
Tejas Prajapati 5 ani în urmă
părinte
comite
96390653c5

+ 32 - 4
drivers/cam_isp/cam_isp_context.c

@@ -708,6 +708,7 @@ static int __cam_isp_ctx_handle_buf_done_for_request(
 		CAM_DBG(CAM_REQ,
 			"Move active request %lld to free list(cnt = %d) [all fences done], ctx %u",
 			buf_done_req_id, ctx_isp->active_req_cnt, ctx->ctx_id);
+		ctx_isp->req_info.last_bufdone_req_id = req->request_id;
 	}
 
 	__cam_isp_ctx_update_state_monitor_array(ctx_isp,
@@ -907,6 +908,7 @@ static int __cam_isp_ctx_notify_sof_in_activated_state(
 			notify.dev_hdl = ctx->dev_hdl;
 			notify.frame_id = ctx_isp->frame_id;
 			notify.trigger = CAM_TRIGGER_POINT_SOF;
+			notify.req_id = ctx_isp->req_info.last_bufdone_req_id;
 			notify.sof_timestamp_val = ctx_isp->sof_timestamp_val;
 
 			ctx->ctx_crm_intf->notify_trigger(&notify);
@@ -1077,7 +1079,7 @@ static int __cam_isp_ctx_epoch_in_applied(struct cam_isp_context *ctx_isp,
 		 * If no wait req in epoch, this is an error case.
 		 * The recovery is to go back to sof state
 		 */
-		CAM_ERR(CAM_ISP, "No wait request");
+		CAM_ERR(CAM_ISP, "Ctx:%d No wait request", ctx->ctx_id);
 		ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_SOF;
 
 		/* Send SOF event as empty frame*/
@@ -1093,7 +1095,8 @@ static int __cam_isp_ctx_epoch_in_applied(struct cam_isp_context *ctx_isp,
 	req_isp->bubble_detected = true;
 	req_isp->reapply = true;
 
-	CAM_DBG(CAM_ISP, "Report Bubble flag %d", req_isp->bubble_report);
+	CAM_INFO(CAM_ISP, "ctx:%d Report Bubble flag %d req id:%lld",
+		ctx->ctx_id, req_isp->bubble_report, req->request_id);
 	if (req_isp->bubble_report && ctx->ctx_crm_intf &&
 		ctx->ctx_crm_intf->notify_err) {
 		struct cam_req_mgr_error_notify notify;
@@ -1242,7 +1245,7 @@ static int __cam_isp_ctx_epoch_in_bubble_applied(
 		 * If no pending req in epoch, this is an error case.
 		 * Just go back to the bubble state.
 		 */
-		CAM_ERR(CAM_ISP, "No pending request.");
+		CAM_ERR(CAM_ISP, "ctx:%d No pending request.", ctx->ctx_id);
 		__cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id,
 			CAM_REQ_MGR_SOF_EVENT_SUCCESS);
 
@@ -1254,6 +1257,8 @@ static int __cam_isp_ctx_epoch_in_bubble_applied(
 		list);
 	req_isp = (struct cam_isp_ctx_req *)req->req_priv;
 	req_isp->bubble_detected = true;
+	CAM_INFO(CAM_ISP, "Ctx:%d Report Bubble flag %d req id:%lld",
+		ctx->ctx_id, req_isp->bubble_report, req->request_id);
 	req_isp->reapply = true;
 
 	if (req_isp->bubble_report && ctx->ctx_crm_intf &&
@@ -1592,6 +1597,7 @@ static int __cam_isp_ctx_fs2_sof_in_sof_state(
 			notify.dev_hdl = ctx->dev_hdl;
 			notify.frame_id = ctx_isp->frame_id;
 			notify.trigger = CAM_TRIGGER_POINT_SOF;
+			notify.req_id = ctx_isp->req_info.last_bufdone_req_id;
 			notify.sof_timestamp_val = ctx_isp->sof_timestamp_val;
 
 			ctx->ctx_crm_intf->notify_trigger(&notify);
@@ -1769,6 +1775,7 @@ static int __cam_isp_ctx_fs2_reg_upd_in_applied_state(
 			notify.dev_hdl = ctx->dev_hdl;
 			notify.frame_id = ctx_isp->frame_id;
 			notify.trigger = CAM_TRIGGER_POINT_SOF;
+			notify.req_id = ctx_isp->req_info.last_bufdone_req_id;
 			notify.sof_timestamp_val = ctx_isp->sof_timestamp_val;
 
 			ctx->ctx_crm_intf->notify_trigger(&notify);
@@ -2457,6 +2464,7 @@ static int __cam_isp_ctx_rdi_only_sof_in_top_state(
 		notify.dev_hdl = ctx->dev_hdl;
 		notify.frame_id = ctx_isp->frame_id;
 		notify.trigger = CAM_TRIGGER_POINT_SOF;
+		notify.req_id = ctx_isp->req_info.last_bufdone_req_id;
 		notify.sof_timestamp_val = ctx_isp->sof_timestamp_val;
 
 		ctx->ctx_crm_intf->notify_trigger(&notify);
@@ -2553,9 +2561,10 @@ static int __cam_isp_ctx_rdi_only_sof_in_bubble_applied(
 		list);
 	req_isp = (struct cam_isp_ctx_req *)req->req_priv;
 	req_isp->bubble_detected = true;
+	CAM_INFO(CAM_ISP, "Ctx:%d Report Bubble flag %d req id:%lld",
+		ctx->ctx_id, req_isp->bubble_report, req->request_id);
 	req_isp->reapply = true;
 
-	CAM_DBG(CAM_ISP, "Report Bubble flag %d", req_isp->bubble_report);
 	if (req_isp->bubble_report && ctx->ctx_crm_intf &&
 		ctx->ctx_crm_intf->notify_err) {
 		struct cam_req_mgr_error_notify notify;
@@ -2654,6 +2663,7 @@ static int __cam_isp_ctx_rdi_only_sof_in_bubble_state(
 		notify.dev_hdl = ctx->dev_hdl;
 		notify.frame_id = ctx_isp->frame_id;
 		notify.trigger = CAM_TRIGGER_POINT_SOF;
+		notify.req_id = ctx_isp->req_info.last_bufdone_req_id;
 		notify.sof_timestamp_val = ctx_isp->sof_timestamp_val;
 
 		ctx->ctx_crm_intf->notify_trigger(&notify);
@@ -2726,6 +2736,7 @@ static int __cam_isp_ctx_rdi_only_reg_upd_in_bubble_applied_state(
 		notify.dev_hdl = ctx->dev_hdl;
 		notify.frame_id = ctx_isp->frame_id;
 		notify.trigger = CAM_TRIGGER_POINT_SOF;
+		notify.req_id = ctx_isp->req_info.last_bufdone_req_id;
 		notify.sof_timestamp_val = ctx_isp->sof_timestamp_val;
 
 		ctx->ctx_crm_intf->notify_trigger(&notify);
@@ -2923,6 +2934,7 @@ static int __cam_isp_ctx_release_hw_in_top_state(struct cam_context *ctx,
 	ctx_isp->reported_req_id = 0;
 	ctx_isp->hw_acquired = false;
 	ctx_isp->init_received = false;
+	ctx_isp->req_info.last_bufdone_req_id = 0;
 
 	atomic64_set(&ctx_isp->state_monitor_head, -1);
 
@@ -2983,6 +2995,7 @@ static int __cam_isp_ctx_release_dev_in_top_state(struct cam_context *ctx,
 	ctx_isp->hw_acquired = false;
 	ctx_isp->init_received = false;
 	ctx_isp->rdi_only_context = false;
+	ctx_isp->req_info.last_bufdone_req_id = 0;
 
 	atomic64_set(&ctx_isp->state_monitor_head, -1);
 
@@ -3913,6 +3926,18 @@ static int __cam_isp_ctx_stop_dev_in_activated_unlock(
 		__cam_isp_ctx_substate_val_to_type(
 		ctx_isp->substate_activated));
 
+	if (ctx->ctx_crm_intf &&
+		ctx->ctx_crm_intf->notify_stop) {
+		struct cam_req_mgr_notify_stop notify;
+
+		notify.link_hdl = ctx->link_hdl;
+		CAM_DBG(CAM_ISP,
+			"Notify CRM about device stop ctx %u link 0x%x",
+			ctx->ctx_id, ctx->link_hdl);
+		ctx->ctx_crm_intf->notify_stop(&notify);
+	} else
+		CAM_ERR(CAM_ISP, "cb not present");
+
 	while (!list_empty(&ctx->pending_req_list)) {
 		req = list_first_entry(&ctx->pending_req_list,
 				struct cam_ctx_request, list);
@@ -3960,11 +3985,13 @@ static int __cam_isp_ctx_stop_dev_in_activated_unlock(
 			}
 		list_add_tail(&req->list, &ctx->free_req_list);
 	}
+
 	ctx_isp->frame_id = 0;
 	ctx_isp->active_req_cnt = 0;
 	ctx_isp->reported_req_id = 0;
 	ctx_isp->bubble_frame_cnt = 0;
 	ctx_isp->last_applied_req_id = 0;
+	ctx_isp->req_info.last_bufdone_req_id = 0;
 	atomic_set(&ctx_isp->process_bubble, 0);
 	atomic64_set(&ctx_isp->state_monitor_head, -1);
 
@@ -4424,6 +4451,7 @@ int cam_isp_context_init(struct cam_isp_context *ctx,
 	ctx->frame_id = 0;
 	ctx->active_req_cnt = 0;
 	ctx->reported_req_id = 0;
+	ctx->req_info.last_bufdone_req_id = 0;
 	ctx->bubble_frame_cnt = 0;
 	ctx->hw_ctx = NULL;
 	ctx->substate_activated = CAM_ISP_CTX_ACTIVATED_SOF;

+ 14 - 0
drivers/cam_isp/cam_isp_context.h

@@ -150,6 +150,18 @@ struct cam_isp_context_state_monitor {
 };
 
 /**
+ * struct cam_isp_context_req_id_info - ISP context request id
+ *                     information for bufdone.
+ *
+ *@last_bufdone_req_id:   Last bufdone request id
+ *
+ */
+
+struct cam_isp_context_req_id_info {
+	int64_t                          last_bufdone_req_id;
+};
+/**
+ *
  * struct cam_isp_context   -  ISP context object
  *
  * @base:                      Common context object pointer
@@ -171,6 +183,7 @@ struct cam_isp_context_state_monitor {
  *                             will invoke CRM cb at those event.
  * @last_applied_req_id:       Last applied request id
  * @state_monitor_head:        Write index to the state monitoring array
+ * @req_info                   Request id information about last buf done
  * @cam_isp_ctx_state_monitor: State monitoring array
  * @rdi_only_context:          Get context type information.
  *                             true, if context is rdi only context
@@ -204,6 +217,7 @@ struct cam_isp_context {
 	atomic64_t                            state_monitor_head;
 	struct cam_isp_context_state_monitor  cam_isp_ctx_state_monitor[
 		CAM_ISP_CTX_STATE_MONITOR_MAX_ENTRIES];
+	struct cam_isp_context_req_id_info    req_info;
 	bool                                  rdi_only_context;
 	bool                                  hw_acquired;
 	bool                                  init_received;

+ 114 - 1
drivers/cam_req_mgr/cam_req_mgr_core.c

@@ -480,7 +480,9 @@ static void __cam_req_mgr_reset_req_slot(struct cam_req_mgr_core_link *link,
 	CAM_DBG(CAM_CRM, "RESET: idx: %d: slot->status %d", idx, slot->status);
 
 	/* Check if CSL has already pushed new request*/
-	if (slot->status == CRM_SLOT_STATUS_REQ_ADDED)
+	if (slot->status == CRM_SLOT_STATUS_REQ_ADDED ||
+		in_q->last_applied_idx == idx ||
+		idx < 0)
 		return;
 
 	/* Reset input queue slot */
@@ -1500,6 +1502,10 @@ static int __cam_req_mgr_process_req(struct cam_req_mgr_core_link *link,
 					reset_step =
 						link->sync_link->max_delay;
 			}
+
+			if (slot->req_id > 0)
+				in_q->last_applied_idx = idx;
+
 			__cam_req_mgr_dec_idx(
 				&idx, reset_step + 1,
 				in_q->num_slots);
@@ -2403,6 +2409,12 @@ int cam_req_mgr_process_error(void *priv, void *data)
 			__cam_req_mgr_tbl_set_all_skip_cnt(&link->req.l_tbl);
 			in_q->rd_idx = idx;
 			in_q->slot[idx].status = CRM_SLOT_STATUS_REQ_ADDED;
+			if (link->sync_link) {
+				in_q->slot[idx].sync_mode = 0;
+				__cam_req_mgr_inc_idx(&idx, 1,
+					link->req.l_tbl->num_slots);
+				in_q->slot[idx].sync_mode = 0;
+			}
 			spin_lock_bh(&link->link_state_spin_lock);
 			link->state = CAM_CRM_LINK_STATE_ERR;
 			spin_unlock_bh(&link->link_state_spin_lock);
@@ -2415,6 +2427,31 @@ end:
 	return rc;
 }
 
+/**
+ * cam_req_mgr_process_stop()
+ *
+ * @brief: This runs in workque thread context. stop notification.
+ * @priv : link information.
+ * @data : contains information about frame_id, link etc.
+ *
+ * @return: 0 on success.
+ */
+int cam_req_mgr_process_stop(void *priv, void *data)
+{
+	int                                  rc = 0;
+	struct cam_req_mgr_core_link        *link = NULL;
+
+	if (!data || !priv) {
+		CAM_ERR(CAM_CRM, "input args NULL %pK %pK", data, priv);
+		rc = -EINVAL;
+		goto end;
+	}
+	link = (struct cam_req_mgr_core_link *)priv;
+	__cam_req_mgr_flush_req_slot(link);
+end:
+	return rc;
+}
+
 /**
  * cam_req_mgr_process_trigger()
  *
@@ -2428,6 +2465,7 @@ end:
 static int cam_req_mgr_process_trigger(void *priv, void *data)
 {
 	int                                  rc = 0;
+	int32_t                              idx = -1;
 	struct cam_req_mgr_trigger_notify   *trigger_data = NULL;
 	struct cam_req_mgr_core_link        *link = NULL;
 	struct cam_req_mgr_req_queue        *in_q = NULL;
@@ -2450,6 +2488,17 @@ static int cam_req_mgr_process_trigger(void *priv, void *data)
 	in_q = link->req.in_q;
 
 	mutex_lock(&link->req.lock);
+
+	if (trigger_data->trigger == CAM_TRIGGER_POINT_SOF) {
+		idx = __cam_req_mgr_find_slot_for_req(in_q,
+			trigger_data->req_id);
+		if (idx >= 0) {
+			if (idx == in_q->last_applied_idx)
+				in_q->last_applied_idx = -1;
+			__cam_req_mgr_reset_req_slot(link, idx);
+		}
+	}
+
 	/*
 	 * Check if current read index is in applied state, if yes make it free
 	 *    and increment read index to next slot.
@@ -2714,6 +2763,68 @@ end:
 	return rc;
 }
 
+/*
+ * cam_req_mgr_cb_notify_stop()
+ *
+ * @brief    : Stop received from device, resets the morked slots
+ * @err_info : contains information about error occurred like bubble/overflow
+ *
+ * @return   : 0 on success, negative in case of failure
+ *
+ */
+static int cam_req_mgr_cb_notify_stop(
+	struct cam_req_mgr_notify_stop *stop_info)
+{
+	int                              rc = 0;
+	struct crm_workq_task           *task = NULL;
+	struct cam_req_mgr_core_link    *link = NULL;
+	struct cam_req_mgr_notify_stop  *notify_stop;
+	struct crm_task_payload         *task_data;
+
+	if (!stop_info) {
+		CAM_ERR(CAM_CRM, "stop_info is NULL");
+		rc = -EINVAL;
+		goto end;
+	}
+
+	link = (struct cam_req_mgr_core_link *)
+		cam_get_device_priv(stop_info->link_hdl);
+	if (!link) {
+		CAM_DBG(CAM_CRM, "link ptr NULL %x", stop_info->link_hdl);
+		rc = -EINVAL;
+		goto end;
+	}
+
+	spin_lock_bh(&link->link_state_spin_lock);
+	if (link->state != CAM_CRM_LINK_STATE_READY) {
+		CAM_WARN(CAM_CRM, "invalid link state:%d", link->state);
+		spin_unlock_bh(&link->link_state_spin_lock);
+		rc = -EPERM;
+		goto end;
+	}
+	crm_timer_reset(link->watchdog);
+	spin_unlock_bh(&link->link_state_spin_lock);
+
+	task = cam_req_mgr_workq_get_task(link->workq);
+	if (!task) {
+		CAM_ERR(CAM_CRM, "no empty task");
+		rc = -EBUSY;
+		goto end;
+	}
+
+	task_data = (struct crm_task_payload *)task->payload;
+	task_data->type = CRM_WORKQ_TASK_NOTIFY_ERR;
+	notify_stop = (struct cam_req_mgr_notify_stop *)&task_data->u;
+	notify_stop->link_hdl = stop_info->link_hdl;
+	task->process_cb = &cam_req_mgr_process_stop;
+	rc = cam_req_mgr_workq_enqueue_task(task, link, CRM_TASK_PRIORITY_0);
+
+end:
+	return rc;
+}
+
+
+
 /**
  * cam_req_mgr_cb_notify_trigger()
  *
@@ -2774,6 +2885,7 @@ static int cam_req_mgr_cb_notify_trigger(
 	notify_trigger->link_hdl = trigger_data->link_hdl;
 	notify_trigger->dev_hdl = trigger_data->dev_hdl;
 	notify_trigger->trigger = trigger_data->trigger;
+	notify_trigger->req_id = trigger_data->req_id;
 	notify_trigger->sof_timestamp_val = trigger_data->sof_timestamp_val;
 	task->process_cb = &cam_req_mgr_process_trigger;
 	rc = cam_req_mgr_workq_enqueue_task(task, link, CRM_TASK_PRIORITY_0);
@@ -2787,6 +2899,7 @@ static struct cam_req_mgr_crm_cb cam_req_mgr_ops = {
 	.notify_err     = cam_req_mgr_cb_notify_err,
 	.add_req        = cam_req_mgr_cb_add_req,
 	.notify_timer   = cam_req_mgr_cb_notify_timer,
+	.notify_stop    = cam_req_mgr_cb_notify_stop,
 };
 
 /**

+ 2 - 0
drivers/cam_req_mgr/cam_req_mgr_core.h

@@ -253,12 +253,14 @@ struct cam_req_mgr_slot {
  * @slot        : request slot holding incoming request id and bubble info.
  * @rd_idx      : indicates slot index currently in process.
  * @wr_idx      : indicates slot index to hold new upcoming req.
+ * @last_applied_idx : indicates slot index last applied successfully.
  */
 struct cam_req_mgr_req_queue {
 	int32_t                     num_slots;
 	struct cam_req_mgr_slot     slot[MAX_REQ_SLOTS];
 	int32_t                     rd_idx;
 	int32_t                     wr_idx;
+	int32_t                     last_applied_idx;
 };
 
 /**

+ 17 - 0
drivers/cam_req_mgr/cam_req_mgr_interface.h

@@ -15,6 +15,7 @@ struct cam_req_mgr_trigger_notify;
 struct cam_req_mgr_error_notify;
 struct cam_req_mgr_add_request;
 struct cam_req_mgr_timer_notify;
+struct cam_req_mgr_notify_stop;
 struct cam_req_mgr_device_info;
 struct cam_req_mgr_core_dev_link_setup;
 struct cam_req_mgr_apply_request;
@@ -37,6 +38,7 @@ typedef int (*cam_req_mgr_notify_trigger)(
 typedef int (*cam_req_mgr_notify_err)(struct cam_req_mgr_error_notify *);
 typedef int (*cam_req_mgr_add_req)(struct cam_req_mgr_add_request *);
 typedef int (*cam_req_mgr_notify_timer)(struct cam_req_mgr_timer_notify *);
+typedef int (*cam_req_mgr_notify_stop)(struct cam_req_mgr_notify_stop *);
 
 /**
  * @brief: cam req mgr to camera device drivers
@@ -61,12 +63,14 @@ typedef int (*cam_req_mgr_process_evt)(struct cam_req_mgr_link_evt_data *);
  * @notify_trigger : payload for trigger indication event
  * @notify_err     : payload for different error occurred at device
  * @add_req        : payload to inform which device and what request is received
+ * @notify_stop    : payload to inform stop event
  */
 struct cam_req_mgr_crm_cb {
 	cam_req_mgr_notify_trigger  notify_trigger;
 	cam_req_mgr_notify_err      notify_err;
 	cam_req_mgr_add_req         add_req;
 	cam_req_mgr_notify_timer    notify_timer;
+	cam_req_mgr_notify_stop     notify_stop;
 };
 
 /**
@@ -142,6 +146,7 @@ enum cam_req_mgr_device_error {
 	CRM_KMD_ERR_PAGE_FAULT,
 	CRM_KMD_ERR_OVERFLOW,
 	CRM_KMD_ERR_TIMEOUT,
+	CRM_KMD_ERR_STOPPED,
 	CRM_KMD_ERR_MAX,
 };
 
@@ -200,6 +205,7 @@ enum cam_req_mgr_link_evt_type {
  * @trigger  : trigger point of this notification, CRM will send apply
  * only to the devices which subscribe to this point.
  * @sof_timestamp_val: Captured time stamp value at sof hw event
+ * @req_id   : req id which returned buf_done
  */
 struct cam_req_mgr_trigger_notify {
 	int32_t  link_hdl;
@@ -207,6 +213,7 @@ struct cam_req_mgr_trigger_notify {
 	int64_t  frame_id;
 	uint32_t trigger;
 	uint64_t sof_timestamp_val;
+	uint64_t req_id;
 };
 
 /**
@@ -253,6 +260,16 @@ struct cam_req_mgr_add_request {
 };
 
 
+/**
+ * struct cam_req_mgr_notify_stop
+ * @link_hdl             : link identifier
+ *
+ */
+struct cam_req_mgr_notify_stop {
+	int32_t  link_hdl;
+};
+
+
 /* CRM to KMD devices */
 /**
  * struct cam_req_mgr_device_info