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

Commit 71001c62 authored by Ahmed Abdul-Salam's avatar Ahmed Abdul-Salam
Browse files

msm: VPU: Implement Session Create and Session Join Ioctls



New ioctls ensure no overlap in VPU usage from independent clients.
- VPU_CREATE_SESSION ioctl allows clients to create a new session by
attaching to the next available one.
- VPU_JOIN_SESSION allows clients to join an active session.
- VPU_ATTACH_TO_SESSION is deprecated but remains unchanged.
New events related to session attach/detach to allow clients to coordinate
use of VPU.

Change-Id: Icb22461824daa97c06bf54fa66b67156fbfa0b93
Signed-off-by: default avatarAhmed Abdul-Salam <aabdulsa@codeaurora.org>
parent 1155db4b
Loading
Loading
Loading
Loading
+125 −14
Original line number Diff line number Diff line
@@ -42,6 +42,9 @@ extern int vpu_init_port_mdss(struct vpu_dev_session *session,
		    (session)->port_info[port].port_ops.priv) : 0)
/*
 * Events/Callbacks handling
 *
 * Notify events of given type ID.
 * If data is not null then it points to a payload of predefined size (<=64).
 */
static void __prepare_v4l2_event(struct v4l2_event *event,
		u32 type, u8 *data, u32 size)
@@ -55,7 +58,7 @@ static void __prepare_v4l2_event(struct v4l2_event *event,
		memcpy(event->u.data, data, size);
}

void notify_vpu_event_client(struct vpu_client *client,
static void notify_vpu_event_client(struct vpu_client *client,
		u32 type, u8 *data, u32 size)
{
	struct v4l2_event event = {0};
@@ -66,7 +69,7 @@ void notify_vpu_event_client(struct vpu_client *client,
	v4l2_event_queue_fh(&client->vfh, &event);
}

void notify_vpu_event_session(struct vpu_dev_session *session,
static void notify_vpu_event_session(struct vpu_dev_session *session,
		u32 type, u8 *data, u32 size)
{
	struct v4l2_event event = {0};
@@ -80,6 +83,28 @@ void notify_vpu_event_session(struct vpu_dev_session *session,
		v4l2_event_queue_fh(&clnt->vfh, &event);
}

static void notify_vpu_event_system(struct vpu_dev_core *core,
		u32 type, u8 *data, u32 size)
{
	struct v4l2_event event = {0};
	struct vpu_client *clnt, *n;
	int i;
	if (!core)
		return;

	__prepare_v4l2_event(&event, type, data, size);

	for (i = 0; i < VPU_NUM_SESSIONS; i++) {
		list_for_each_entry_safe(clnt, n,
				&core->sessions[i]->clients_list, clients_entry)
			v4l2_event_queue_fh(&clnt->vfh, &event);
	}

	list_for_each_entry_safe(clnt, n,
				      &core->unattached_list, clients_entry)
		v4l2_event_queue_fh(&clnt->vfh, &event);
}

/* __system_callback_handler
 *
 * event:	see enum vpu_chan_event defined in vpu_channel.h
@@ -315,20 +340,17 @@ int vpu_close_client(struct vpu_client *client)
	return 0;
}

int vpu_attach_client(struct vpu_client *client, int session_num)
static int __vpu_attach_client(struct vpu_client *client,
		struct vpu_dev_session *session)
{
	struct vpu_dev_core *core;
	struct vpu_dev_session *session;
	int ret = 0;
	if (!client || session_num < 0 || session_num >= VPU_NUM_SESSIONS) {
		pr_err("invalid session attach # %d\n", session_num);
		return -EINVAL;
	}

	if (!client)
		return -EINVAL;
	core = client->core;
	session = core->sessions[session_num];

	pr_debug("Attach client %p to session %d\n", client, session_num);
	pr_debug("Attach client %p to session %d\n", client, session->id);

	if (client->session == session) {
		return 0; /* client already attached to this session */
@@ -340,8 +362,6 @@ int vpu_attach_client(struct vpu_client *client, int session_num)
	if (session->client_count >= VPU_MAX_CLIENTS_PER_SESSION)
		return -EBUSY;

	mutex_lock(&session->lock);

	if (session->client_count++ == 0) {

		/* Initialize session controller */
@@ -358,15 +378,17 @@ int vpu_attach_client(struct vpu_client *client, int session_num)
			pr_err("could not open IPC channel\n");
			goto err_deinit_controller;
		}

		notify_vpu_event_system(core, VPU_EVENT_SESSION_CREATED,
				(u8 *)&session->id, sizeof(session->id));
	}

	/* remove from unattached_list and add to session's clients list */
	list_del_init(&client->clients_entry);
	list_add_tail(&client->clients_entry, &session->clients_list);
	client->session = session;
	mutex_unlock(&session->lock);

	pr_debug("Attach to session %d successful\n", session_num);
	pr_debug("Attach to session %d successful\n", session->id);
	return 0;

err_deinit_controller:
@@ -374,7 +396,87 @@ err_deinit_controller:
	session->controller = NULL;
err_dec_count:
	session->client_count--;
	return ret;
}

int vpu_create_session(struct vpu_client *client)
{
	struct vpu_dev_core *core;
	struct vpu_dev_session *session;
	int ret, i;

	if (!client)
		return -EINVAL;
	core = client->core;

	/* find an inactive session */
	for (i = 0; i < VPU_NUM_SESSIONS; i++) {
		session = core->sessions[i];

		mutex_lock(&session->lock);

		if (session->client_count > 0) {
			mutex_unlock(&session->lock);
		} else {
			ret = __vpu_attach_client(client, session);
			if (ret)
				pr_err("Failed attach, ret = %d\n", ret);
			else
				ret = session->id; /* return session number */
			mutex_unlock(&session->lock);

			return ret;
		}
	}

	pr_warn("No idle sessions available\n");
	return -EBUSY;
}

int vpu_join_session(struct vpu_client *client, int session_num)
{
	struct vpu_dev_core *core;
	struct vpu_dev_session *session;
	int ret = -ENODEV;

	if (!client || session_num < 0 || session_num >= VPU_NUM_SESSIONS) {
		pr_err("invalid session # %d\n", session_num);
		return -EINVAL;
	}

	core = client->core;
	session = core->sessions[session_num];

	mutex_lock(&session->lock);

	if (session->client_count == 0)
		pr_err("Session %d is not created yet\n", session_num);
	else
		ret = __vpu_attach_client(client, session);

	mutex_unlock(&session->lock);

	return ret;
}

int vpu_attach_session_deprecated(struct vpu_client *client, int session_num)
{
	struct vpu_dev_core *core;
	struct vpu_dev_session *session;
	int ret;

	if (!client || session_num < 0 || session_num >= VPU_NUM_SESSIONS) {
		pr_err("invalid session # %d\n", session_num);
		return -EINVAL;
	}

	core = client->core;
	session = core->sessions[session_num];

	mutex_lock(&session->lock);
	ret = __vpu_attach_client(client, session);
	mutex_unlock(&session->lock);

	return ret;
}

@@ -420,10 +522,19 @@ void vpu_detach_client(struct vpu_client *client)
		session->streaming_state = 0;
		session->commit_state = 0;
		session->dual_output = false;

		notify_vpu_event_system(client->core,
				VPU_EVENT_SESSION_FREED,
				(u8 *)&session->id, sizeof(session->id));
	}

	list_del_init(&client->clients_entry); /* remove from attached list */
	client->session = NULL;

	/* notify remaining session clients of the new client count */
	notify_vpu_event_session(session, VPU_EVENT_SESSION_CLIENT_EXITED,
		(u8 *)&session->client_count, sizeof(session->client_count));

	mutex_unlock(&session->lock);

	/* add back to global unattached list */
+5 −14
Original line number Diff line number Diff line
@@ -32,7 +32,11 @@ static inline int get_vpu_num_sessions(unsigned *ret)
	return 0;
}

int vpu_attach_client(struct vpu_client *client, int session_num);
int vpu_create_session(struct vpu_client *client);
int vpu_join_session(struct vpu_client *client, int session_num);

int vpu_attach_session_deprecated(struct vpu_client *client, int session_num);

void vpu_detach_client(struct vpu_client *client);


@@ -81,19 +85,6 @@ int vpu_streamoff(struct vpu_client *client, enum v4l2_buf_type i);

int vpu_trigger_stream(struct vpu_dev_session *session);

/*
 * Notify client with event of ID type.
 * If data is not null then it points to payload of size (<=64)
 */
void notify_vpu_event_client(struct vpu_client *client,
		u32 type, u8 *data, u32 size);

/*
 * Notify All clients in session with event of ID type.
 * If data is not null then it points to payload of size (<=64)
 */
void notify_vpu_event_session(struct vpu_dev_session *session,
		u32 type, u8 *data, u32 size);

/*
 * Videobuf2 related functions
+18 −3
Original line number Diff line number Diff line
@@ -128,13 +128,28 @@ static long v4l2_vpu_private_ioctls(struct file *file, void *fh,
	switch (cmd) {
	case VPU_QUERY_SESSIONS:
		pr_debug("Received ioctl VPU_QUERY_SESSIONS\n");
		ret = get_vpu_num_sessions((unsigned *)arg);
		ret = get_vpu_num_sessions((int *)arg);
		break;

	case VPU_ATTACH_TO_SESSION:
		pr_debug("Received ioctl VPU_ATTACH_TO_SESSION\n");
		session_num = *((unsigned *)arg);
		ret = vpu_attach_client(client, session_num);
		session_num = *((int *)arg);
		ret = vpu_attach_session_deprecated(client, session_num);
		break;

	case VPU_CREATE_SESSION:
		pr_debug("Received ioctl VPU_CREATE_SESSION\n");
		session_num = vpu_create_session(client);
		if (session_num < 0)
			ret = session_num;
		else
			*((int *)arg) = session_num;
		break;

	case VPU_JOIN_SESSION:
		pr_debug("Received ioctl VPU_JOIN_SESSION\n");
		session_num = *((int *)arg);
		ret = vpu_join_session(client, session_num);
		break;

	case VPU_CREATE_OUTPUT2:
+16 −1
Original line number Diff line number Diff line
@@ -150,6 +150,15 @@ struct v4l2_format_vpu_extension {
 * VPU_EVENT_SESSION_TIMESTAMP: New Session timestamp
 * payload data: vpu_frame_timestamp_info
 *
 * VPU_EVENT_SESSION_CREATED: New session has been created
 * payload data: int (number of the attached session)
 *
 * VPU_EVENT_SESSION_FREED: Session is detached and free
 * payload data: int (number of the detached session)
 *
 * VPU_EVENT_SESSION_CLIENT_EXITED: Indicates that clients of current
 *	session have exited.
 * payload data: int (number of all remaining clients for this session)
 *
 * VPU_EVENT_HW_ERROR: a hardware error occurred in VPU
 * payload data: NULL
@@ -167,6 +176,9 @@ enum VPU_PRIVATE_EVENT {
	VPU_EVENT_FLUSH_DONE = VPU_EVENT_START + 1,
	VPU_EVENT_ACTIVE_REGION_CHANGED = VPU_EVENT_START + 2,
	VPU_EVENT_SESSION_TIMESTAMP = VPU_EVENT_START + 3,
	VPU_EVENT_SESSION_CREATED = VPU_EVENT_START + 4,
	VPU_EVENT_SESSION_FREED = VPU_EVENT_START + 5,
	VPU_EVENT_SESSION_CLIENT_EXITED = VPU_EVENT_START + 6,

	VPU_EVENT_HW_ERROR = VPU_EVENT_START + 11,
	VPU_EVENT_INVALID_CONFIG = VPU_EVENT_START + 12,
@@ -423,10 +435,13 @@ struct vpu_control_port {
 * V P U   D E V I C E   P R I V A T E   I O C T L   C O D E S
 */

/* VPU Session ioctls (deprecated) */
#define VPU_ATTACH_TO_SESSION	_IOW('V', (BASE_VIDIOC_PRIVATE + 1), int)

/* VPU Session ioctls */
#define VPU_QUERY_SESSIONS	_IOR('V', (BASE_VIDIOC_PRIVATE + 0), int)
#define VPU_ATTACH_TO_SESSION	_IOW('V', (BASE_VIDIOC_PRIVATE + 1), int)
#define VPU_CREATE_SESSION	_IOR('V', (BASE_VIDIOC_PRIVATE + 2), int)
#define VPU_JOIN_SESSION	_IOW('V', (BASE_VIDIOC_PRIVATE + 3), int)

/* Enable second VPU output port and use with current client */
#define VPU_CREATE_OUTPUT2	_IO('V', (BASE_VIDIOC_PRIVATE + 5))