Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c0cab065 authored by Vishalsingh Hajeri's avatar Vishalsingh Hajeri Committed by Karthik Anantha Ram
Browse files

msm: camera: isp: State monitoring in isp for error logging



Maintaining a buffer to keep track of current state and the
incoming request type as part of the activated state irq.
When an error occurs this buffer can be dumped for analysis.

Change-Id: Iba2d9bd696a5fa20438f2da2ebadaf695d34afe9
Signed-off-by: default avatarKarthik Anantha Ram <kartanan@codeaurora.org>
Signed-off-by: default avatarvhajeri <vhajeri@codeaurora.org>
parent 537f00f6
Loading
Loading
Loading
Loading
+170 −23
Original line number Diff line number Diff line
@@ -26,6 +26,97 @@

static const char isp_dev_name[] = "isp";

#define INC_STATE_MONITOR_HEAD(head) \
	(atomic64_add_return(1, head) % \
	CAM_ISP_CTX_STATE_MONITOR_MAX_ENTRIES)

static void __cam_isp_ctx_update_state_monitor_array(
	struct cam_isp_context *ctx_isp,
	enum cam_isp_state_change_trigger trigger_type,
	uint32_t req_id)
{
	int iterator = 0;

	iterator = INC_STATE_MONITOR_HEAD(&ctx_isp->state_monitor_head);
	ctx_isp->cam_isp_ctx_state_monitor[iterator].curr_state =
		ctx_isp->substate_activated;
	ctx_isp->cam_isp_ctx_state_monitor[iterator].trigger =
		trigger_type;
	ctx_isp->cam_isp_ctx_state_monitor[iterator].req_id =
		req_id;
	ctx_isp->cam_isp_ctx_state_monitor[iterator].evt_time_stamp =
		jiffies_to_msecs(jiffies);
}

static const char *__cam_isp_ctx_substate_val_to_type(
	uint32_t type)
{
	switch (type) {
	case CAM_ISP_CTX_ACTIVATED_SOF:
		return "SOF";
	case CAM_ISP_CTX_ACTIVATED_APPLIED:
		return "APPLIED";
	case CAM_ISP_CTX_ACTIVATED_EPOCH:
		return "EPOCH";
	case CAM_ISP_CTX_ACTIVATED_BUBBLE:
		return "BUBBLE";
	case CAM_ISP_CTX_ACTIVATED_BUBBLE_APPLIED:
		return "BUBBLE_APPLIED";
	case CAM_ISP_CTX_ACTIVATED_HALT:
		return "HALT";
	default:
		return "CAM_ISP_CTX_INVALID_STATE";
	}
}

static const char *__cam_isp_hw_evt_val_to_type(
	uint32_t evt_id)
{
	switch (evt_id) {
	case CAM_ISP_STATE_CHANGE_TRIGGER_ERROR:
		return "ERROR";
	case CAM_ISP_STATE_CHANGE_TRIGGER_SOF:
		return "SOF";
	case CAM_ISP_STATE_CHANGE_TRIGGER_REG_UPDATE:
		return "REG_UPDATE";
	case CAM_ISP_STATE_CHANGE_TRIGGER_EPOCH:
		return "EPOCH";
	case CAM_ISP_STATE_CHANGE_TRIGGER_EOF:
		return "EOF";
	case CAM_ISP_STATE_CHANGE_TRIGGER_DONE:
		return "DONE";
	default:
		return "CAM_ISP_EVENT_INVALID";
	}
}

static void __cam_isp_ctx_dump_state_monitor_array(
	struct cam_isp_context *ctx_isp)
{
	int i = 0;
	uint64_t state_head = 0;
	uint64_t index;

	state_head = atomic64_read(&ctx_isp->state_monitor_head);
	CAM_ERR_RATE_LIMIT(CAM_ISP,
		"Dumping state information for preceding requests");

	for (i = CAM_ISP_CTX_STATE_MONITOR_MAX_ENTRIES - 1; i >= 0;
		i--) {
		index = (((state_head - i) +
			CAM_ISP_CTX_STATE_MONITOR_MAX_ENTRIES) %
			CAM_ISP_CTX_STATE_MONITOR_MAX_ENTRIES);
		CAM_ERR_RATE_LIMIT(CAM_ISP,
		"time[0x%llx] req_id[%u] state[%s] evt_type[%s]",
		ctx_isp->cam_isp_ctx_state_monitor[index].evt_time_stamp,
		ctx_isp->cam_isp_ctx_state_monitor[index].req_id,
		__cam_isp_ctx_substate_val_to_type(
		ctx_isp->cam_isp_ctx_state_monitor[index].curr_state),
		__cam_isp_hw_evt_val_to_type(
		ctx_isp->cam_isp_ctx_state_monitor[index].trigger));
	}
}

static int __cam_isp_ctx_enqueue_request_in_order(
	struct cam_context *ctx, struct cam_ctx_request *req)
{
@@ -134,46 +225,46 @@ static int __cam_isp_ctx_enqueue_init_request(
	return rc;
}

static const char *__cam_isp_resource_handle_id_to_type
	(uint32_t resource_handle)
static const char *__cam_isp_resource_handle_id_to_type(
	uint32_t resource_handle)
{
	switch (resource_handle) {
	case CAM_ISP_IFE_OUT_RES_FULL:
		return "CAM_ISP_IFE_OUT_RES_FULL";
		return "FULL";
	case CAM_ISP_IFE_OUT_RES_DS4:
		return "CAM_ISP_IFE_OUT_RES_DS4";
		return "DS4";
	case CAM_ISP_IFE_OUT_RES_DS16:
		return "CAM_ISP_IFE_OUT_RES_DS16";
		return "DS16";
	case CAM_ISP_IFE_OUT_RES_RAW_DUMP:
		return "CAM_ISP_IFE_OUT_RES_RAW_DUMP";
		return "RAW_DUMP";
	case CAM_ISP_IFE_OUT_RES_FD:
		return "CAM_ISP_IFE_OUT_RES_FD";
		return "FD";
	case CAM_ISP_IFE_OUT_RES_PDAF:
		return "CAM_ISP_IFE_OUT_RES_PDAF";
		return "PDAF";
	case CAM_ISP_IFE_OUT_RES_RDI_0:
		return "CAM_ISP_IFE_OUT_RES_RDI_0";
		return "RDI_0";
	case CAM_ISP_IFE_OUT_RES_RDI_1:
		return "CAM_ISP_IFE_OUT_RES_RDI_1";
		return "RDI_1";
	case CAM_ISP_IFE_OUT_RES_RDI_2:
		return "CAM_ISP_IFE_OUT_RES_RDI_2";
		return "RDI_2";
	case CAM_ISP_IFE_OUT_RES_RDI_3:
		return "CAM_ISP_IFE_OUT_RES_RDI_3";
		return "RDI_3";
	case CAM_ISP_IFE_OUT_RES_STATS_HDR_BE:
		return "CAM_ISP_IFE_OUT_RES_STATS_HDR_BE";
		return "STATS_HDR_BE";
	case CAM_ISP_IFE_OUT_RES_STATS_HDR_BHIST:
		return "CAM_ISP_IFE_OUT_RES_STATS_HDR_BHIST";
		return "STATS_HDR_BHIST";
	case CAM_ISP_IFE_OUT_RES_STATS_TL_BG:
		return "CAM_ISP_IFE_OUT_RES_STATS_TL_BG";
		return "STATS_TL_BG";
	case CAM_ISP_IFE_OUT_RES_STATS_BF:
		return "CAM_ISP_IFE_OUT_RES_STATS_BF";
		return "STATS_BF";
	case CAM_ISP_IFE_OUT_RES_STATS_AWB_BG:
		return "CAM_ISP_IFE_OUT_RES_STATS_AWB_BG";
		return "STATS_AWB_BG";
	case CAM_ISP_IFE_OUT_RES_STATS_BHIST:
		return "CAM_ISP_IFE_OUT_RES_STATS_BHIST";
		return "STATS_BHIST";
	case CAM_ISP_IFE_OUT_RES_STATS_RS:
		return "CAM_ISP_IFE_OUT_RES_STATS_RS";
		return "STATS_RS";
	case CAM_ISP_IFE_OUT_RES_STATS_CS:
		return "CAM_ISP_IFE_OUT_RES_STATS_CS";
		return "STATS_CS";
	default:
		return "CAM_ISP_Invalid_Resource_Type";
	}
@@ -350,6 +441,9 @@ static int __cam_isp_ctx_handle_buf_done_in_activated_state(
	}

end:
	__cam_isp_ctx_update_state_monitor_array(ctx_isp,
		CAM_ISP_STATE_CHANGE_TRIGGER_DONE,
		ctx_isp->base->req_list->request_id);
	return rc;
}

@@ -510,6 +604,11 @@ static int __cam_isp_ctx_sof_in_activated_state(
{
	int rc = 0;
	struct cam_isp_hw_sof_event_data      *sof_event_data = evt_data;
	struct cam_ctx_request *req;
	struct cam_context *ctx = ctx_isp->base;

	req = list_last_entry(&ctx->pending_req_list,
		struct cam_ctx_request, list);

	if (!evt_data) {
		CAM_ERR(CAM_ISP, "in valid sof event data");
@@ -518,6 +617,8 @@ static int __cam_isp_ctx_sof_in_activated_state(

	ctx_isp->frame_id++;
	ctx_isp->sof_timestamp_val = sof_event_data->timestamp;
	__cam_isp_ctx_update_state_monitor_array(ctx_isp,
		CAM_ISP_STATE_CHANGE_TRIGGER_SOF, req->request_id);
	CAM_DBG(CAM_ISP, "frame id: %lld time stamp:0x%llx",
		ctx_isp->frame_id, ctx_isp->sof_timestamp_val);

@@ -528,11 +629,11 @@ static int __cam_isp_ctx_reg_upd_in_sof(struct cam_isp_context *ctx_isp,
	void *evt_data)
{
	int rc = 0;
	struct cam_ctx_request *req;
	struct cam_ctx_request *req = NULL;
	struct cam_isp_ctx_req *req_isp;
	struct cam_context *ctx = ctx_isp->base;

	if (ctx->state != CAM_CTX_ACTIVATED) {
	if (ctx->state != CAM_CTX_ACTIVATED && ctx_isp->frame_id > 1) {
		CAM_DBG(CAM_ISP, "invalid RUP");
		goto end;
	}
@@ -560,6 +661,11 @@ static int __cam_isp_ctx_reg_upd_in_sof(struct cam_isp_context *ctx_isp,
				CAM_ISP_CTX_ACTIVATED_EPOCH;
		}
	}
	if (req != NULL) {
		__cam_isp_ctx_update_state_monitor_array(ctx_isp,
			CAM_ISP_STATE_CHANGE_TRIGGER_REG_UPDATE,
			req->request_id);
	}
end:
	return rc;
}
@@ -627,6 +733,15 @@ static int __cam_isp_ctx_epoch_in_applied(struct cam_isp_context *ctx_isp,
	CAM_DBG(CAM_ISP, "next substate %d",
		ctx_isp->substate_activated);
end:
	if (request_id == 0) {
		req = list_last_entry(&ctx->active_req_list,
			struct cam_ctx_request, list);
		__cam_isp_ctx_update_state_monitor_array(ctx_isp,
			CAM_ISP_STATE_CHANGE_TRIGGER_EPOCH, req->request_id);
	} else {
		__cam_isp_ctx_update_state_monitor_array(ctx_isp,
			CAM_ISP_STATE_CHANGE_TRIGGER_EPOCH, request_id);
	}
	return 0;
}

@@ -649,6 +764,7 @@ static int __cam_isp_ctx_sof_in_epoch(struct cam_isp_context *ctx_isp,
	int rc = 0;
	struct cam_context                    *ctx = ctx_isp->base;
	struct cam_isp_hw_sof_event_data      *sof_event_data = evt_data;
	struct cam_ctx_request *req;

	if (!evt_data) {
		CAM_ERR(CAM_ISP, "in valid sof event data");
@@ -663,6 +779,10 @@ static int __cam_isp_ctx_sof_in_epoch(struct cam_isp_context *ctx_isp,
	else
		CAM_DBG(CAM_ISP, "Still need to wait for the buf done");

	req = list_last_entry(&ctx->active_req_list,
		struct cam_ctx_request, list);
	__cam_isp_ctx_update_state_monitor_array(ctx_isp,
		CAM_ISP_STATE_CHANGE_TRIGGER_SOF, ctx->req_list->request_id);
	CAM_DBG(CAM_ISP, "next substate %d",
		ctx_isp->substate_activated);

@@ -761,6 +881,10 @@ static int __cam_isp_ctx_epoch_in_bubble_applied(
	ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_BUBBLE;
	CAM_DBG(CAM_ISP, "next substate %d", ctx_isp->substate_activated);
end:
	req = list_last_entry(&ctx->active_req_list, struct cam_ctx_request,
		list);
	__cam_isp_ctx_update_state_monitor_array(ctx_isp,
		CAM_ISP_STATE_CHANGE_TRIGGER_EPOCH, req->request_id);
	return 0;
}

@@ -772,6 +896,9 @@ static int __cam_isp_ctx_buf_done_in_bubble_applied(
		(struct cam_isp_hw_done_event_data *) evt_data;

	rc = __cam_isp_ctx_handle_buf_done_in_activated_state(ctx_isp, done, 1);
	__cam_isp_ctx_update_state_monitor_array(ctx_isp,
		CAM_ISP_STATE_CHANGE_TRIGGER_DONE,
		ctx_isp->base->req_list->request_id);
	return rc;
}

@@ -894,6 +1021,14 @@ static int __cam_isp_ctx_handle_error(struct cam_isp_context *ctx_isp,
		rc = -EFAULT;
	}


	list_del_init(&req->list);
	list_add(&req->list, &ctx->pending_req_list);
	/* might need to check if active list is empty */
	if (req != NULL) {
		__cam_isp_ctx_update_state_monitor_array(ctx_isp,
			CAM_ISP_STATE_CHANGE_TRIGGER_ERROR, req->request_id);
	}
	CAM_DBG(CAM_ISP, "Exit");
	return rc;
}
@@ -1014,7 +1149,7 @@ static int __cam_isp_ctx_apply_req_in_activated_state(
	struct cam_ctx_request          *active_req;
	struct cam_isp_ctx_req          *req_isp;
	struct cam_isp_ctx_req          *active_req_isp;
	struct cam_isp_context          *ctx_isp;
	struct cam_isp_context          *ctx_isp = NULL;
	struct cam_hw_config_args        cfg;

	if (list_empty(&ctx->pending_req_list)) {
@@ -1088,6 +1223,11 @@ static int __cam_isp_ctx_apply_req_in_activated_state(
		spin_unlock_bh(&ctx->lock);
	}
end:
	if (ctx_isp != NULL) {
		__cam_isp_ctx_update_state_monitor_array(ctx_isp,
			CAM_ISP_STATE_CHANGE_TRIGGER_SOF,
			ctx->req_list->request_id);
	}
	return rc;
}

@@ -2439,6 +2579,7 @@ static int __cam_isp_ctx_handle_irq_in_activated(void *context,
	} else {
		CAM_DBG(CAM_ISP, "No handle function for substate %d",
			ctx_isp->substate_activated);
		__cam_isp_ctx_dump_state_monitor_array(ctx_isp);
	}
	CAM_DBG(CAM_ISP, "Exit: State %d Substate %d",
		 ctx->state, ctx_isp->substate_activated);
@@ -2552,6 +2693,12 @@ int cam_isp_context_init(struct cam_isp_context *ctx,
	ctx_base->state_machine = cam_isp_ctx_top_state_machine;
	ctx_base->ctx_priv = ctx;

	/* initializing current state for error logging */
	for (i = 0; i < CAM_ISP_CTX_STATE_MONITOR_MAX_ENTRIES; i++) {
		ctx->cam_isp_ctx_state_monitor[i].curr_state =
		CAM_ISP_CTX_ACTIVATED_MAX;
	}
	atomic64_set(&ctx->state_monitor_head, -1);
err:
	return rc;
}
+60 −18
Original line number Diff line number Diff line
@@ -28,11 +28,16 @@
#define CAM_ISP_CTX_RES_MAX                     20

/*
 * Maxiimum configuration entry size  - This is based on the
 * Maximum configuration entry size  - This is based on the
 * worst case DUAL IFE use case plus some margin.
 */
#define CAM_ISP_CTX_CFG_MAX                     22

/*
 * Maximum entries in state monitoring array for error logging
 */
#define CAM_ISP_CTX_STATE_MONITOR_MAX_ENTRIES   20

/* forward declaration */
struct cam_isp_context;

@@ -56,6 +61,19 @@ enum cam_isp_ctx_activated_substate {
	CAM_ISP_CTX_ACTIVATED_MAX,
};

/**
 * enum cam_isp_state_change_trigger - Different types of ISP events
 *
 */
enum cam_isp_state_change_trigger {
	CAM_ISP_STATE_CHANGE_TRIGGER_ERROR,
	CAM_ISP_STATE_CHANGE_TRIGGER_SOF,
	CAM_ISP_STATE_CHANGE_TRIGGER_REG_UPDATE,
	CAM_ISP_STATE_CHANGE_TRIGGER_EPOCH,
	CAM_ISP_STATE_CHANGE_TRIGGER_EOF,
	CAM_ISP_STATE_CHANGE_TRIGGER_DONE,
	CAM_ISP_STATE_CHANGE_TRIGGER_MAX
};

/**
 * struct cam_isp_ctx_irq_ops - Function table for handling IRQ callbacks
@@ -100,6 +118,25 @@ struct cam_isp_ctx_req {
	struct cam_isp_prepare_hw_update_data hw_update_data;
};

/**
 * struct cam_isp_context_state_monitor - ISP context state
 *                                        monitoring for
 *                                        debug purposes
 *
 *@curr_state:          Current sub state that received req
 *@req_type:            Event type of incoming req
 *@req_id:              Request id
 *@evt_time_stamp       Current time stamp
 *
 */
struct cam_isp_context_state_monitor {
	enum cam_isp_ctx_activated_substate  curr_state;
	enum cam_isp_state_change_trigger    trigger;
	uint32_t                             req_id;
	int64_t                              frame_id;
	uint64_t                             evt_time_stamp;
};

/**
 * struct cam_isp_context   -  ISP context object
 *
@@ -114,10 +151,12 @@ struct cam_isp_ctx_req {
 * @sof_timestamp_val:         Captured time stamp value at sof hw event
 * @active_req_cnt:            Counter for the active request
 * @reported_req_id:           Last reported request id
 * @subscribe_event:       The irq event mask that CRM subscribes to, IFE will
 *                         invoke CRM cb at those event.
 * @subscribe_event:           The irq event mask that CRM subscribes to, IFE
 *                             will invoke CRM cb at those event.
 * @last_applied_req_id:       Last applied request id
 * @frame_skip_count:          Number of frame to skip before change state
 * @state_monitor_head:        Write index to the state monitoring array
 * @cam_isp_ctx_state_monitor: State monitoring array
 *
 */
struct cam_isp_context {
@@ -138,6 +177,9 @@ struct cam_isp_context {
	uint32_t                         subscribe_event;
	int64_t                          last_applied_req_id;
	uint32_t                         frame_skip_count;
	atomic64_t                       state_monitor_head;
	struct cam_isp_context_state_monitor cam_isp_ctx_state_monitor[
		CAM_ISP_CTX_STATE_MONITOR_MAX_ENTRIES];
};

/**