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

Commit e57322e8 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: cam: reqmgr: Update camera req manager driver" into msm-4.9

parents 755c294b d79f95e3
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