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

Commit 30d56c29 authored by Gaurav Jindal's avatar Gaurav Jindal
Browse files

msm: camera: LDAR Debug info dump framework implementation



When user space detects an error for a request or does
not receive the expected response. it sends dump request
to kernel space.
User space passes the culprit issue request id
and the buffer where the info can be dumped.
Kernel space traverse across the drivers and find the culprit hw
and dumps the relevant information in the buffer.
This data is written to a file by user space for offline
processing.
This commit implements the framework for the traversal
across the RT and NRT devices.

Change-Id: I0b14206f1b740089677160eecf84025c6babf59d
Signed-off-by: default avatarGaurav Jindal <gjindal@codeaurora.org>
parent 7f757e61
Loading
Loading
Loading
Loading
+49 −0
Original line number Diff line number Diff line
@@ -234,6 +234,28 @@ int cam_context_handle_crm_process_evt(struct cam_context *ctx,
	return rc;
}

int cam_context_handle_crm_dump_req(struct cam_context *ctx,
	struct cam_req_mgr_dump_info *dump)
{
	int rc = 0;

	if (!ctx->state_machine) {
		CAM_ERR(CAM_CORE, "Context is not ready");
		return -EINVAL;
	}
	mutex_lock(&ctx->ctx_mutex);
	if (ctx->state_machine[ctx->state].crm_ops.dump_req) {
		rc = ctx->state_machine[ctx->state].crm_ops.dump_req(ctx,
			dump);
	} else {
		CAM_ERR(CAM_CORE, "No crm dump req in dev %d, state %d",
			ctx->dev_hdl, ctx->state);
	}
	mutex_unlock(&ctx->ctx_mutex);

	return rc;
}

int cam_context_dump_pf_info(struct cam_context *ctx, unsigned long iova,
	uint32_t buf_info)
{
@@ -502,6 +524,33 @@ int cam_context_handle_stop_dev(struct cam_context *ctx,
	return rc;
}

int cam_context_handle_dump_dev(struct cam_context *ctx,
	struct cam_dump_req_cmd *cmd)
{
	int rc = 0;

	if (!ctx || !ctx->state_machine) {
		CAM_ERR(CAM_CORE, "Context is not ready");
		return -EINVAL;
	}

	if (!cmd) {
		CAM_ERR(CAM_CORE, "Invalid stop device command payload");
		return -EINVAL;
	}

	mutex_lock(&ctx->ctx_mutex);
	if (ctx->state_machine[ctx->state].ioctl_ops.dump_dev)
		rc = ctx->state_machine[ctx->state].ioctl_ops.dump_dev(
			ctx, cmd);
	else
		CAM_WARN(CAM_CORE, "No dump device in dev %d, name %s state %d",
			ctx->dev_hdl, ctx->dev_name, ctx->state);
	mutex_unlock(&ctx->ctx_mutex);

	return rc;
}

int cam_context_init(struct cam_context *ctx,
	const char *dev_name,
	uint64_t dev_id,
+32 −0
Original line number Diff line number Diff line
@@ -92,6 +92,7 @@ struct cam_ctx_request {
 * @flush_dev:             Function pointer for flush device
 * @acquire_hw:            Function pointer for acquire hw
 * @release_hw:            Function pointer for release hw
 * @dump_dev:              Function pointer for dump dev
 *
 */
struct cam_ctx_ioctl_ops {
@@ -109,6 +110,9 @@ struct cam_ctx_ioctl_ops {
			struct cam_flush_dev_cmd *cmd);
	int (*acquire_hw)(struct cam_context *ctx, void *args);
	int (*release_hw)(struct cam_context *ctx, void *args);
	int (*dump_dev)(struct cam_context *ctx,
			struct cam_dump_req_cmd *cmd);

};

/**
@@ -120,6 +124,7 @@ struct cam_ctx_ioctl_ops {
 * @apply_req:             Apply setting for the context
 * @flush_req:             Flush request to remove request ids
 * @process_evt:           Handle event notification from CRM.(optional)
 * @dump_req:              Dump information for the issue request
 *
 */
struct cam_ctx_crm_ops {
@@ -135,6 +140,8 @@ struct cam_ctx_crm_ops {
			struct cam_req_mgr_flush_request *flush);
	int (*process_evt)(struct cam_context *ctx,
			struct cam_req_mgr_link_evt_data *evt_data);
	int (*dump_req)(struct cam_context *ctx,
			struct cam_req_mgr_dump_info *dump);
};


@@ -304,6 +311,18 @@ int cam_context_handle_crm_flush_req(struct cam_context *ctx,
int cam_context_handle_crm_process_evt(struct cam_context *ctx,
	struct cam_req_mgr_link_evt_data *process_evt);

/**
 * cam_context_handle_crm_dump_req()
 *
 * @brief:        Handle CRM dump request
 *
 * @ctx:          Object pointer for cam_context
 * @dump:         Request to dump
 *
 */
int cam_context_handle_crm_dump_req(struct cam_context *ctx,
	struct cam_req_mgr_dump_info *dump);

/**
 * cam_context_dump_pf_info()
 *
@@ -413,6 +432,19 @@ int cam_context_handle_start_dev(struct cam_context *ctx,
int cam_context_handle_stop_dev(struct cam_context *ctx,
		struct cam_start_stop_dev_cmd *cmd);


/**
 * cam_context_handle_dump_dev()
 *
 * @brief:        Handle dump device command
 *
 * @ctx:          Object pointer for cam_context
 * @cmd:          Dump device command payload
 *
 */
int cam_context_handle_dump_dev(struct cam_context *ctx,
	struct cam_dump_req_cmd *cmd);

/**
 * cam_context_deinit()
 *
+40 −0
Original line number Diff line number Diff line
@@ -1044,3 +1044,43 @@ int32_t cam_context_dump_pf_info_to_hw(struct cam_context *ctx,
end:
	return rc;
}

int32_t cam_context_dump_dev_to_hw(struct cam_context *ctx,
	struct cam_dump_req_cmd *cmd)
{
	int rc = 0;
	struct cam_hw_dump_args dump_args;

	if (!ctx || !cmd) {
		CAM_ERR(CAM_CTXT, "Invalid input params %pK %pK", ctx, cmd);
		return -EINVAL;
	}
	if (!ctx->hw_mgr_intf) {
		CAM_ERR(CAM_CTXT, "[%s][%d] HW interface is not ready",
			ctx->dev_name, ctx->ctx_id);
		return -EFAULT;
	}
	memset(&dump_args, 0, sizeof(dump_args));
	if (ctx->hw_mgr_intf->hw_dump) {
		dump_args.ctxt_to_hw_map = ctx->ctxt_to_hw_map;
		dump_args.buf_handle = cmd->buf_handle;
		dump_args.offset = cmd->offset;
		dump_args.request_id = cmd->issue_req_id;
		rc  = ctx->hw_mgr_intf->hw_dump(
			ctx->hw_mgr_intf->hw_mgr_priv,
			&dump_args);
		if (rc) {
			CAM_ERR(CAM_CTXT, "[%s][%d] handle[%u] failed",
			    ctx->dev_name, ctx->ctx_id, dump_args.buf_handle);
			return rc;
		}
		CAM_INFO(CAM_CTXT, "[%s] ctx: %d Filled Length %d",
		    ctx->dev_name, ctx->ctx_id,
		    dump_args.offset - cmd->offset);
		/* Drivers update offest upto which the buffer is written*/
		cmd->offset  = dump_args.offset;
	} else {
		CAM_INFO(CAM_CTXT, "%s hw dump not registered", ctx->dev_name);
	}
	return rc;
}
+3 −2
Original line number Diff line number Diff line
/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -36,5 +36,6 @@ int32_t cam_context_flush_req_to_hw(struct cam_context *ctx,
int32_t cam_context_dump_pf_info_to_hw(struct cam_context *ctx,
	struct cam_packet *packet, unsigned long iova, uint32_t buf_info,
	bool *mem_found);

int32_t cam_context_dump_dev_to_hw(struct cam_context *ctx,
	struct cam_dump_req_cmd *cmd);
#endif /* _CAM_CONTEXT_UTILS_H_ */
+17 −0
Original line number Diff line number Diff line
@@ -272,6 +272,21 @@ struct cam_hw_reset_args {
	void                           *ctxt_to_hw_map;
};

/**
 * struct cam_hw_dump_args - Dump arguments
 *
 * @request_id:            request_id
 * @buf_handle:            Buffer handle
 * @offset:                Buffer offset. This is updated by the drivers.
 * @ctxt_to_hw_map:        HW context from the acquire
 */
struct cam_hw_dump_args {
	uint64_t          request_id;
	uint32_t          buf_handle;
	int32_t           offset;
	void             *ctxt_to_hw_map;
};

/* enum cam_hw_mgr_command - Hardware manager command type */
enum cam_hw_mgr_command {
	CAM_HW_MGR_CMD_INTERNAL,
@@ -324,6 +339,7 @@ struct cam_hw_cmd_args {
 * @hw_close:                  Function pointer for HW deinit
 * @hw_flush:                  Function pointer for HW flush
 * @hw_reset:                  Function pointer for HW reset
 * @hw_dump:                   Function pointer for HW dump
 *
 */
struct cam_hw_mgr_intf {
@@ -345,6 +361,7 @@ struct cam_hw_mgr_intf {
	int (*hw_close)(void *hw_priv, void *hw_close_args);
	int (*hw_flush)(void *hw_priv, void *hw_flush_args);
	int (*hw_reset)(void *hw_priv, void *hw_reset_args);
	int (*hw_dump)(void *hw_priv, void *hw_dump_args);
};

#endif /* _CAM_HW_MGR_INTF_H_ */
Loading