/*   SCE CONFIDENTIAL                                       */
/*   PLAYSTATION(R)3 Programmer Tool Runtime Library 084.006 */
/*   Copyright (C) 2006 Sony Computer Entertainment Inc.    */
/*   All Rights Reserved.                                   */

/** \ingroup all_syscall
 * \defgroup spu_thread SPU Threads
 * \brief system calls defined in sys/spu_thread.h
 *
 * Interfaces defined in sys/spu_thread.h.
 *
 * Refer to <i>Cell OS Lv-2 User's Manual</i> for the detailed description.
 */
/*@{*/
#ifndef __LV2_KERNEL_SPU_SYSCALL_SPU_THREAD_H__
#define __LV2_KERNEL_SPU_SYSCALL_SPU_THREAD_H__

#include <sys/cdefs.h>
#include <sys/syscall.h>

#include <sys/integertypes.h>
#include <sys/return_code.h>
#include <sys/types.h>

CDECL_BEGIN


#define SYS_SPU_THREAD_EVENT_USER 0x1
#define SYS_SPU_THREAD_EVENT_DMA  0x2
#define SYS_SPU_THREAD_EVENT_USER_KEY 0xFFFFFFFF53505501ULL
#define SYS_SPU_THREAD_EVENT_DMA_KEY  0xFFFFFFFF53505502ULL


#define SYS_SPU_THREAD_DMA_COMPLETION_STOP 0x0U
#define SYS_SPU_THREAD_DMA_COMPLETION_ANY  0x1U
#define SYS_SPU_THREAD_DMA_COMPLETION_ALL  0x2U


#define SYS_SPU_THREAD_ARGUMENT_LET_8(x) (((uint64_t)x) << 32U)
#define SYS_SPU_THREAD_ARGUMENT_LET_16(x) (((uint64_t)x) << 32U)
#define SYS_SPU_THREAD_ARGUMENT_LET_32(x) (((uint64_t)x) << 32U)
#define SYS_SPU_THREAD_ARGUMENT_LET_64(x) (x)


/** \brief SPU thread argument structure
 * 
 * The sys_spu_thread_argument_t structure type is used to pass arguments 
 * to an SPU thread by sys_spu_thread_initialize().
 *
 * \see sys_spu_thread_initialize
 */
typedef struct sys_spu_thread_argument {
	__CSTD uint64_t arg1;
						/**< arg1 (loaded to SPU GPR3) */
	__CSTD uint64_t arg2;
						/**< arg2 (loaded to SPU GPR4) */
	__CSTD uint64_t arg3;
						/**< arg3 (loaded to SPU GPR5) */
	__CSTD uint64_t arg4;
						/**< arg4 (loaded to SPU GPR6) */
} sys_spu_thread_argument_t;

#define SYS_SPU_SEGMENT_TYPE_COPY  0x0001
#define SYS_SPU_SEGMENT_TYPE_FILL  0x0002
#define SYS_SPU_SEGMENT_TYPE_INFO  0x0004

/** \brief SPU segment structure
 *
 * The sys_spu_segment_t structure type describes an SPU segment.
 * The initial image to be loaded to an SPU is represented by an array 
 * of this structure type.
 *
 * \a type must be one of the following values.
 * - SYS_SPU_SEGMENT_TYPE_COPY \n
 *   The segment type is COPY.  A segment of this type copies a specified 
 *   area in the process address space to the local storage.
 * - SYS_SPU_SEGMENT_TYPE_FILL \n
 *   The segment type is FILL.  A segment of this type fills a specified 
 *   area in the local storage with an arbitrary 32-bit values.
 * - SYS_SPU_SEGMENT_TYPE_INFO \n
 *   The segment type is INFO.  The detail specification is TBD.
 *
 * \a size represents the size of this SPU segment, and its valid range is 
 * from 128 byte to 16 KB.
 *
 * \a src is a union type, and its meaning differs with the SPU segment type.
 * \a pa_start is used if \a type is SYS_SPU_SEGMENT_TYPE_COPY, and 
 * represents the top effective address of an area in the process address 
 * space that is copied to the SPU segment.  \a pa_start must be aligned to
 * 128 bytes.
 * \a value is used if \a type is 
 * SYS_SEGMENT_TYPE_FILL, and represents the 32-bit value to be filled in 
 * the SPU segment.
 * 
 * \see sys_spu_thread_initialize, sys_spu_thread_attribute_t
 */
struct sys_spu_segment {
  /** SPU segment type (COPY/FILL/INFO) */
	int type;
  /** Top LS address on which this SPU segment will be loaded */
	__CSTD uint32_t ls_start;
  /** Size of this SPU segment in bytes */
	int size;
	union {
	/** Top effective address which an SPU segment of COPY type will copy from */
		sys_addr_t pa_start;
	/** The value to be filled in an SPU segment of FILL type */
		__CSTD uint32_t value;
		uint64_t pad;
	} src;
};
typedef struct sys_spu_segment sys_spu_segment_t;


#define SYS_SPU_THREAD_OPTION_NONE                 0x00000000U
#define SYS_SPU_THREAD_OPTION_ASYNC_INTR_ENABLE    0x00000001U
#define SYS_SPU_THREAD_OPTION_DEC_SYNC_TB_ENABLE   0x00000002U

/** \brief SPU thread attribute sturcture
 *
 * The sys_spu_thread_attribute_t structure type is used to set 
 * attributes to an SPU thread by sys_spu_thread_initialize().
 *
 * \see sys_spu_thread_initialize, sys_spu_thread_segment_t
 */
struct sys_spu_thread_attribute {
  /** A string of the name for this SPU thread */
	const char *name;
  /** The length of \a name including the null terminator */
	__CSTD size_t nsize;
  /** SPU thread options (NONE/SYNC_INTR_ENABLE/DEC_SYNC_TB_ENABLE) */
	__CSTD uint32_t option;
};
typedef struct sys_spu_thread_attribute sys_spu_thread_attribute_t;


#define SYS_SPU_IMAGE_TYPE_USER     0x0U
#define SYS_SPU_IMAGE_TYPE_KERNEL   0x1U

struct sys_spu_image {
	uint32_t type;
	uint32_t entry_point;
	sys_spu_segment_t *segs;
	int nsegs;
};
typedef struct sys_spu_image sys_spu_image_t;


/* Basic operations */
static inline int sys_spu_thread_initialize(sys_spu_thread_t * thread,
											sys_spu_thread_group_t group,
											unsigned int spu_num,
											sys_spu_image_t * img,
											sys_spu_thread_attribute_t * attr,
											sys_spu_thread_argument_t * arg)
{
	system_call(6, SYS_SPU_THREAD_INITIALIZE, (uint32_t) thread, group, spu_num,
				(uint32_t) img, (uint32_t) attr, (uint32_t) arg);

#ifdef REG_PASS_SYS_SPU_THREAD_INITIALIZE
	REG_PASS_SYS_SPU_THREAD_INITIALIZE;
#endif
	return_to_user_prog(int);
}


static inline int sys_spu_thread_set_argument(sys_spu_thread_t id,
											  sys_spu_thread_argument_t * arg)
{
	system_call(2, SYS_SPU_THREAD_SET_ARGUMENT, id, (uint32_t) arg);

#ifdef REG_PASS_SYS_SPU_THREAD_SET_ARGUMENT
	REG_PASS_SYS_SPU_THREAD_SET_ARGUMENT;
#endif
	return_to_user_prog(int);
}


static inline int sys_spu_thread_get_exit_status(sys_spu_thread_t id,
												 int *status)
{
	system_call(2, SYS_SPU_THREAD_GET_EXIT_STATUS, id, (uint32_t) status);

#ifdef REG_PASS_SYS_SPU_THREAD_GET_EXIT_STATUS
	REG_PASS_SYS_SPU_THREAD_GET_EXIT_STATUS;
#endif
	return_to_user_prog(int);
}


static inline int sys_spu_thread_connect_event(sys_spu_thread_t id,
											   sys_event_queue_t eq,
											   sys_event_type_t et,
											   __CSTD uint8_t spup)
{
	system_call(4, SYS_SPU_THREAD_CONNECT_EVENT, id, eq, et, spup);

#ifdef REG_PASS_SYS_SPU_THREAD_CONNECT_EVENT
	REG_PASS_SYS_SPU_THREAD_CONNECT_EVENT;
#endif
	return_to_user_prog(int);
}


static inline int sys_spu_thread_disconnect_event(sys_spu_thread_t id,
												  sys_event_type_t et,
												  __CSTD uint8_t spup)
{
	system_call(3, SYS_SPU_THREAD_DISCONNECT_EVENT, id, et, spup);

#ifdef REG_PASS_SYS_SPU_THREAD_DISCONNECT_EVENT
	REG_PASS_SYS_SPU_THREAD_DISCONNECT_EVENT;
#endif
	return_to_user_prog(int);
}


static inline int sys_spu_thread_bind_queue(sys_spu_thread_t id,
											sys_event_queue_t spuq,
											__CSTD uint32_t spuq_num)
{
	system_call(3, SYS_SPU_THREAD_BIND_QUEUE, id, spuq, spuq_num);

#ifdef REG_PASS_SYS_SPU_THREAD_BIND_QUEUE
	REG_PASS_SYS_SPU_THREAD_BIND_QUEUE;
#endif
	return_to_user_prog(int);
}


static inline int sys_spu_thread_unbind_queue(sys_spu_thread_t id,
											  __CSTD uint32_t spuq_num)
{
	system_call(2, SYS_SPU_THREAD_UNBIND_QUEUE, id, spuq_num);

#ifdef REG_PASS_SYS_SPU_THREAD_UNBIND_QUEUE
	REG_PASS_SYS_SPU_THREAD_UNBIND_QUEUE;
#endif
	return_to_user_prog(int);
}



/* Context operations */
static inline int sys_spu_thread_write_ls(sys_spu_thread_t id,
										  __CSTD uint32_t address,
										  __CSTD uint64_t value,
										  __CSTD size_t type)
{
	system_call(4, SYS_SPU_THREAD_WRITE_LS, id, address, value, type);

#ifdef REG_PASS_SYS_SPU_THREAD_WRITE_LS
	REG_PASS_SYS_SPU_THREAD_WRITE_LS;
#endif
	return_to_user_prog(int);
}

static inline int sys_spu_thread_read_ls(sys_spu_thread_t id,
										 __CSTD uint32_t address,
										 __CSTD uint64_t * value,
										 __CSTD size_t type)
{
	system_call(4, SYS_SPU_THREAD_READ_LS, id, address, (uint32_t) value, type);

#ifdef REG_PASS_SYS_SPU_THREAD_READ_LS
	REG_PASS_SYS_SPU_THREAD_READ_LS;
#endif
	return_to_user_prog(int);
}


static inline int sys_spu_thread_write_snr(sys_spu_thread_t id, int number,
										   __CSTD uint32_t value)
{
	system_call(3, SYS_SPU_THREAD_WRITE_SNR, id, number, value);

#ifdef REG_PASS_SYS_SPU_THREAD_WRITE_SNR
	REG_PASS_SYS_SPU_THREAD_WRITE_SNR;
#endif
	return_to_user_prog(int);
}



static inline int sys_spu_thread_set_spu_cfg(sys_spu_thread_t id,
											 __CSTD uint64_t value)
{
	system_call(2, SYS_SPU_THREAD_SET_SPU_CFG, id, value);

#ifdef REG_PASS_SYS_SPU_THREAD_SET_SPU_CFG
	REG_PASS_SYS_SPU_THREAD_SET_SPU_CFG;
#endif
	return_to_user_prog(int);
}


static inline int sys_spu_thread_get_spu_cfg(sys_spu_thread_t id,
											 __CSTD uint64_t * value)
{
	system_call(2, SYS_SPU_THREAD_GET_SPU_CFG, id, (uint32_t) value);

#ifdef REG_PASS_SYS_SPU_THREAD_GET_SPU_CFG
	REG_PASS_SYS_SPU_THREAD_GET_SPU_CFG;
#endif
	return_to_user_prog(int);
}


static inline int sys_spu_thread_write_spu_mb(sys_spu_thread_t id,
											  __CSTD uint32_t value)
{
	system_call(2, SYS_SPU_THREAD_WRITE_SPU_MB, id, value);

#ifdef REG_PASS_SYS_SPU_THREAD_WRITE_SPU_MB
	REG_PASS_SYS_SPU_THREAD_WRITE_SPU_MB;
#endif
	return_to_user_prog(int);
}



/* For compatible with SDK050 */
static int sys_spu_thread_write_to_ls(sys_spu_thread_t id,
									  __CSTD uint32_t address,
									  __CSTD uint64_t value, __CSTD size_t type)
	__attribute__ ((deprecated));

static int sys_spu_thread_read_from_ls(sys_spu_thread_t id,
									   __CSTD uint32_t address,
									   __CSTD uint64_t * value,
									   __CSTD size_t type)
	__attribute__ ((deprecated));

static int sys_spu_thread_write_signal(sys_spu_thread_t id,
									   int number, __CSTD uint32_t value)
	__attribute__ ((deprecated));


static inline int sys_spu_thread_write_to_ls(sys_spu_thread_t id,
											 __CSTD uint32_t address,
											 __CSTD uint64_t value,
											 __CSTD size_t type)
{
	return sys_spu_thread_write_ls(id, address, value, type);
}

static inline int sys_spu_thread_read_from_ls(sys_spu_thread_t id,
											  __CSTD uint32_t address,
											  __CSTD uint64_t * value,
											  __CSTD size_t type)
{
	return sys_spu_thread_read_ls(id, address, value, type);
}

static inline int sys_spu_thread_write_signal(sys_spu_thread_t id,
											  int number, __CSTD uint32_t value)
{
	return sys_spu_thread_write_snr(id, number, value);
}




CDECL_END

#endif /* __LV2_KERNEL_SPU_SYSCALL_SPU_THREAD_H__ */
/*@}*/
