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

Commit d79f95e3 authored by Sagar Gore's avatar Sagar Gore Committed by Gerrit - the friendly Code Review server
Browse files

msm: cam: reqmgr: Update camera req manager driver



Enable request tracking and apply control for camera drivers.
Process sof and apply requests based on pipeline delay of devices
linked with request manager. Support flush all or cancel particular
request scheduled to request manager. Recover from errors of hardware
update over frame boundary. Handle notify error from drivers and
initiate recovery mechanism. Debug support for printing useful debug
information such as session info, force recovery etc.

Change-Id: I3634d8a6efb5596303ae0feeb2dd3412fcbfa7f8
Signed-off-by: default avatarSagar Gore <sgore@codeaurora.org>
parent d49371a3
Loading
Loading
Loading
Loading
+7 −1
Original line number Diff line number Diff line
ccflags-y += -Idrivers/media/platform/msm/camera/cam_smmu/

obj-$(CONFIG_SPECTRA_CAMERA) += cam_req_mgr_dev.o cam_req_mgr_util.o cam_req_mgr_core.o cam_req_mgr_workq.o cam_mem_mgr.o
obj-$(CONFIG_SPECTRA_CAMERA) += cam_req_mgr_dev.o \
				cam_req_mgr_util.o \
				cam_req_mgr_core.o \
				cam_req_mgr_workq.o \
				cam_mem_mgr.o \
				cam_req_mgr_timer.o \
				cam_req_mgr_debug.o
+1789 −361

File changed.

Preview size limit exceeded, changes collapsed.

+264 −133
Original line number Diff line number Diff line
@@ -14,94 +14,224 @@

#include "cam_req_mgr_interface.h"
#include "cam_req_mgr_core_defs.h"
#include "cam_req_mgr_timer.h"

#define CAM_REQ_MGR_MAX_LINKED_DEV     16
#define MAX_REQ_SLOTS                  48

#define CAM_REQ_MGR_WATCHDOG_TIMEOUT   5000
#define CAM_REQ_MGR_SCHED_REQ_TIMEOUT  1000
#define CAM_REQ_MGR_SIMULATE_SCHED_REQ 30

#define FORCE_DISABLE_RECOVERY  2
#define FORCE_ENABLE_RECOVERY   1
#define AUTO_RECOVERY           0

#define CRM_WORKQ_NUM_TASKS 30

/**
 * enum crm_workq_task_type
 * @codes: to identify which type of task is present
 */
enum crm_workq_task_type {
	CRM_WORKQ_TASK_GET_DEV_INFO,
	CRM_WORKQ_TASK_SETUP_LINK,
	CRM_WORKQ_TASK_DEV_ADD_REQ,
	CRM_WORKQ_TASK_APPLY_REQ,
	CRM_WORKQ_TASK_NOTIFY_SOF,
	CRM_WORKQ_TASK_NOTIFY_ERR,
	CRM_WORKQ_TASK_SCHED_REQ,
	CRM_WORKQ_TASK_FLUSH_REQ,
	CRM_WORKQ_TASK_INVALID,
};

/**
 * struct crm_task_payload
 * @type       : to identify which type of task is present
 * @u          : union of payload of all types of tasks supported
 * @sched_req  : contains info of  incoming reqest from CSL to CRM
 * @flush_info : contains info of cancelled reqest
 * @dev_req    : contains tracking info of available req id at device
 * @send_req   : contains info of apply settings to be sent to devs in link
 * @apply_req  : contains info of which request is applied at device
 * @notify_sof : contains notification from IFE to CRM about SOF trigger
 * @notify_err : contains error info happened while processing request
 * -
 */
struct crm_task_payload {
	enum crm_workq_task_type type;
	union {
		struct cam_req_mgr_sched_request        sched_req;
		struct cam_req_mgr_flush_info           flush_info;
		struct cam_req_mgr_add_request          dev_req;
		struct cam_req_mgr_send_request         send_req;
		struct cam_req_mgr_sof_notify           notify_sof;
		struct cam_req_mgr_error_notify         notify_err;
	} u;
};

/**
 * enum crm_req_state
 * State machine for life cycle of request in pd table
 * EMPTY   : indicates req slot is empty
 * PENDING : indicates req slot is waiting for reqs from all devs
 * READY   : indicates req slot is ready to be sent to devs
 * INVALID : indicates req slot is not in valid state
 */
enum crm_req_state {
	CRM_REQ_STATE_EMPTY,
	CRM_REQ_STATE_PENDING,
	CRM_REQ_STATE_READY,
	CRM_REQ_STATE_INVALID,
};

/**
 * enum crm_req_status
 * State machine for life cycle of request in link
 * EMPTY - indicates req slot is empty
 * PENDING - indicates req slot is waiting for reqs from all devs
 * READY - indicates req slot is ready to be sent to devs
 * APPLIED - indicates req slot is sent to devices
 * INVALID - indicates req slot is not in valid state
 * enum crm_slot_status
 * State machine for life cycle of request in input queue
 * NO_REQ     : empty slot
 * REQ_ADDED  : new entry in slot
 * INCOMPLETE : waiting for
 * APPLIED    : req is sent to devices
 * INVALID    : invalid state
 */
enum crm_req_status {
	CRM_REQ_STATUS_EMPTY,
	CRM_REQ_STATUS_PENDING,
	CRM_REQ_STATUS_READY,
	CRM_REQ_STATUS_APPLIED,
	CRM_REQ_STATUS_INVALID,
enum crm_slot_status {
	CRM_SLOT_STATUS_NO_REQ,
	CRM_SLOT_STATUS_REQ_ADDED,
	CRM_SLOT_STATUS_REQ_PENDING,
	CRM_SLOT_STATUS_REQ_APPLIED,
	CRM_SLOT_STATUS_INVALID,
};

/**
 * enum cam_req_mgr_link_state
 * State machine for life cycle of link in crm
 * AVAILABLE - indicates link is not in use
 * IDLE - indicates link is reserved but not initialized
 * READY - indicates link is initialized and ready for operation
 * STREAMING - indicates link is receiving triggers and requests
 * BUBBLE_DETECTED - indicates device on link is in bad shape
 * ROLLBACK_STARTED - indicates link had triggered error recovery
 * MAX - indicates link max as invalid
 * AVAILABLE  : link available
 * IDLE       : link initialized but not ready yet
 * READY      : link is ready for use
 * ERR	      : link has encountered error
 * MAX        : invalid state
 */
enum cam_req_mgr_link_state {
	CAM_CRM_LINK_STATE_AVAILABLE,
	CAM_CRM_LINK_STATE_IDLE,
	CAM_CRM_LINK_STATE_READY,
	CAM_CRM_LINK_STATE_STREAMING,
	CAM_CRM_LINK_STATE_BUBBLE_DETECTED,
	CAM_CRM_LINK_STATE_ROLLBACK_STARTED,
	CAM_CRM_LINK_STATE_DEVICE_STATE_MAX,
	CAM_CRM_LINK_STATE_ERR,
	CAM_CRM_LINK_STATE_MAX,
};

/**
 * struct cam_req_mgr_request_slot
 * @idx: device handle
 * @req_status: state machine for life cycle of a request
 * @request_id: request id value
 * struct cam_req_mgr_traverse
 * @idx        : slot index
 * @result     : contains which all tables were able to apply successfully
 * @tbl        : pointer of pipeline delay based request table
 * @apply_data : pointer which various tables will update during traverse
 * @in_q       : input request queue pointer
 */
struct cam_req_mgr_request_slot {
struct cam_req_mgr_traverse {
	int32_t                       idx;
	enum crm_req_status req_status;
	int64_t request_id;
	uint32_t                      result;
	struct cam_req_mgr_req_tbl   *tbl;
	struct cam_req_mgr_apply     *apply_data;
	struct cam_req_mgr_req_queue *in_q;
};

/**
 * struct cam_req_mgr_request_queue
 * @read_index: idx currently being processed
 * @write_index: idx at which incoming req is stored
 * @num_slots: num of req slots i.e. queue depth
 * @req_slot: slots which hold the request info
 * struct cam_req_mgr_apply
 * @idx      : corresponding input queue slot index
 * @pd       : pipeline delay of device
 * @req_id   : req id for dev with above pd to process
 * @skip_idx: skip applying settings when this is set.
 */
struct cam_req_mgr_request_queue {
	int32_t read_index;
	int32_t write_index;
	uint32_t num_slots;
	struct cam_req_mgr_request_slot *req_slot;
struct cam_req_mgr_apply {
	int32_t idx;
	int32_t pd;
	int64_t req_id;
	int32_t skip_idx;
};

/**
 * struct cam_req_mgr_frame_settings
 * @request_id: request id to apply
 * @frame_id: frame id for debug purpose
 * struct cam_req_mgr_tbl_slot
 * @idx           : slot index
 * @req_ready_map : mask tracking which all devices have request ready
 * @state         : state machine for life cycle of a slot
 */
struct cam_req_mgr_frame_settings {
	int64_t request_id;
	int64_t frame_id;
struct cam_req_mgr_tbl_slot {
	int32_t             idx;
	uint32_t            req_ready_map;
	enum crm_req_state  state;
};

/**
 * struct cam_req_mgr_req_tbl
 * @id            : table indetifier
 * @pd            : pipeline delay of table
 * @dev_count     : num of devices having same pipeline delay
 * @dev_mask      : mask to track which devices are linked
 * @skip_traverse : to indicate how many traverses need to be dropped
 *              by this table especially in the beginning or bubble recovery
 * @next          : pointer to next pipeline delay request table
 * @pd_delta      : differnce between this table's pipeline delay and next
 * @num_slots     : number of request slots present in the table
 * @slot          : array of slots tracking requests availability at devices
 */
struct cam_req_mgr_req_tbl {
	int32_t                     id;
	int32_t                     pd;
	int32_t                     dev_count;
	int32_t                     dev_mask;
	int32_t                     skip_traverse;
	struct cam_req_mgr_req_tbl *next;
	int32_t                     pd_delta;
	int32_t                     num_slots;
	struct cam_req_mgr_tbl_slot slot[MAX_REQ_SLOTS];
};

/**
 * struct cam_req_mgr_request_table
 * @pipeline_delay: pipeline delay of this req table
 * @l_devices: list of devices belonging to this p_delay
 * @dev_mask: each dev hdl has unique bit assigned, dev mask tracks if all devs
 *  received req id packet from UMD to process
 * struct cam_req_mgr_slot
 * - Internal Book keeping
 * @idx      : slot index
 * @skip_idx : if req id in this slot needs to be skipped/not applied
 * @status   : state machine for life cycle of a slot
 * - members updated due to external events
 * @recover  : if user enabled recovery for this request.
 * @req_id   : mask tracking which all devices have request ready
 */
struct cam_req_mgr_request_table {
	uint32_t pipeline_delay;
	struct list_head l_devices;
	uint32_t dev_mask;
struct cam_req_mgr_slot {
	int32_t               idx;
	int32_t               skip_idx;
	enum crm_slot_status  status;
	int32_t               recover;
	int64_t               req_id;
};

/**
 * struct cam_req_mgr_req_queue
 * @num_slots   : max num of input queue slots
 * @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.
 */
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;
};

/**
 * struct cam_req_mgr_req_data
 * @in_q        : Poiner to Input request queue
 * @l_tbl       : unique pd request tables.
 * @num_tbl     : how many unique pd value devices are present
 * @apply_data	: Holds information about request id for a request
 * @lock        : mutex lock protecting request data ops.
 */
struct cam_req_mgr_req_data {
	struct cam_req_mgr_req_queue *in_q;
	struct cam_req_mgr_req_tbl   *l_tbl;
	int32_t                       num_tbl;
	struct cam_req_mgr_apply      apply_data[CAM_PIPELINE_DELAY_MAX];
	struct mutex                  lock;
};

/**
@@ -109,77 +239,81 @@ struct cam_req_mgr_request_table {
 * - Device Properties
 * @dev_hdl  : device handle
 * @dev_bit  : unique bit assigned to device in link
 * -Device progress status
 * @available_req_id: tracks latest available req id at this device
 * @processing_req_id: tracks request id currently processed
 * - Device characteristics
 * @pd_tbl   : tracks latest available req id at this device
 * @dev_info : holds dev characteristics such as pipeline delay, dev name
 * @ops      : holds func pointer to call methods on this device
 * @parent: pvt data - Pointer to parent link device its connected with
 * @entry: entry to the list of connected devices in link
 * @parent   : pvt data - like link which this dev hdl belongs to
 */
struct cam_req_mgr_connected_device {
	int32_t                         dev_hdl;
	int64_t                         dev_bit;
	int64_t available_req_id;
	int64_t processing_req_id;
	struct cam_req_mgr_req_tbl     *pd_tbl;
	struct cam_req_mgr_device_info  dev_info;
	struct cam_req_mgr_kmd_ops     *ops;
	void                           *parent;
	struct list_head entry;
};

/**
 * struct cam_req_mgr_core_link
 * -  Link Properties
 * @link_hdl       : Link identifier
 * @num_connections: num of connected devices to this link
 * @max_pipeline_delay: Max of pipeline delay of all connected devs
 * - Input request queue
 * @in_requests: Queue to hold incoming request hints from CSL
 * @num_devs       : num of connected devices to this link
 * @max_delay      : Max of pipeline delay of all connected devs
 * @workq          : Pointer to handle workq related jobs
 * @pd_mask        : each set bit indicates the device with pd equal to bit
 *                   position is available.
 * - List of connected devices
 * @l_devices: List of connected devices to this link
 * @fs_list: Holds the request id which each device in link will consume.
 * @req_table: table to keep track of req ids recived at each dev handle
 * @l_dev          : List of connected devices to this link
 * - Request handling data struct
 * @req            : req data holder.
 * - Timer
 * @watchdog       : watchdog timer to recover from sof freeze
 * - Link private data
 * @link_state: link state cycle
 * @parent: pvt data - like session info
 * @link_head: List head of connected devices
 * @lock: spin lock to guard link data operations
 * @workq_comp     : conditional variable to block user thread for workq to
 *                   finish schedule request processing
 * @state          : link state machine
 * @parent         : pvt data - link's parent is session
 * @lock           : mutex lock to guard link data operations
 */
struct cam_req_mgr_core_link {
	int32_t                              link_hdl;
	int32_t num_connections;
	enum cam_pipeline_delay max_pipeline_delay;
	struct cam_req_mgr_request_queue in_requests;
	int32_t                              num_devs;
	enum cam_pipeline_delay              max_delay;
	struct cam_req_mgr_core_workq       *workq;
	struct cam_req_mgr_connected_device *l_devices;
	struct cam_req_mgr_frame_settings fs_list[CAM_REQ_MGR_MAX_LINKED_DEV];
	struct cam_req_mgr_request_table req_table[CAM_PIPELINE_DELAY_MAX];
	enum cam_req_mgr_link_state link_state;
	int32_t                              pd_mask;
	struct cam_req_mgr_connected_device *l_dev;
	struct cam_req_mgr_req_data          req;
	struct cam_req_mgr_timer            *watchdog;
	struct completion                    workq_comp;
	enum cam_req_mgr_link_state          state;
	void                                *parent;
	struct list_head link_head;
	spinlock_t lock;
	struct mutex                         lock;
};

/**
 * struct cam_req_mgr_core_session
 * - Session Properties
 * @session_hdl        : session identifier
 * @num_active_links: num of active links for current session
 * @num_links          : num of active links for current session
 * - Links of this session
 * @links              : pointer to array of links within session
 * @in_q               : Input request queue one per session
 * - Session private data
 * @entry              : pvt data - entry in the list of sessions
 * @lock               : pvt data - spin lock to guard session data
 * - Debug data
 * @force_err_recovery : For debugging, we can force bubble recovery
 *                       to be always ON or always OFF using debugfs.
 */
struct cam_req_mgr_core_session {
	int32_t                       session_hdl;
	uint32_t num_active_links;
	struct cam_req_mgr_core_link links[MAX_LINKS_PER_SESSION];
	uint32_t                      num_links;
	struct cam_req_mgr_core_link *links[MAX_LINKS_PER_SESSION];
	struct cam_req_mgr_req_queue  in_q;
	struct list_head              entry;
	spinlock_t lock;
	struct mutex                  lock;
	int32_t                       force_err_recovery;
};

/**
@@ -193,16 +327,14 @@ struct cam_req_mgr_core_device {
	struct mutex                 crm_lock;
};

/* cam_req_mgr_dev to cam_req_mgr_core internal functions */
/**
 * cam_req_mgr_create_session()
 * @brief    : creates session
 * @ses_info : output param for session handle
 *
 * Called as part of session creation.
 * called as part of session creation.
 */
int cam_req_mgr_create_session(
	struct cam_req_mgr_session_info *ses_info);
int cam_req_mgr_create_session(struct cam_req_mgr_session_info *ses_info);

/**
 * cam_req_mgr_destroy_session()
@@ -212,15 +344,14 @@ int cam_req_mgr_create_session(
 * Called as part of session destroy
 * return success/failure
 */
int cam_req_mgr_destroy_session(
	struct cam_req_mgr_session_info *ses_info);
int cam_req_mgr_destroy_session(struct cam_req_mgr_session_info *ses_info);

/**
 * cam_req_mgr_link()
 * @brief     : creates a link for a session
 * @link_info : handle and session info to create a link
 *
 * Link is formed in a session for multiple devices. It creates
 * link is formed in a session for multiple devices. it creates
 * a unique link handle for the link and is specific to a
 * session. Returns link handle
 */
@@ -231,7 +362,7 @@ int cam_req_mgr_link(struct cam_req_mgr_link_info *link_info);
 * @brief       : destroy a link in a session
 * @unlink_info : session and link handle info
 *
 * Link is destroyed in a session
 * link is destroyed in a session
 */
int cam_req_mgr_unlink(struct cam_req_mgr_unlink_info *unlink_info);

@@ -244,11 +375,11 @@ int cam_req_mgr_schedule_request(
	struct cam_req_mgr_sched_request *sched_req);

/**
 * cam_req_mgr_sync_mode()
 * cam_req_mgr_sync_link()
 * @brief: sync for links in a session
 * @sync_links: session, links info and master link info
 */
int cam_req_mgr_sync_mode(struct cam_req_mgr_sync_mode *sync_links);
int cam_req_mgr_sync_link(struct cam_req_mgr_sync_mode *sync_links);

/**
 * cam_req_mgr_flush_requests()
+10 −0
Original line number Diff line number Diff line
@@ -15,6 +15,16 @@
#define CRM_TRACE_ENABLE 0
#define CRM_DEBUG_MUTEX 0

#define SET_SUCCESS_BIT(ret, pd)	{\
	(ret) |= (1 << (pd));	\
	}

#define SET_FAILURE_BIT(ret, pd)	{\
	(ret) &= (0 << (pd));	\
	}

#define CRM_GET_REQ_ID(in_q, idx) in_q->slot[idx].req_id

#if (CRM_TRACE_ENABLE == 1)
	#define CRM_DBG(fmt, args...) do { \
	trace_printk("%d: [crm_dbg] "fmt"\n", __LINE__, ##args); \
+139 −0
Original line number Diff line number Diff line
/* Copyright (c) 2016-2017, 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
 * only version 2 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

#include "cam_req_mgr_debug.h"

#define MAX_SESS_INFO_LINE_BUFF_LEN 256

static char sess_info_buffer[MAX_SESS_INFO_LINE_BUFF_LEN];

static int cam_req_mgr_debug_set_bubble_recovery(void *data, u64 val)
{
	struct cam_req_mgr_core_device  *core_dev = data;
	struct cam_req_mgr_core_session *session;
	int rc = 0;

	mutex_lock(&core_dev->crm_lock);

	if (!list_empty(&core_dev->session_head)) {
		list_for_each_entry(session,
			&core_dev->session_head, entry) {
			session->force_err_recovery = val;
		}
	}

	mutex_unlock(&core_dev->crm_lock);

	return rc;
}

static int cam_req_mgr_debug_get_bubble_recovery(void *data, u64 *val)
{
	struct cam_req_mgr_core_device *core_dev = data;
	struct cam_req_mgr_core_session *session;

	mutex_lock(&core_dev->crm_lock);

	if (!list_empty(&core_dev->session_head)) {
		session = list_first_entry(&core_dev->session_head,
			struct cam_req_mgr_core_session,
			entry);
		*val = session->force_err_recovery;
	}
	mutex_unlock(&core_dev->crm_lock);

	return 0;
}

DEFINE_SIMPLE_ATTRIBUTE(bubble_recovery, cam_req_mgr_debug_get_bubble_recovery,
	cam_req_mgr_debug_set_bubble_recovery, "%lld\n");

static int session_info_open(struct inode *inode, struct file *file)
{
	file->private_data = inode->i_private;
	return 0;
}

static ssize_t session_info_read(struct file *t_file, char *t_char,
	size_t t_size_t, loff_t *t_loff_t)
{
	int i;
	char *out_buffer = sess_info_buffer;
	char line_buffer[MAX_SESS_INFO_LINE_BUFF_LEN] = {0};
	struct cam_req_mgr_core_device *core_dev =
		(struct cam_req_mgr_core_device *) t_file->private_data;
	struct cam_req_mgr_core_session *session;

	memset(out_buffer, 0, MAX_SESS_INFO_LINE_BUFF_LEN);

	mutex_lock(&core_dev->crm_lock);

	if (!list_empty(&core_dev->session_head)) {
		list_for_each_entry(session,
			&core_dev->session_head, entry) {
			snprintf(line_buffer, sizeof(line_buffer),
				"session_hdl = %x \t"
				"num_links = %d\n",
				session->session_hdl, session->num_links);
			strlcat(out_buffer, line_buffer,
				sizeof(sess_info_buffer));
			for (i = 0; i < session->num_links; i++) {
				snprintf(line_buffer, sizeof(line_buffer),
					"link_hdl[%d] = 0x%x, num_devs connected = %d\n",
					i, session->links[i]->link_hdl,
					session->links[i]->num_devs);
				strlcat(out_buffer, line_buffer,
					sizeof(sess_info_buffer));
			}
		}
	}

	mutex_unlock(&core_dev->crm_lock);

	return simple_read_from_buffer(t_char, t_size_t,
		t_loff_t, out_buffer, strlen(out_buffer));
}

static ssize_t session_info_write(struct file *t_file,
	const char *t_char, size_t t_size_t, loff_t *t_loff_t)
{
	memset(sess_info_buffer, 0, MAX_SESS_INFO_LINE_BUFF_LEN);

	return 0;
}

static const struct file_operations session_info = {
	.open = session_info_open,
	.read = session_info_read,
	.write = session_info_write,
};

int cam_req_mgr_debug_register(struct cam_req_mgr_core_device *core_dev)
{
	struct dentry *debugfs_root;
	char dirname[32] = {0};

	snprintf(dirname, sizeof(dirname), "cam_req_mgr");
	debugfs_root = debugfs_create_dir(dirname, NULL);
	if (!debugfs_root)
		return -ENOMEM;

	if (!debugfs_create_file("sessions_info", 0644,
		debugfs_root, core_dev, &session_info))
		return -ENOMEM;

	if (!debugfs_create_file("bubble_recovery", 0644,
		debugfs_root, core_dev, &bubble_recovery))
		return -ENOMEM;

	return 0;
}
Loading