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

/*
 * $Date: $
 * $Revision: $
 */

/**
 * \ingroup all_syscall
 * \defgroup intr PPU Interrupts
 * \brief system calls defined in sys/interrupt.h
 *
 * Interfaces defined in sys/interrupt.h
 *
 * Refer to <i>Cell OS Lv-2 User's Manual</i> for the detailed description.
 */
/*@{*/

#ifndef __LV2_KERNEL_MACHINE_SYSCALL_INTERRUPT_H__
#define __LV2_KERNEL_MACHINE_SYSCALL_INTERRUPT_H__

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

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

CDECL_BEGIN



typedef __CSTD uint64_t sys_irqoutlet_id_t;

/* \brief H/W thread id */
typedef __CSTD uint32_t sys_hw_thread_t;
#define SYS_HW_THREAD_ANY		0xfffffffeU
#define SYS_HW_THREAD_INVALID	0xffffffffU

/** \brief interrupt thread handle (opaque value for users) */
typedef __CSTD uint32_t sys_interrupt_thread_handle_t;

/** \brief interrupt handler handle (opaque value for users) */
typedef __CSTD uint32_t sys_interrupt_handler_handle_t;

typedef void (*__ppu_intr_handler_entry) (__CSTD uint64_t, __CSTD uint64_t);

/*
 * intr_thread_t will be appeared in pu_thread.h.
 */

/* create interrupt tag */
static inline int sys_interrupt_tag_create(sys_interrupt_tag_t * intrtag,
										   sys_irqoutlet_id_t irq,
										   sys_hw_thread_t hwthread)
{
	system_call(3, SYS_INTERRUPT_TAG_CREATE, (uint32_t) intrtag, irq, hwthread);

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


static inline int sys_interrupt_tag_destroy(sys_interrupt_tag_t intrtag)
{
	system_call(1, SYS_INTERRUPT_TAG_DESTROY, intrtag);

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



static inline int _sys_interrupt_thread_establish(sys_interrupt_thread_handle_t
												  * ih,
												  sys_interrupt_tag_t intrtag,
												  __CSTD uint64_t intrthread,
												  __CSTD uint64_t arg1,
												  __CSTD uint64_t arg2)
{
	system_call(5, _SYS_INTERRUPT_THREAD_ESTABLISH, (uint32_t) ih, intrtag,
				intrthread, arg1, arg2);

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


/**
 * \brief establish an interrupt tag on an interrupt thread
 *
 * The sys_interrupt_thread_establish() system call establishes an interrupt thread 
 * \a threadid with the given interrupt tag \a intrtagid and the argument
 * \a arg, and stores the created interrupt service handler to the location 
 * pointed by \a ith_addr. 
 *
 *  
 *
 * \param ih	(OUT) Pointer to the storage for the interrupt thread handle.
 * \param intrtag	  The interrupt tag ID
 * \param intrthread  The interrupt thread iD
 * \param arg	The argument for the interrupt thread
 * \retval CELL_OK	Success
 * \retval ESRCH    Invalid interrupt tag ID
 * \retval EAGAIN	Error due to kernel resource limitation
 * \retval EFAULT	\a ih is not valid addr
 * \retval ESTAT	The assigned interrupt thread has already been established
 *                  on the same interrupt tag.
 */
static inline int sys_interrupt_thread_establish(sys_interrupt_thread_handle_t *
												 ih,
												 sys_interrupt_tag_t intrtag,
												 sys_ppu_thread_t intrthread,
												 __CSTD uint64_t arg)
{
	return _sys_interrupt_thread_establish(ih, intrtag, intrthread, arg, 0);
}


static inline void sys_interrupt_thread_eoi(void)
{
	system_call(0, SYS_INTERRUPT_THREAD_EOI);

#ifdef REG_PASS_SYS_INTERRUPT_THREAD_EOI
	REG_PASS_SYS_INTERRUPT_THREAD_EOI;
#endif
	return_to_user_prog(void);
}


extern int sys_interrupt_thread_disestablish(sys_interrupt_thread_handle_t ih);

static inline int
_sys_interrupt_thread_disestablish(sys_interrupt_thread_handle_t ih,
								   uint64_t * tls_mem)
{
	system_call(2, _SYS_INTERRUPT_THREAD_DISESTABLISH, ih, (uint32_t) tls_mem);

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



#define SYS_INTERRUPT_HANDLER_STACKSIZE_DEFAULT	4096

/*@}*/


/* establish an interrupt thread to an interrupt tag */

CDECL_END

#endif /* __LV2_KERNEL_MACHINE_SYSCALL_INTERRUPT_H__ */
