summaryrefslogblamecommitdiffstats
path: root/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/bufq/src/bufq.c
blob: 42d9a85088585092ab64b0b09aed0340f05acc7c (plain) (tree)
















































































































































































































































                                                                                                                    
                                 







































                                                                         
                  








                                        
                                                




















































































































































                                                                                                               
                        















                                                                      
                                           






                                                
                        














                                                                      
                                           









































































































                                                                                
/*
 * Support for Intel Camera Imaging ISP subsystem.
 * Copyright (c) 2015, Intel Corporation.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms and conditions of the GNU General Public License,
 * version 2, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope 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 "assert_support.h"		/* assert */
#include "ia_css_buffer.h"
#include "sp.h"
#include "ia_css_bufq.h"		/* Bufq API's */
#include "ia_css_queue.h"		/* ia_css_queue_t */
#include "sw_event_global.h"		/* Event IDs.*/
#include "ia_css_eventq.h"		/* ia_css_eventq_recv()*/
#include "ia_css_debug.h"		/* ia_css_debug_dtrace*/
#include "sh_css_internal.h"		/* sh_css_queue_type */
#include "sp_local.h"			/* sp_address_of */
#include "ia_css_util.h"		/* ia_css_convert_errno()*/
#include "sh_css_firmware.h"		/* sh_css_sp_fw*/

#define BUFQ_DUMP_FILE_NAME_PREFIX_SIZE 256

static char prefix[BUFQ_DUMP_FILE_NAME_PREFIX_SIZE] = {0};

/*********************************************************/
/* Global Queue objects used by CSS                      */
/*********************************************************/

#ifndef ISP2401

struct sh_css_queues {
	/* Host2SP buffer queue */
	ia_css_queue_t host2sp_buffer_queue_handles
		[SH_CSS_MAX_SP_THREADS][SH_CSS_MAX_NUM_QUEUES];
	/* SP2Host buffer queue */
	ia_css_queue_t sp2host_buffer_queue_handles
		[SH_CSS_MAX_NUM_QUEUES];

	/* Host2SP event queue */
	ia_css_queue_t host2sp_psys_event_queue_handle;

	/* SP2Host event queue */
	ia_css_queue_t sp2host_psys_event_queue_handle;

#if !defined(HAS_NO_INPUT_SYSTEM)
	/* Host2SP ISYS event queue */
	ia_css_queue_t host2sp_isys_event_queue_handle;

	/* SP2Host ISYS event queue */
	ia_css_queue_t sp2host_isys_event_queue_handle;
#endif
	/* Tagger command queue */
	ia_css_queue_t host2sp_tag_cmd_queue_handle;
};

#else

struct sh_css_queues {
	/* Host2SP buffer queue */
	ia_css_queue_t host2sp_buffer_queue_handles
		[SH_CSS_MAX_SP_THREADS][SH_CSS_MAX_NUM_QUEUES];
	/* SP2Host buffer queue */
	ia_css_queue_t sp2host_buffer_queue_handles
		[SH_CSS_MAX_NUM_QUEUES];

	/* Host2SP event queue */
	ia_css_queue_t host2sp_psys_event_queue_handle;

	/* SP2Host event queue */
	ia_css_queue_t sp2host_psys_event_queue_handle;

#if !defined(HAS_NO_INPUT_SYSTEM)
	/* Host2SP ISYS event queue */
	ia_css_queue_t host2sp_isys_event_queue_handle;

	/* SP2Host ISYS event queue */
	ia_css_queue_t sp2host_isys_event_queue_handle;

	/* Tagger command queue */
	ia_css_queue_t host2sp_tag_cmd_queue_handle;
#endif
};

#endif

struct sh_css_queues  css_queues;


/*******************************************************
*** Static variables
********************************************************/
static int buffer_type_to_queue_id_map[SH_CSS_MAX_SP_THREADS][IA_CSS_NUM_DYNAMIC_BUFFER_TYPE];
static bool queue_availability[SH_CSS_MAX_SP_THREADS][SH_CSS_MAX_NUM_QUEUES];

/*******************************************************
*** Static functions
********************************************************/
static void map_buffer_type_to_queue_id(
	unsigned int thread_id,
	enum ia_css_buffer_type buf_type
	);
static void unmap_buffer_type_to_queue_id(
	unsigned int thread_id,
	enum ia_css_buffer_type buf_type
	);

static ia_css_queue_t *bufq_get_qhandle(
	enum sh_css_queue_type type,
	enum sh_css_queue_id id,
	int thread
	);

/*******************************************************
*** Public functions
********************************************************/
void ia_css_queue_map_init(void)
{
	unsigned int i, j;

	for (i = 0; i < SH_CSS_MAX_SP_THREADS; i++) {
		for (j = 0; j < SH_CSS_MAX_NUM_QUEUES; j++)
			queue_availability[i][j] = true;
	}

	for (i = 0; i < SH_CSS_MAX_SP_THREADS; i++) {
		for (j = 0; j < IA_CSS_NUM_DYNAMIC_BUFFER_TYPE; j++)
			buffer_type_to_queue_id_map[i][j] = SH_CSS_INVALID_QUEUE_ID;
	}
}

void ia_css_queue_map(
	unsigned int thread_id,
	enum ia_css_buffer_type buf_type,
	bool map)
{
	assert(buf_type < IA_CSS_NUM_DYNAMIC_BUFFER_TYPE);
	assert(thread_id < SH_CSS_MAX_SP_THREADS);

	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
		"ia_css_queue_map() enter: buf_type=%d, thread_id=%d\n", buf_type, thread_id);

	if (map)
		map_buffer_type_to_queue_id(thread_id, buf_type);
	else
		unmap_buffer_type_to_queue_id(thread_id, buf_type);
}

/**
 * @brief Query the internal queue ID.
 */
bool ia_css_query_internal_queue_id(
	enum ia_css_buffer_type buf_type,
	unsigned int thread_id,
	enum sh_css_queue_id *val)
{
	IA_CSS_ENTER("buf_type=%d, thread_id=%d, val = %p", buf_type, thread_id, val);

	if ((val == NULL) || (thread_id >= SH_CSS_MAX_SP_THREADS) || (buf_type >= IA_CSS_NUM_DYNAMIC_BUFFER_TYPE)) {
		IA_CSS_LEAVE("return_val = false");
		return false;
	}

	*val = buffer_type_to_queue_id_map[thread_id][buf_type];
	if ((*val == SH_CSS_INVALID_QUEUE_ID) || (*val >= SH_CSS_MAX_NUM_QUEUES)) {
		IA_CSS_LOG("INVALID queue ID MAP = %d\n", *val);
		IA_CSS_LEAVE("return_val = false");
		return false;
	}
	IA_CSS_LEAVE("return_val = true");
	return true;
}

/*******************************************************
*** Static functions
********************************************************/
static void map_buffer_type_to_queue_id(
	unsigned int thread_id,
	enum ia_css_buffer_type buf_type)
{
	unsigned int i;

	assert(thread_id < SH_CSS_MAX_SP_THREADS);
	assert(buf_type < IA_CSS_NUM_DYNAMIC_BUFFER_TYPE);
	assert(buffer_type_to_queue_id_map[thread_id][buf_type] == SH_CSS_INVALID_QUEUE_ID);

	/* queue 0 is reserved for parameters because it doesn't depend on events */
	if (buf_type == IA_CSS_BUFFER_TYPE_PARAMETER_SET) {
		assert(queue_availability[thread_id][IA_CSS_PARAMETER_SET_QUEUE_ID]);
		queue_availability[thread_id][IA_CSS_PARAMETER_SET_QUEUE_ID] = false;
		buffer_type_to_queue_id_map[thread_id][buf_type] = IA_CSS_PARAMETER_SET_QUEUE_ID;
		return;
	}

	/* queue 1 is reserved for per frame parameters because it doesn't depend on events */
	if (buf_type == IA_CSS_BUFFER_TYPE_PER_FRAME_PARAMETER_SET) {
		assert(queue_availability[thread_id][IA_CSS_PER_FRAME_PARAMETER_SET_QUEUE_ID]);
		queue_availability[thread_id][IA_CSS_PER_FRAME_PARAMETER_SET_QUEUE_ID] = false;
		buffer_type_to_queue_id_map[thread_id][buf_type] = IA_CSS_PER_FRAME_PARAMETER_SET_QUEUE_ID;
		return;
	}

	for (i = SH_CSS_QUEUE_C_ID; i < SH_CSS_MAX_NUM_QUEUES; i++) {
		if (queue_availability[thread_id][i] == true) {
			queue_availability[thread_id][i] = false;
			buffer_type_to_queue_id_map[thread_id][buf_type] = i;
			break;
		}
	}

	assert(i != SH_CSS_MAX_NUM_QUEUES);
	return;
}

static void unmap_buffer_type_to_queue_id(
	unsigned int thread_id,
	enum ia_css_buffer_type buf_type)
{
	int queue_id;

	assert(thread_id < SH_CSS_MAX_SP_THREADS);
	assert(buf_type < IA_CSS_NUM_DYNAMIC_BUFFER_TYPE);
	assert(buffer_type_to_queue_id_map[thread_id][buf_type] != SH_CSS_INVALID_QUEUE_ID);

	queue_id = buffer_type_to_queue_id_map[thread_id][buf_type];
	buffer_type_to_queue_id_map[thread_id][buf_type] = SH_CSS_INVALID_QUEUE_ID;
	queue_availability[thread_id][queue_id] = true;
}


static ia_css_queue_t *bufq_get_qhandle(
	enum sh_css_queue_type type,
	enum sh_css_queue_id id,
	int thread)
{
	ia_css_queue_t *q = NULL;

	switch (type) {
	case sh_css_host2sp_buffer_queue:
		if ((thread >= SH_CSS_MAX_SP_THREADS) || (thread < 0) ||
			(id == SH_CSS_INVALID_QUEUE_ID))
			break;
		q = &css_queues.host2sp_buffer_queue_handles[thread][id];
		break;
	case sh_css_sp2host_buffer_queue:
		if (id == SH_CSS_INVALID_QUEUE_ID)
			break;
		q = &css_queues.sp2host_buffer_queue_handles[id];
		break;
	case sh_css_host2sp_psys_event_queue:
		q = &css_queues.host2sp_psys_event_queue_handle;
		break;
	case sh_css_sp2host_psys_event_queue:
		q = &css_queues.sp2host_psys_event_queue_handle;
		break;
#if !defined(HAS_NO_INPUT_SYSTEM)
	case sh_css_host2sp_isys_event_queue:
		q = &css_queues.host2sp_isys_event_queue_handle;
		break;
	case sh_css_sp2host_isys_event_queue:
		q = &css_queues.sp2host_isys_event_queue_handle;
		break;
#endif		
	case sh_css_host2sp_tag_cmd_queue:
		q = &css_queues.host2sp_tag_cmd_queue_handle;
		break;
	default:
		break;
	}

	return q;
}

/* Local function to initialize a buffer queue. This reduces
 * the chances of copy-paste errors or typos.
 */
static inline void
init_bufq(unsigned int desc_offset,
	  unsigned int elems_offset,
	  ia_css_queue_t *handle)
{
	const struct ia_css_fw_info *fw;
	unsigned int q_base_addr;
	ia_css_queue_remote_t remoteq;

	fw = &sh_css_sp_fw;
	q_base_addr = fw->info.sp.host_sp_queue;

	/* Setup queue location as SP and proc id as SP0_ID */
	remoteq.location = IA_CSS_QUEUE_LOC_SP;
	remoteq.proc_id = SP0_ID;
	remoteq.cb_desc_addr = q_base_addr + desc_offset;
	remoteq.cb_elems_addr = q_base_addr + elems_offset;
	/* Initialize the queue instance and obtain handle */
	ia_css_queue_remote_init(handle, &remoteq);
}

void ia_css_bufq_init(void)
{
	int i, j;

	IA_CSS_ENTER_PRIVATE("");

	/* Setup all the local queue descriptors for Host2SP Buffer Queues */
	for (i = 0; i < SH_CSS_MAX_SP_THREADS; i++)
		for (j = 0; j < SH_CSS_MAX_NUM_QUEUES; j++) {
			init_bufq((uint32_t)offsetof(struct host_sp_queues, host2sp_buffer_queues_desc[i][j]),
				  (uint32_t)offsetof(struct host_sp_queues, host2sp_buffer_queues_elems[i][j]),
				  &css_queues.host2sp_buffer_queue_handles[i][j]);
		}

	/* Setup all the local queue descriptors for SP2Host Buffer Queues */
	for (i = 0; i < SH_CSS_MAX_NUM_QUEUES; i++) {
		init_bufq(offsetof(struct host_sp_queues, sp2host_buffer_queues_desc[i]),
			  offsetof(struct host_sp_queues, sp2host_buffer_queues_elems[i]),
			  &css_queues.sp2host_buffer_queue_handles[i]);
	}

	/* Host2SP event queue*/
	init_bufq((uint32_t)offsetof(struct host_sp_queues, host2sp_psys_event_queue_desc),
		  (uint32_t)offsetof(struct host_sp_queues, host2sp_psys_event_queue_elems),
		  &css_queues.host2sp_psys_event_queue_handle);

	/* SP2Host event queue */
	init_bufq((uint32_t)offsetof(struct host_sp_queues, sp2host_psys_event_queue_desc),
		  (uint32_t)offsetof(struct host_sp_queues, sp2host_psys_event_queue_elems),
		  &css_queues.sp2host_psys_event_queue_handle);

#if !defined(HAS_NO_INPUT_SYSTEM)
	/* Host2SP ISYS event queue */
	init_bufq((uint32_t)offsetof(struct host_sp_queues, host2sp_isys_event_queue_desc),
		  (uint32_t)offsetof(struct host_sp_queues, host2sp_isys_event_queue_elems),
		  &css_queues.host2sp_isys_event_queue_handle);

	/* SP2Host ISYS event queue*/
	init_bufq((uint32_t)offsetof(struct host_sp_queues, sp2host_isys_event_queue_desc),
		  (uint32_t)offsetof(struct host_sp_queues, sp2host_isys_event_queue_elems),
		  &css_queues.sp2host_isys_event_queue_handle);

	/* Host2SP tagger command queue */
	init_bufq((uint32_t)offsetof(struct host_sp_queues, host2sp_tag_cmd_queue_desc),
		  (uint32_t)offsetof(struct host_sp_queues, host2sp_tag_cmd_queue_elems),
		  &css_queues.host2sp_tag_cmd_queue_handle);
#endif

	IA_CSS_LEAVE_PRIVATE("");
}

enum ia_css_err ia_css_bufq_enqueue_buffer(
	int thread_index,
	int queue_id,
	uint32_t item)
{
	enum ia_css_err return_err = IA_CSS_SUCCESS;
	ia_css_queue_t *q;
	int error;

	IA_CSS_ENTER_PRIVATE("queue_id=%d", queue_id);
	if ((thread_index >= SH_CSS_MAX_SP_THREADS) || (thread_index < 0) ||
			(queue_id == SH_CSS_INVALID_QUEUE_ID))
		return IA_CSS_ERR_INVALID_ARGUMENTS;

	/* Get the queue for communication */
	q = bufq_get_qhandle(sh_css_host2sp_buffer_queue,
		queue_id,
		thread_index);
	if (q != NULL) {
		error = ia_css_queue_enqueue(q, item);
		return_err = ia_css_convert_errno(error);
	} else {
		IA_CSS_ERROR("queue is not initialized");
		return_err = IA_CSS_ERR_RESOURCE_NOT_AVAILABLE;
	}

	IA_CSS_LEAVE_ERR_PRIVATE(return_err);
	return return_err;
}

enum ia_css_err ia_css_bufq_dequeue_buffer(
	int queue_id,
	uint32_t *item)
{
	enum ia_css_err return_err;
	int error = 0;
	ia_css_queue_t *q;

	IA_CSS_ENTER_PRIVATE("queue_id=%d", queue_id);
	if ((item == NULL) ||
	    (queue_id <= SH_CSS_INVALID_QUEUE_ID) ||
	    (queue_id >= SH_CSS_MAX_NUM_QUEUES)
	   )
		return IA_CSS_ERR_INVALID_ARGUMENTS;

	q = bufq_get_qhandle(sh_css_sp2host_buffer_queue,
		queue_id,
		-1);
	if (q != NULL) {
		error = ia_css_queue_dequeue(q, item);
		return_err = ia_css_convert_errno(error);
	} else {
		IA_CSS_ERROR("queue is not initialized");
		return_err = IA_CSS_ERR_RESOURCE_NOT_AVAILABLE;
	}

	IA_CSS_LEAVE_ERR_PRIVATE(return_err);
	return return_err;
}

enum ia_css_err ia_css_bufq_enqueue_psys_event(
	uint8_t evt_id,
	uint8_t evt_payload_0,
	uint8_t evt_payload_1,
	uint8_t evt_payload_2)
{
	enum ia_css_err return_err;
	int error = 0;
	ia_css_queue_t *q;

	IA_CSS_ENTER_PRIVATE("evt_id=%d", evt_id);
	q = bufq_get_qhandle(sh_css_host2sp_psys_event_queue, -1, -1);
	if (NULL == q) {
		IA_CSS_ERROR("queue is not initialized");
		return IA_CSS_ERR_RESOURCE_NOT_AVAILABLE;
	}

	error = ia_css_eventq_send(q,
			evt_id, evt_payload_0, evt_payload_1, evt_payload_2);

	return_err = ia_css_convert_errno(error);
	IA_CSS_LEAVE_ERR_PRIVATE(return_err);
	return return_err;
}

enum  ia_css_err ia_css_bufq_dequeue_psys_event(
	uint8_t item[BUFQ_EVENT_SIZE])
{
	enum ia_css_err;
	int error = 0;
	ia_css_queue_t *q;

	/* No ENTER/LEAVE in this function since this is polled
	 * by some test apps. Enablign logging here floods the log
	 * files which may cause timeouts. */
	if (item == NULL)
		return IA_CSS_ERR_INVALID_ARGUMENTS;

	q = bufq_get_qhandle(sh_css_sp2host_psys_event_queue, -1, -1);
	if (NULL == q) {
		IA_CSS_ERROR("queue is not initialized");
		return IA_CSS_ERR_RESOURCE_NOT_AVAILABLE;
	}
	error = ia_css_eventq_recv(q, item);

	return ia_css_convert_errno(error);

}

enum  ia_css_err ia_css_bufq_dequeue_isys_event(
	uint8_t item[BUFQ_EVENT_SIZE])
{
#if !defined(HAS_NO_INPUT_SYSTEM)
	enum ia_css_err;
	int error = 0;
	ia_css_queue_t *q;

	/* No ENTER/LEAVE in this function since this is polled
	 * by some test apps. Enablign logging here floods the log
	 * files which may cause timeouts. */
	if (item == NULL)
		return IA_CSS_ERR_INVALID_ARGUMENTS;

	q = bufq_get_qhandle(sh_css_sp2host_isys_event_queue, -1, -1);
	if (q == NULL) {
		IA_CSS_ERROR("queue is not initialized");
		return IA_CSS_ERR_RESOURCE_NOT_AVAILABLE;
	}
	error = ia_css_eventq_recv(q, item);
	return ia_css_convert_errno(error);
#else
	(void)item;
	return IA_CSS_ERR_RESOURCE_NOT_AVAILABLE;
#endif
}

enum ia_css_err ia_css_bufq_enqueue_isys_event(uint8_t evt_id)
{
#if !defined(HAS_NO_INPUT_SYSTEM)
	enum ia_css_err return_err;
	int error = 0;
	ia_css_queue_t *q;

	IA_CSS_ENTER_PRIVATE("event_id=%d", evt_id);
	q = bufq_get_qhandle(sh_css_host2sp_isys_event_queue, -1, -1);
	if (q == NULL) {
		IA_CSS_ERROR("queue is not initialized");
		return IA_CSS_ERR_RESOURCE_NOT_AVAILABLE;
	}

	error = ia_css_eventq_send(q, evt_id, 0, 0, 0);
	return_err = ia_css_convert_errno(error);
	IA_CSS_LEAVE_ERR_PRIVATE(return_err);
	return return_err;
#else
	(void)evt_id;
	return IA_CSS_ERR_RESOURCE_NOT_AVAILABLE;
#endif
}

enum ia_css_err ia_css_bufq_enqueue_tag_cmd(
	uint32_t item)
{
#if !defined(HAS_NO_INPUT_SYSTEM)
	enum ia_css_err return_err;
	int error = 0;
	ia_css_queue_t *q;

	IA_CSS_ENTER_PRIVATE("item=%d", item);
	q = bufq_get_qhandle(sh_css_host2sp_tag_cmd_queue, -1, -1);
	if (NULL == q) {
		IA_CSS_ERROR("queue is not initialized");
		return IA_CSS_ERR_RESOURCE_NOT_AVAILABLE;
	}
	error = ia_css_queue_enqueue(q, item);

	return_err = ia_css_convert_errno(error);
	IA_CSS_LEAVE_ERR_PRIVATE(return_err);
	return return_err;
#else
	(void)item;
	return IA_CSS_ERR_RESOURCE_NOT_AVAILABLE;
#endif
}

enum ia_css_err ia_css_bufq_deinit(void)
{
	return IA_CSS_SUCCESS;
}

static void bufq_dump_queue_info(const char *prefix, ia_css_queue_t *qhandle)
{
	uint32_t free = 0, used = 0;
	assert(prefix != NULL && qhandle != NULL);
	ia_css_queue_get_used_space(qhandle, &used);
	ia_css_queue_get_free_space(qhandle, &free);
	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "%s: used=%u free=%u\n",
		prefix, used, free);

}

void ia_css_bufq_dump_queue_info(void)
{
	int i, j;

	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "Queue Information:\n");

	for (i = 0; i < SH_CSS_MAX_SP_THREADS; i++) {
		for (j = 0; j < SH_CSS_MAX_NUM_QUEUES; j++) {
			snprintf(prefix, BUFQ_DUMP_FILE_NAME_PREFIX_SIZE,
				"host2sp_buffer_queue[%u][%u]", i, j);
			bufq_dump_queue_info(prefix,
				&css_queues.host2sp_buffer_queue_handles[i][j]);
		}
	}

	for (i = 0; i < SH_CSS_MAX_NUM_QUEUES; i++) {
		snprintf(prefix, BUFQ_DUMP_FILE_NAME_PREFIX_SIZE,
			"sp2host_buffer_queue[%u]", i);
		bufq_dump_queue_info(prefix,
			&css_queues.sp2host_buffer_queue_handles[i]);
	}
	bufq_dump_queue_info("host2sp_psys_event",
		&css_queues.host2sp_psys_event_queue_handle);
	bufq_dump_queue_info("sp2host_psys_event",
		&css_queues.sp2host_psys_event_queue_handle);

#if !defined(HAS_NO_INPUT_SYSTEM)
	bufq_dump_queue_info("host2sp_isys_event",
		&css_queues.host2sp_isys_event_queue_handle);
	bufq_dump_queue_info("sp2host_isys_event",
		&css_queues.sp2host_isys_event_queue_handle);
	bufq_dump_queue_info("host2sp_tag_cmd",
		&css_queues.host2sp_tag_cmd_queue_handle);
#endif
}