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

Commit b524a853 authored by Jing Zhou's avatar Jing Zhou
Browse files

msm: camera: isp: Add flush support in camera isp



Add support for flushing all request ids or cancel particular
request id in isp context pending list from camera request
manager interface.

Change-Id: I4a6d4bc6645f501af08bb0acbcce8b47d90ae10a
Signed-off-by: default avatarRavikishore Pampana <rpampana@codeaurora.org>
Signed-off-by: default avatarJing Zhou <jzhou70@codeaurora.org>
parent 2f604f08
Loading
Loading
Loading
Loading
+27 −4
Original line number Diff line number Diff line
@@ -34,7 +34,7 @@ static int cam_context_handle_hw_event(void *context, uint32_t evt_id,
	return rc;
}

int cam_context_handle_get_dev_info(struct cam_context *ctx,
int cam_context_handle_crm_get_dev_info(struct cam_context *ctx,
	struct cam_req_mgr_device_info *info)
{
	int rc;
@@ -63,7 +63,7 @@ int cam_context_handle_get_dev_info(struct cam_context *ctx,
	return rc;
}

int cam_context_handle_link(struct cam_context *ctx,
int cam_context_handle_crm_link(struct cam_context *ctx,
	struct cam_req_mgr_core_dev_link_setup *link)
{
	int rc;
@@ -91,7 +91,7 @@ int cam_context_handle_link(struct cam_context *ctx,
	return rc;
}

int cam_context_handle_unlink(struct cam_context *ctx,
int cam_context_handle_crm_unlink(struct cam_context *ctx,
	struct cam_req_mgr_core_dev_link_setup *unlink)
{
	int rc;
@@ -120,7 +120,7 @@ int cam_context_handle_unlink(struct cam_context *ctx,
	return rc;
}

int cam_context_handle_apply_req(struct cam_context *ctx,
int cam_context_handle_crm_apply_req(struct cam_context *ctx,
	struct cam_req_mgr_apply_request *apply)
{
	int rc;
@@ -149,6 +149,29 @@ int cam_context_handle_apply_req(struct cam_context *ctx,
	return rc;
}

int cam_context_handle_crm_flush_req(struct cam_context *ctx,
	struct cam_req_mgr_flush_request *flush)
{
	int rc;

	if (!ctx->state_machine) {
		pr_err("%s: Context is not ready\n", __func__);
		return -EINVAL;
	}

	mutex_lock(&ctx->ctx_mutex);
	if (ctx->state_machine[ctx->state].crm_ops.flush_req) {
		rc = ctx->state_machine[ctx->state].crm_ops.flush_req(ctx,
			flush);
	} else {
		pr_err("%s: No crm flush req in dev %d, state %d\n",
			__func__, ctx->dev_hdl, ctx->state);
		rc = -EPROTO;
	}
	mutex_unlock(&ctx->ctx_mutex);

	return rc;
}

int cam_context_handle_acquire_dev(struct cam_context *ctx,
	struct cam_acquire_dev_cmd *cmd)
+22 −8
Original line number Diff line number Diff line
@@ -100,6 +100,7 @@ struct cam_ctx_ioctl_ops {
 * @link:                  Link the context
 * @unlink:                Unlink the context
 * @apply_req:             Apply setting for the context
 * @flush_req:             Flush request to remove request ids
 *
 */
struct cam_ctx_crm_ops {
@@ -111,6 +112,8 @@ struct cam_ctx_crm_ops {
			struct cam_req_mgr_core_dev_link_setup *unlink);
	int (*apply_req)(struct cam_context *ctx,
			struct cam_req_mgr_apply_request *apply);
	int (*flush_req)(struct cam_context *ctx,
			struct cam_req_mgr_flush_request *flush);
};


@@ -182,7 +185,7 @@ struct cam_context {
};

/**
 * cam_context_handle_get_dev_info()
 * cam_context_handle_crm_get_dev_info()
 *
 * @brief:        Handle get device information command
 *
@@ -190,11 +193,11 @@ struct cam_context {
 * @info:                  Device information returned
 *
 */
int cam_context_handle_get_dev_info(struct cam_context *ctx,
int cam_context_handle_crm_get_dev_info(struct cam_context *ctx,
		struct cam_req_mgr_device_info *info);

/**
 * cam_context_handle_link()
 * cam_context_handle_crm_link()
 *
 * @brief:        Handle link command
 *
@@ -202,11 +205,11 @@ int cam_context_handle_get_dev_info(struct cam_context *ctx,
 * @link:                  Link command payload
 *
 */
int cam_context_handle_link(struct cam_context *ctx,
int cam_context_handle_crm_link(struct cam_context *ctx,
		struct cam_req_mgr_core_dev_link_setup *link);

/**
 * cam_context_handle_unlink()
 * cam_context_handle_crm_unlink()
 *
 * @brief:        Handle unlink command
 *
@@ -214,11 +217,11 @@ int cam_context_handle_link(struct cam_context *ctx,
 * @unlink:                Unlink command payload
 *
 */
int cam_context_handle_unlink(struct cam_context *ctx,
int cam_context_handle_crm_unlink(struct cam_context *ctx,
		struct cam_req_mgr_core_dev_link_setup *unlink);

/**
 * cam_context_handle_apply_req()
 * cam_context_handle_crm_apply_req()
 *
 * @brief:        Handle apply request command
 *
@@ -226,9 +229,20 @@ int cam_context_handle_unlink(struct cam_context *ctx,
 * @apply:                 Apply request command payload
 *
 */
int cam_context_handle_apply_req(struct cam_context *ctx,
int cam_context_handle_crm_apply_req(struct cam_context *ctx,
		struct cam_req_mgr_apply_request *apply);

/**
 * cam_context_handle_crm_flush_req()
 *
 * @brief:        Handle flush request command
 *
 * @ctx:                   Object pointer for cam_context
 * @apply:                 Flush request command payload
 *
 */
int cam_context_handle_crm_flush_req(struct cam_context *ctx,
		struct cam_req_mgr_flush_request *apply);

/**
 * cam_context_handle_acquire_dev()
+31 −10
Original line number Diff line number Diff line
@@ -201,7 +201,7 @@ static int __cam_node_handle_release_dev(struct cam_node *node,
	return rc;
}

static int __cam_node_get_dev_info(struct cam_req_mgr_device_info *info)
static int __cam_node_crm_get_dev_info(struct cam_req_mgr_device_info *info)
{
	struct cam_context *ctx = NULL;

@@ -214,10 +214,11 @@ static int __cam_node_get_dev_info(struct cam_req_mgr_device_info *info)
			__func__, info->dev_hdl);
		return -EINVAL;
	}
	return cam_context_handle_get_dev_info(ctx, info);
	return cam_context_handle_crm_get_dev_info(ctx, info);
}

static int __cam_node_link_setup(struct cam_req_mgr_core_dev_link_setup *setup)
static int __cam_node_crm_link_setup(
	struct cam_req_mgr_core_dev_link_setup *setup)
{
	int rc;
	struct cam_context *ctx = NULL;
@@ -233,14 +234,14 @@ static int __cam_node_link_setup(struct cam_req_mgr_core_dev_link_setup *setup)
	}

	if (setup->link_enable)
		rc = cam_context_handle_link(ctx, setup);
		rc = cam_context_handle_crm_link(ctx, setup);
	else
		rc = cam_context_handle_unlink(ctx, setup);
		rc = cam_context_handle_crm_unlink(ctx, setup);

	return rc;
}

static int __cam_node_apply_req(struct cam_req_mgr_apply_request *apply)
static int __cam_node_crm_apply_req(struct cam_req_mgr_apply_request *apply)
{
	struct cam_context *ctx = NULL;

@@ -254,7 +255,26 @@ static int __cam_node_apply_req(struct cam_req_mgr_apply_request *apply)
		return -EINVAL;
	}

	return cam_context_handle_apply_req(ctx, apply);
	return cam_context_handle_crm_apply_req(ctx, apply);
}

static int __cam_node_crm_flush_req(struct cam_req_mgr_flush_request *flush)
{
	struct cam_context *ctx = NULL;

	if (!flush) {
		pr_err("%s: Invalid flush request payload\n", __func__);
		return -EINVAL;
	}

	ctx = (struct cam_context *) cam_get_device_priv(flush->dev_hdl);
	if (!ctx) {
		pr_err("%s: Can not get context for handle %d\n",
			__func__, flush->dev_hdl);
		return -EINVAL;
	}

	return cam_context_handle_crm_flush_req(ctx, flush);
}

int cam_node_deinit(struct cam_node *node)
@@ -283,9 +303,10 @@ int cam_node_init(struct cam_node *node, struct cam_hw_mgr_intf *hw_mgr_intf,
	strlcpy(node->name, name, sizeof(node->name));

	memcpy(&node->hw_mgr_intf, hw_mgr_intf, sizeof(node->hw_mgr_intf));
	node->crm_node_intf.apply_req = __cam_node_apply_req;
	node->crm_node_intf.get_dev_info = __cam_node_get_dev_info;
	node->crm_node_intf.link_setup = __cam_node_link_setup;
	node->crm_node_intf.apply_req = __cam_node_crm_apply_req;
	node->crm_node_intf.get_dev_info = __cam_node_crm_get_dev_info;
	node->crm_node_intf.link_setup = __cam_node_crm_link_setup;
	node->crm_node_intf.flush_req = __cam_node_crm_flush_req;

	mutex_init(&node->list_mutex);
	INIT_LIST_HEAD(&node->free_ctx_list);
+104 −22
Original line number Diff line number Diff line
@@ -14,11 +14,13 @@
#include <linux/videodev2.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/ratelimit.h>

#include "cam_isp_context.h"
#include "cam_isp_log.h"
#include "cam_mem_mgr.h"
#include "cam_sync_api.h"
#include "cam_req_mgr_dev.h"

#undef CDBG
#define CDBG(fmt, args...) pr_debug(fmt, ##args)
@@ -537,7 +539,7 @@ static int __cam_isp_ctx_apply_req_in_activated_state(
	 */
	list_for_each_entry(req, &ctx->active_req_list, list) {
		if (++cnt > 2) {
			pr_err("%s: Apply failed due to pipeline congestion\n",
			pr_err_ratelimited("%s: Apply failed due to congest\n",
				__func__);
			rc = -EFAULT;
			goto end;
@@ -627,6 +629,94 @@ static int __cam_isp_ctx_apply_req_in_bubble(
	return rc;
}

static int __cam_isp_ctx_flush_req(struct cam_context *ctx,
	struct list_head *req_list, struct cam_req_mgr_flush_request *flush_req)
{
	int i, rc;
	uint32_t cancel_req_id_found = 0;
	struct cam_ctx_request           *req;
	struct cam_ctx_request           *req_temp;
	struct cam_isp_ctx_req           *req_isp;

	spin_lock(&ctx->lock);
	if (list_empty(req_list)) {
		spin_unlock(&ctx->lock);
		CDBG("%s: request list is empty\n", __func__);
		return 0;
	}

	list_for_each_entry_safe(req, req_temp, req_list, list) {
		if ((flush_req->type == CAM_REQ_MGR_FLUSH_TYPE_CANCEL_REQ)
				&& (req->request_id != flush_req->req_id))
			continue;

		list_del_init(&req->list);
		req_isp = (struct cam_isp_ctx_req *) req->req_priv;
		for (i = 0; i < req_isp->num_fence_map_out; i++) {
			if (req_isp->fence_map_out[i].sync_id != -1) {
				CDBG("%s: Flush req 0x%llx, fence %d\n",
					__func__, req->request_id,
					req_isp->fence_map_out[i].sync_id);
				rc = cam_sync_signal(
					req_isp->fence_map_out[i].sync_id,
					CAM_SYNC_STATE_SIGNALED_ERROR);
				if (rc)
					pr_err_ratelimited("%s: signal fence failed\n",
						__func__);
				req_isp->fence_map_out[i].sync_id = -1;
			}
		}
		list_add_tail(&req->list, &ctx->free_req_list);

		/* If flush request id found, exit the loop */
		if (flush_req->type == CAM_REQ_MGR_FLUSH_TYPE_CANCEL_REQ) {
			cancel_req_id_found = 1;
			break;
		}
	}
	spin_unlock(&ctx->lock);

	if (flush_req->type == CAM_REQ_MGR_FLUSH_TYPE_CANCEL_REQ &&
		!cancel_req_id_found)
		CDBG("%s:Flush request id:%lld is not found in the list\n",
			__func__, flush_req->req_id);

	return 0;
}

static int __cam_isp_ctx_flush_req_in_top_state(
	struct cam_context *ctx,
	struct cam_req_mgr_flush_request *flush_req)
{
	int rc = 0;

	CDBG("%s: try to flush pending list\n", __func__);
	rc = __cam_isp_ctx_flush_req(ctx, &ctx->pending_req_list, flush_req);
	CDBG("%s: Flush request in top state %d\n",
		__func__, ctx->state);
	return rc;
}

static int __cam_isp_ctx_flush_req_in_ready(
	struct cam_context *ctx,
	struct cam_req_mgr_flush_request *flush_req)
{
	int rc = 0;

	CDBG("%s: try to flush pending list\n", __func__);
	rc = __cam_isp_ctx_flush_req(ctx, &ctx->pending_req_list, flush_req);

	/* if nothing is in pending req list, change state to acquire*/
	spin_lock(&ctx->lock);
	if (list_empty(&ctx->pending_req_list))
		ctx->state = CAM_CTX_ACQUIRED;
	spin_unlock(&ctx->lock);

	CDBG("%s: Flush request in ready state. next state %d\n",
		__func__, ctx->state);
	return rc;
}

static struct cam_ctx_ops
	cam_isp_ctx_activated_state_machine[CAM_ISP_CTX_ACTIVATED_MAX] = {
	/* SOF */
@@ -679,12 +769,10 @@ static int __cam_isp_ctx_release_dev_in_top_state(struct cam_context *ctx,
	struct cam_release_dev_cmd *cmd)
{
	int rc = 0;
	int i;
	struct cam_hw_release_args       rel_arg;
	struct cam_ctx_request	        *req;
	struct cam_isp_ctx_req	        *req_isp;
	struct cam_isp_context *ctx_isp =
		(struct cam_isp_context *) ctx->ctx_priv;
	struct cam_req_mgr_flush_request flush_req;

	if (ctx_isp->hw_ctx) {
		rel_arg.ctxt_to_hw_map = ctx_isp->hw_ctx;
@@ -704,25 +792,16 @@ static int __cam_isp_ctx_release_dev_in_top_state(struct cam_context *ctx,
	 * But we still add some sanity check code here to help the debug
	 */
	if (!list_empty(&ctx->active_req_list))
		pr_err("%s: Active list is empty.\n", __func__);
		pr_err("%s: Active list is not empty\n", __func__);

	/* Flush all the pending request list  */
	flush_req.type = CAM_REQ_MGR_FLUSH_TYPE_ALL;
	flush_req.link_hdl = ctx->link_hdl;
	flush_req.dev_hdl = ctx->dev_hdl;

	CDBG("%s: try to flush pending list\n", __func__);
	rc = __cam_isp_ctx_flush_req(ctx, &ctx->pending_req_list, &flush_req);

	/* flush the pending list */
	while (!list_empty(&ctx->pending_req_list)) {
		req = list_first_entry(&ctx->pending_req_list,
			struct cam_ctx_request, list);
		list_del_init(&req->list);
		req_isp = (struct cam_isp_ctx_req *) req->req_priv;
		pr_err("%s: signal fence in pending list. fence num %d\n",
			__func__, req_isp->num_fence_map_out);
		for (i = 0; i < req_isp->num_fence_map_out; i++) {
			if (req_isp->fence_map_out[i].sync_id != -1) {
				cam_sync_signal(
					req_isp->fence_map_out[i].sync_id,
					CAM_SYNC_STATE_SIGNALED_ERROR);
			}
		}
		list_add_tail(&req->list, &ctx->free_req_list);
	}
	ctx->state = CAM_CTX_AVAILABLE;
	CDBG("%s: next state %d\n", __func__, ctx->state);
	return rc;
@@ -1252,6 +1331,7 @@ static struct cam_ctx_ops
			.link = __cam_isp_ctx_link_in_acquired,
			.unlink = __cam_isp_ctx_unlink_in_acquired,
			.get_dev_info = __cam_isp_ctx_get_dev_info_in_acquired,
			.flush_req = __cam_isp_ctx_flush_req_in_top_state,
		},
		.irq_ops = NULL,
	},
@@ -1264,6 +1344,7 @@ static struct cam_ctx_ops
		},
		.crm_ops = {
			.unlink = __cam_isp_ctx_unlink_in_ready,
			.flush_req = __cam_isp_ctx_flush_req_in_ready,
		},
		.irq_ops = NULL,
	},
@@ -1276,6 +1357,7 @@ static struct cam_ctx_ops
		},
		.crm_ops = {
			.apply_req = __cam_isp_ctx_apply_req,
			.flush_req = __cam_isp_ctx_flush_req_in_top_state,
		},
		.irq_ops = __cam_isp_ctx_handle_irq_in_activated,
	},