2008-06-09 Ken Werner <ken.werner@de.ibm.com>

* libc/machine/spu/Makefile.am: Add new files.
	* libc/machine/spu/Makefile.in: Likewise.
	* libc/machine/spu/include/spu_timer.h: New file to add timer support
        using interrupts.
	* libc/machine/spu/spu_clock_stop.c: Likewise.
	* libc/machine/spu/spu_clock_svcs.c: Likewise.
	* libc/machine/spu/spu_timer_flih.S: Likewise.
	* libc/machine/spu/spu_timer_free.c: Likewise.
	* libc/machine/spu/spu_timer_internal.h: Likewise.
	* libc/machine/spu/spu_timer_slih.c: Likewise.
	* libc/machine/spu/spu_timer_slih_reg.c: Likewise.
	* libc/machine/spu/spu_timer_stop.c: Likewise.
	* libc/machine/spu/spu_timer_svcs.c: Likewise.
This commit is contained in:
Jeff Johnston 2008-06-10 02:13:22 +00:00
parent 27a07c4596
commit a0496b5e4f
13 changed files with 1217 additions and 11 deletions

View File

@ -1,3 +1,19 @@
2008-06-09 Ken Werner <ken.werner@de.ibm.com>
* libc/machine/spu/Makefile.am: Add new files.
* libc/machine/spu/Makefile.in: Likewise.
* libc/machine/spu/include/spu_timer.h: New file to add timer support
using interrupts.
* libc/machine/spu/spu_clock_stop.c: Likewise.
* libc/machine/spu/spu_clock_svcs.c: Likewise.
* libc/machine/spu/spu_timer_flih.S: Likewise.
* libc/machine/spu/spu_timer_free.c: Likewise.
* libc/machine/spu/spu_timer_internal.h: Likewise.
* libc/machine/spu/spu_timer_slih.c: Likewise.
* libc/machine/spu/spu_timer_slih_reg.c: Likewise.
* libc/machine/spu/spu_timer_stop.c: Likewise.
* libc/machine/spu/spu_timer_svcs.c: Likewise.
2008-06-09 Ken Werner <ken.werner@de.ibm.com>
* libc/machine/spu/strcat.c: Return value fixed.

View File

@ -21,7 +21,9 @@ lib_a_SOURCES = setjmp.S assert.c clearerr.c creat.c fclose.c feof.c \
tmpnam.c ungetc.c usleep.c vfiprintf.c vfiscanf.c vfprintf.c \
vfscanf.c viprintf.c viscanf.c vprintf.c vscanf.c vsiprintf.c \
vsiscanf.c vsniprintf.c vsnprintf.c vsprintf.c vsscanf.c \
stack_reg_va.S
stack_reg_va.S spu_clock_svcs.c spu_clock_stop.c spu_timer_flih.S \
spu_timer_slih.c spu_timer_slih_reg.c spu_timer_svcs.c \
spu_timer_stop.c spu_timer_free.c
lib_a_CCASFLAGS = $(AM_CCASFLAGS)
lib_a_CFLAGS = $(AM_CFLAGS)

View File

@ -74,7 +74,11 @@ DIST_COMMON = $(srcdir)/../../../../config.guess \
$(srcdir)/../../../../compile $(srcdir)/../../../../compile \
$(srcdir)/../../../../compile $(srcdir)/../../../../compile \
$(srcdir)/../../../../compile $(srcdir)/../../../../compile \
$(srcdir)/../../../../compile $(srcdir)/../../../../compile
$(srcdir)/../../../../compile $(srcdir)/../../../../compile \
$(srcdir)/../../../../compile $(srcdir)/../../../../compile \
$(srcdir)/../../../../compile $(srcdir)/../../../../compile \
$(srcdir)/../../../../compile $(srcdir)/../../../../compile \
$(srcdir)/../../../../compile
subdir = .
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/../../../acinclude.m4 \
@ -131,7 +135,12 @@ am_lib_a_OBJECTS = lib_a-setjmp.$(OBJEXT) lib_a-assert.$(OBJEXT) \
lib_a-vscanf.$(OBJEXT) lib_a-vsiprintf.$(OBJEXT) \
lib_a-vsiscanf.$(OBJEXT) lib_a-vsniprintf.$(OBJEXT) \
lib_a-vsnprintf.$(OBJEXT) lib_a-vsprintf.$(OBJEXT) \
lib_a-vsscanf.$(OBJEXT) lib_a-stack_reg_va.$(OBJEXT)
lib_a-vsscanf.$(OBJEXT) lib_a-stack_reg_va.$(OBJEXT) \
lib_a-spu_clock_svcs.$(OBJEXT) lib_a-spu_clock_stop.$(OBJEXT) \
lib_a-spu_timer_flih.$(OBJEXT) lib_a-spu_timer_slih.$(OBJEXT) \
lib_a-spu_timer_slih_reg.$(OBJEXT) \
lib_a-spu_timer_svcs.$(OBJEXT) lib_a-spu_timer_stop.$(OBJEXT) \
lib_a-spu_timer_free.$(OBJEXT)
lib_a_OBJECTS = $(am_lib_a_OBJECTS)
DEFAULT_INCLUDES = -I. -I$(srcdir)
depcomp =
@ -205,6 +214,11 @@ STRIP = @STRIP@
USE_LIBTOOL_FALSE = @USE_LIBTOOL_FALSE@
USE_LIBTOOL_TRUE = @USE_LIBTOOL_TRUE@
VERSION = @VERSION@
ac_ct_AR = @ac_ct_AR@
ac_ct_AS = @ac_ct_AS@
ac_ct_RANLIB = @ac_ct_RANLIB@
ac_ct_READELF = @ac_ct_READELF@
ac_ct_STRIP = @ac_ct_STRIP@
aext = @aext@
am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
@ -220,23 +234,18 @@ build_cpu = @build_cpu@
build_os = @build_os@
build_vendor = @build_vendor@
datadir = @datadir@
datarootdir = @datarootdir@
docdir = @docdir@
dvidir = @dvidir@
exec_prefix = @exec_prefix@
host = @host@
host_alias = @host_alias@
host_cpu = @host_cpu@
host_os = @host_os@
host_vendor = @host_vendor@
htmldir = @htmldir@
includedir = @includedir@
infodir = @infodir@
install_sh = @install_sh@
libdir = @libdir@
libexecdir = @libexecdir@
libm_machine_dir = @libm_machine_dir@
localedir = @localedir@
localstatedir = @localstatedir@
lpfx = @lpfx@
machine_dir = @machine_dir@
@ -245,10 +254,8 @@ mkdir_p = @mkdir_p@
newlib_basedir = @newlib_basedir@
oext = @oext@
oldincludedir = @oldincludedir@
pdfdir = @pdfdir@
prefix = @prefix@
program_transform_name = @program_transform_name@
psdir = @psdir@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
sys_dir = @sys_dir@
@ -271,7 +278,9 @@ lib_a_SOURCES = setjmp.S assert.c clearerr.c creat.c fclose.c feof.c \
tmpnam.c ungetc.c usleep.c vfiprintf.c vfiscanf.c vfprintf.c \
vfscanf.c viprintf.c viscanf.c vprintf.c vscanf.c vsiprintf.c \
vsiscanf.c vsniprintf.c vsnprintf.c vsprintf.c vsscanf.c \
stack_reg_va.S
stack_reg_va.S spu_clock_svcs.c spu_clock_stop.c spu_timer_flih.S \
spu_timer_slih.c spu_timer_slih_reg.c spu_timer_svcs.c \
spu_timer_stop.c spu_timer_free.c
lib_a_CCASFLAGS = $(AM_CCASFLAGS)
lib_a_CFLAGS = $(AM_CFLAGS)
@ -430,6 +439,12 @@ lib_a-stack_reg_va.o: stack_reg_va.S
lib_a-stack_reg_va.obj: stack_reg_va.S
$(CCAS) $(lib_a_CCASFLAGS) $(CCASFLAGS) -c -o lib_a-stack_reg_va.obj `if test -f 'stack_reg_va.S'; then $(CYGPATH_W) 'stack_reg_va.S'; else $(CYGPATH_W) '$(srcdir)/stack_reg_va.S'; fi`
lib_a-spu_timer_flih.o: spu_timer_flih.S
$(CCAS) $(lib_a_CCASFLAGS) $(CCASFLAGS) -c -o lib_a-spu_timer_flih.o `test -f 'spu_timer_flih.S' || echo '$(srcdir)/'`spu_timer_flih.S
lib_a-spu_timer_flih.obj: spu_timer_flih.S
$(CCAS) $(lib_a_CCASFLAGS) $(CCASFLAGS) -c -o lib_a-spu_timer_flih.obj `if test -f 'spu_timer_flih.S'; then $(CYGPATH_W) 'spu_timer_flih.S'; else $(CYGPATH_W) '$(srcdir)/spu_timer_flih.S'; fi`
.c.o:
$(COMPILE) -c $<
@ -855,6 +870,48 @@ lib_a-vsscanf.o: vsscanf.c
lib_a-vsscanf.obj: vsscanf.c
$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-vsscanf.obj `if test -f 'vsscanf.c'; then $(CYGPATH_W) 'vsscanf.c'; else $(CYGPATH_W) '$(srcdir)/vsscanf.c'; fi`
lib_a-spu_clock_svcs.o: spu_clock_svcs.c
$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-spu_clock_svcs.o `test -f 'spu_clock_svcs.c' || echo '$(srcdir)/'`spu_clock_svcs.c
lib_a-spu_clock_svcs.obj: spu_clock_svcs.c
$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-spu_clock_svcs.obj `if test -f 'spu_clock_svcs.c'; then $(CYGPATH_W) 'spu_clock_svcs.c'; else $(CYGPATH_W) '$(srcdir)/spu_clock_svcs.c'; fi`
lib_a-spu_clock_stop.o: spu_clock_stop.c
$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-spu_clock_stop.o `test -f 'spu_clock_stop.c' || echo '$(srcdir)/'`spu_clock_stop.c
lib_a-spu_clock_stop.obj: spu_clock_stop.c
$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-spu_clock_stop.obj `if test -f 'spu_clock_stop.c'; then $(CYGPATH_W) 'spu_clock_stop.c'; else $(CYGPATH_W) '$(srcdir)/spu_clock_stop.c'; fi`
lib_a-spu_timer_slih.o: spu_timer_slih.c
$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-spu_timer_slih.o `test -f 'spu_timer_slih.c' || echo '$(srcdir)/'`spu_timer_slih.c
lib_a-spu_timer_slih.obj: spu_timer_slih.c
$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-spu_timer_slih.obj `if test -f 'spu_timer_slih.c'; then $(CYGPATH_W) 'spu_timer_slih.c'; else $(CYGPATH_W) '$(srcdir)/spu_timer_slih.c'; fi`
lib_a-spu_timer_slih_reg.o: spu_timer_slih_reg.c
$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-spu_timer_slih_reg.o `test -f 'spu_timer_slih_reg.c' || echo '$(srcdir)/'`spu_timer_slih_reg.c
lib_a-spu_timer_slih_reg.obj: spu_timer_slih_reg.c
$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-spu_timer_slih_reg.obj `if test -f 'spu_timer_slih_reg.c'; then $(CYGPATH_W) 'spu_timer_slih_reg.c'; else $(CYGPATH_W) '$(srcdir)/spu_timer_slih_reg.c'; fi`
lib_a-spu_timer_svcs.o: spu_timer_svcs.c
$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-spu_timer_svcs.o `test -f 'spu_timer_svcs.c' || echo '$(srcdir)/'`spu_timer_svcs.c
lib_a-spu_timer_svcs.obj: spu_timer_svcs.c
$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-spu_timer_svcs.obj `if test -f 'spu_timer_svcs.c'; then $(CYGPATH_W) 'spu_timer_svcs.c'; else $(CYGPATH_W) '$(srcdir)/spu_timer_svcs.c'; fi`
lib_a-spu_timer_stop.o: spu_timer_stop.c
$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-spu_timer_stop.o `test -f 'spu_timer_stop.c' || echo '$(srcdir)/'`spu_timer_stop.c
lib_a-spu_timer_stop.obj: spu_timer_stop.c
$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-spu_timer_stop.obj `if test -f 'spu_timer_stop.c'; then $(CYGPATH_W) 'spu_timer_stop.c'; else $(CYGPATH_W) '$(srcdir)/spu_timer_stop.c'; fi`
lib_a-spu_timer_free.o: spu_timer_free.c
$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-spu_timer_free.o `test -f 'spu_timer_free.c' || echo '$(srcdir)/'`spu_timer_free.c
lib_a-spu_timer_free.obj: spu_timer_free.c
$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-spu_timer_free.obj `if test -f 'spu_timer_free.c'; then $(CYGPATH_W) 'spu_timer_free.c'; else $(CYGPATH_W) '$(srcdir)/spu_timer_free.c'; fi`
uninstall-info-am:
ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)

View File

@ -0,0 +1,84 @@
/*
(C) Copyright IBM Corp. 2008
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of IBM nor the names of its contributors may be
used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _SPU_TIMER_H_
#define _SPU_TIMER_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
/* Clock services. */
extern void spu_clock_start (void);
extern int spu_clock_stop (void);
extern uint64_t spu_clock_read (void);
/* Timer services. */
extern int spu_timer_alloc (int interval, void (*func) (int));
extern int spu_timer_free (int id);
extern int spu_timer_start (int id);
extern int spu_timer_stop (int id);
/* Interrupt services. */
extern void spu_slih_register (unsigned event_mask,
unsigned (*slih) (unsigned));
extern unsigned spu_clock_slih (unsigned event_mask);
/* Number of supported timers. */
#define SPU_TIMER_NTIMERS 4
/* Recommended minimun spu timer interval time from (cat /proc/cpuinfo)
* QS20 100/14318000 = 6.98 usec
* QS21/QS22 100/26666666 = 3.75 usec
* PS3 100/79800000 = 1.25 usec */
#define SPU_TIMER_MIN_INTERVAL 100
/* Clock error codes. */
#define SPU_CLOCK_ERR_NOT_RUNNING -2
#define SPU_CLOCK_ERR_STILL_RUNNING -3
#define SPU_CLOCK_ERR_TIMERS_ACTIVE -4
/* Timer error codes. */
#define SPU_TIMER_ERR_INVALID_PARM -10
#define SPU_TIMER_ERR_NONE_FREE -11
#define SPU_TIMER_ERR_INVALID_ID -12
#define SPU_TIMER_ERR_ACTIVE -13
#define SPU_TIMER_ERR_NOT_ACTIVE -14
#define SPU_TIMER_ERR_NOCLOCK -15
#define SPU_TIMER_ERR_FREE -16
#define SPU_TIMER_ERR_NOT_STOPPED -17
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,67 @@
/*
(C) Copyright IBM Corp. 2008
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of IBM nor the names of its contributors may be
used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
/* SPU clock stop library service. */
#include <spu_timer.h>
#include "spu_timer_internal.h"
/* Stops the SPU clock:
* decrements clock start count
* when count is zero, disables the decrementer event and stops the
decrementer
Returns 0 on success and <0 on failure:
* SPU_CLOCK_ERR_NOT_RUNNING - clock was already off
* SPU_CLOCK_ERR_TIMERS_ACTIVE - active timers exist
* SPU_CLOCK_ERR_STILL_RUNNING - start count was decremented but clock was
not stopped */
int
spu_clock_stop (void)
{
if (__spu_clock_startcnt == 0)
return SPU_CLOCK_ERR_NOT_RUNNING;
if (__spu_clock_startcnt == 1 && (__spu_timers_active || __spu_timers_handled))
return SPU_CLOCK_ERR_TIMERS_ACTIVE;
/* Don't stop clock if the clock is still in use. */
if (--__spu_clock_startcnt != 0)
return SPU_CLOCK_ERR_STILL_RUNNING;
/* Clock stopped, stop decrementer. */
__disable_spu_decr ();
/* Clock is enabled on clock start - restore to original state (saved at start). */
if (__likely (!__spu_clock_state_was_enabled))
{
spu_idisable ();
}
return 0;
}

View File

@ -0,0 +1,93 @@
/*
(C) Copyright IBM Corp. 2008
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of IBM nor the names of its contributors may be
used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
/* SPU clock start and read library services. */
#include <spu_timer.h>
#include "spu_timer_internal.h"
/* The software managed timebase value. */
volatile uint64_t __spu_tb_val __attribute__ ((aligned (16)));
/* Timeout value of the current interval. */
volatile int __spu_tb_timeout __attribute__ ((aligned (16)));
/* Clock start count (clock is running if >0). */
volatile unsigned __spu_clock_startcnt __attribute__ ((aligned (16)));
/* Saved interrupt state from clock_start. */
volatile unsigned __spu_clock_state_was_enabled;
/* Initializes the software managed timebase, enables the decrementer event,
starts the decrementer and enables interrupts. Must be called before
clock or timer services can be used. Should only be called by base app/lib
code (not from an interrupt/timer handler).
Returns with interrupts ENABLED. */
void
spu_clock_start (void)
{
/* Increment clock start and return if it was already running. */
if (++__spu_clock_startcnt > 1)
return;
__spu_clock_state_was_enabled = spu_readch (SPU_RdMachStat) & 0x1;
spu_idisable ();
__spu_tb_timeout = CLOCK_START_VALUE;
__spu_tb_val = 0;
/* Disable, write, enable the decrementer. */
__enable_spu_decr (__spu_tb_timeout, __disable_spu_decr ());
spu_ienable ();
return;
}
/* Returns a monotonically increasing, 64-bit counter, in timebase units,
relative to the last call to spu_clock_start(). */
uint64_t
spu_clock_read (void)
{
int64_t time;
unsigned was_enabled;
/* Return 0 if clock is off. */
if (__spu_clock_startcnt == 0)
return 0LL;
was_enabled = spu_readch (SPU_RdMachStat) & 0x1;
spu_idisable ();
time = __spu_tb_val + (__spu_tb_timeout - spu_readch (SPU_RdDec));
if (__likely (was_enabled))
spu_ienable ();
return time;
}

View File

@ -0,0 +1,152 @@
/*
(C) Copyright IBM Corp. 2008
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of IBM nor the names of its contributors may be
used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
/* First-level interrupt handler. */
/* The following two convenience macros assist in the coding of the
saving and restoring the volatile register starting from register
2 up to register 79.
saveregs first, last Saves registers from first to the last.
restoreregs first, last Restores registers from last down to first.
Note: first must be less than or equal to last. */
.macro saveregs first, last
stqd $\first, -(STACK_SKIP+\first)*16($SP)
.if \last-\first
saveregs "(\first+1)",\last
.endif
.endm
.macro restoreregs first, last
lqd $\last, (82-\last)*16($SP)
.if \last-\first
restoreregs \first,"(\last-1)"
.endif
.endm
.section .interrupt,"ax"
.align 3
.type spu_flih, @function
spu_flih:
/* Adjust the stack pointer to skip the maximum register save area
(STACK_SKIP quadword registers) in case an interrupt occurred while
executing a leaf function that used the stack area without actually
allocating its own stack frame. */
.set STACK_SKIP, 125
/* Save the current link register on a new stack frame for the
normal spu_flih() version of this file. */
stqd $0, -(STACK_SKIP+80)*16($SP)
stqd $SP, -(STACK_SKIP+82)*16($SP) /* Save back chain pointer. */
saveregs 2, 39
il $2, -(STACK_SKIP+82)*16 /* Stack frame size. */
rdch $3, $SPU_RdEventStat /* Read event status. */
rdch $6, $SPU_RdEventMask /* Read event mask. */
hbrp /* Open a slot for instruction prefetch. */
saveregs 40,59
clz $4, $3 /* Get first slih index. */
stqd $6, -(STACK_SKIP+1)*16($SP) /* Save event mask on stack. */
saveregs 60, 67
/* Do not disable/ack the decrementer event here.
The timer library manages this and expects it
to be enabled upon entry to the SLIH. */
il $7, 0x20
andc $5, $3, $7
andc $7, $6, $5 /* Clear event bits. */
saveregs 68, 69
wrch $SPU_WrEventAck, $3 /* Ack events(s) - include decrementer event. */
wrch $SPU_WrEventMask, $7 /* Disable event(s) - exclude decrementer event. */
saveregs 70, 79
a $SP, $SP, $2 /* Instantiate flih stack frame. */
next_event:
/* Fetch and dispatch the event handler for the first non-zero event. The
dispatch handler is indexed into the __spu_slih_handlers array using the
count of zero off the event status as an index. */
ila $5, __spu_slih_handlers /* Slih array offset. */
shli $4, $4, 2 /* Slih entry offset. */
lqx $5, $4, $5 /* Load slih address. */
rotqby $5, $5, $4 /* Rotate to word 0. */
bisl $0, $5 /* Branch to slih. */
clz $4, $3 /* Get next slih index. */
brnz $3, next_event
lqd $2, 81*16($SP) /* Read event mask from stack. */
restoreregs 40, 79
wrch $SPU_WrEventMask, $2 /* Restore event mask. */
hbrp /* Open a slot for instruction pre-fetch. */
restoreregs 2, 39
/* Restore the link register from the new stack frame for the
normal spu_flih() version of this file. */
lqd $0, 2*16($SP)
lqd $SP, 0*16($SP) /* restore stack pointer from back chain ptr. */
irete /* Return from interrupt and re-enable interrupts. */
.size spu_flih, .-spu_flih
/* spu_slih_handlers[]
Here we initialize 33 default event handlers. The first entry in this array
corresponds to the event handler for the event associated with bit 0 of
Channel 0 (External Event Status). The 32nd entry in this array corresponds
to bit 31 of Channel 0 (DMA Tag Status Update Event). The 33rd entry in
this array is a special case entry to handle "phantom events" which occur
when the channel count for Channel 0 is 1, causing an asynchronous SPU
interrupt, but the value returned for a read of Channel 0 is 0. The index
calculated into this array by spu_flih() for this case is 32, hence the
33rd entry. */
.data
.align 4
.extern __spu_default_slih
.global __spu_slih_handlers
.type __spu_slih_handlers, @object
__spu_slih_handlers:
.rept 33
.long __spu_default_slih
.endr
.size __spu_slih_handlers, .-__spu_slih_handlers

View File

@ -0,0 +1,86 @@
/*
(C) Copyright IBM Corp. 2008
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of IBM nor the names of its contributors may be
used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
/* SPU timer free library service. */
#include <spu_timer.h>
#include "spu_timer_internal.h"
/* Frees an allocated timer. The timer must be in the stopped state for this
to succeed. Maybe be called:
* after allocated, before it's started
* after it's been explicitly stopped
Returns 0 on success, timer sucessfully deallocated. Returns <0 on failure
* SPU_TIMER_INVALID_ID - id out of range
* SPU_TIMER_ERR_FREE - id in free state
* SPU_TIMER_ERR_ACTIVE - id in handled or active state */
int
spu_timer_free (int id)
{
spu_timer_t *t, **pn;
unsigned was_enabled;
if (id < 0 || id >= SPU_TIMER_NTIMERS)
return SPU_TIMER_ERR_INVALID_ID;
if (__spu_timers[id].state == SPU_TIMER_STOPPED)
{
was_enabled = spu_readch (SPU_RdMachStat) & 0x1;
spu_idisable ();
t = __spu_timers_stopped;
pn = &__spu_timers_stopped;
while (t && (t->id != id))
{
pn = &t->next;
t = t->next;
}
#ifdef SPU_TIMER_DEBUG
if (!t)
ABORT ();
#endif
*pn = t->next;
/* Add timer back to free list (mask). */
__spu_timers_avail |= (1 << (id));
__spu_timers[id].state = SPU_TIMER_FREE;
if (__likely (was_enabled))
spu_ienable ();
return 0;
}
/* Handle invalid states. */
return (__spu_timers[id].state == SPU_TIMER_FREE) ?
SPU_TIMER_ERR_FREE : SPU_TIMER_ERR_ACTIVE;
}

View File

@ -0,0 +1,140 @@
/*
(C) Copyright IBM Corp. 2008
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of IBM nor the names of its contributors may be
used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
/* Internal definitions for SPU timer library. */
#ifndef _SPU_TIMER_INTERNAL_H_
#define _SPU_TIMER_INTERNAL_H_
#include <spu_intrinsics.h>
#include <spu_mfcio.h>
#include <limits.h>
#include <stdlib.h>
#ifdef SPU_TIMER_DEBUG
#include <stdio.h>
#include <assert.h>
#endif
/* The timer state tells which list its on. */
typedef enum spu_timer_state
{
SPU_TIMER_FREE = 0,
SPU_TIMER_ACTIVE = 1,
SPU_TIMER_HANDLED = 2,
SPU_TIMER_STOPPED = 3
} spu_timer_state_t;
typedef struct spu_timer
{
int tmout __attribute__ ((aligned (16))); /* Time until expiration (tb). */
int intvl __attribute__ ((aligned (16))); /* Interval. */
int id __attribute__ ((aligned (16)));
spu_timer_state_t state __attribute__ ((aligned (16)));
void (*func) (int) __attribute__ ((aligned (16))); /* Handler. */
struct spu_timer *next __attribute__ ((aligned (16)));
} spu_timer_t;
/* Max decrementer value. */
#define DECR_MAX 0xFFFFFFFFU
/* Arbitrary non-triggering value. */
#define CLOCK_START_VALUE 0x7FFFFFFF
#define MIN_INTVL 1
#define MAX_INTVL INT_MAX
/* Timers within 15 tics will expire together. */
#define TIMER_INTERVAL_WINDOW 15
/* Disables the decrementer and returns the saved event mask for a subsequent
call to __enable_spu_decr. The decrementer interrupt is acknowledged in the
flih when the event is received, but is required also as part of the
procedure to stop the decrementer. */
static inline unsigned
__disable_spu_decr (void)
{
unsigned mask = spu_readch (SPU_RdEventMask);
spu_writech (SPU_WrEventMask, mask & ~MFC_DECREMENTER_EVENT);
spu_writech (SPU_WrEventAck, MFC_DECREMENTER_EVENT);
spu_sync_c ();
return mask;
}
/* Writes and enables the decrementer, along with the given event mask. */
static inline void
__enable_spu_decr (int val, unsigned mask)
{
spu_writech (SPU_WrDec, (val));
spu_writech (SPU_WrEventMask, mask | MFC_DECREMENTER_EVENT);
spu_sync_c ();
}
/* These are shared between modules but are not inlined, to save space. */
extern void __spu_timer_start (int id, int reset);
extern void __reset_spu_decr (int val);
/* The timers. */
extern spu_timer_t __spu_timers[];
/* Active timer list. */
extern spu_timer_t *__spu_timers_active;
/* Stopped (allocated) timer list. */
extern spu_timer_t *__spu_timers_stopped;
/* List of timers being handled. */
extern spu_timer_t *__spu_timers_handled;
/* Bitmask of available timers. */
extern unsigned __spu_timers_avail;
/* The software managed timebase value. */
extern volatile uint64_t __spu_tb_val;
/* Timeout value of the current interval. */
extern volatile int __spu_tb_timeout;
/* Clock start count (clock is running if >0). */
extern volatile unsigned __spu_clock_startcnt;
/* Saved interrupt state from clock_start. */
extern volatile unsigned __spu_clock_state_was_enabled;
#define __likely(_c) __builtin_expect((_c), 1)
#define __unlikely(_c) __builtin_expect((_c), 0)
#define ABORT() \
{\
fprintf(stderr, "Internal error, aborting: %s:%d\n", __FILE__, __LINE__);\
assert(0);\
}
#endif

View File

@ -0,0 +1,221 @@
/*
(C) Copyright IBM Corp. 2008
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of IBM nor the names of its contributors may be
used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
/* Second Level Interrupt handler and related services for SPU timers. */
#include "spu_timer_internal.h"
/* Resets decrementer to the specified value. Also updates software timebase
to account for the time between the last decrementer reset and now. There
are two cases:
* Called by application to start a new timer.
* Called by spu_clock to active the next timer.
In both cases, the amount of time is the current interval timeout minus the
current decrementer value. */
void
__reset_spu_decr (int val)
{
/* The interrupt occurs when the msb goes from 0 to 1 or when the decrementer
goes from 0 to -1. To be precisely accurate we should set the timer to
the intverval -1, unless the interval passed in is 0 in which case it
should be left at 0. */
int enable_val = (__likely (val)) ? val - 1 : 0;
/* Decrementer must be stopped before writing it - minimize the time
stopped. */
unsigned mask = __disable_spu_decr ();
/* Perform tb correction before resettting the decrementer. the corrected
value is the current timeout value minus the current decrementer value.
Occasionally the read returns 0 - a second read will clear this
condition. */
int decval0 = spu_readch (SPU_RdDec);
int decval = spu_readch (SPU_RdDec);
/* Restart decrementer with next timeout val. */
__enable_spu_decr (enable_val, mask);
/* Update the timebase values before enabling for interrupts. */
__spu_tb_val += __spu_tb_timeout - decval;
__spu_tb_timeout = enable_val;
}
/* Update software timebase and timeout value for the 'next to expire' timer.
Called when starting a new timer so the timer list will have timeouts
relative to the current time. */
static inline void
__update_spu_tb_val (void)
{
int elapsed = __spu_tb_timeout - spu_readch (SPU_RdDec);
#ifdef SPU_TIMER_DEBUG
if (elapsed < 0)
ABORT ();
#endif
__spu_tb_val += elapsed;
/* Adjust the timeout for the timer next to expire. Note this could cause
the timeout to go negative, if it was just about to expire when we called
spu_timer_start. This is OK, since this can happen any time interrupts
are disabled. We just schedule an immediate timeout in this case. */
if (__spu_timers_active)
{
__spu_timers_active->tmout -= elapsed;
if (__spu_timers_active->tmout < 0)
__spu_timers_active->tmout = 0;
}
}
/* Add an allocated timer to the active list. The active list is sorted by
timeout value. The timer at the head of the list is the timer that will
expire next. The rest of the timers have a timeout value that is relative
to the timer ahead of it on the list. This relative value is determined
here, when the timer is added to the active list. When its position in the
list is found, the timer's timeout value is set to its interval minus the
sum of all the timeout values ahead of it. The timeout value for the timer
following the newly added timer is then adjusted to a new relative value. If
the newly added timer is at the head of the list, the decrementer is reset.
This function is called by SLIH to restart multiple timers (reset == 0) or
by spu_timer_start() to start a single timer (reset == 1). */
void
__spu_timer_start (int id, int reset)
{
spu_timer_t *t;
spu_timer_t **pn;
spu_timer_t *start = &__spu_timers[id];
unsigned tmout_time = 0;
unsigned my_intvl = start->intvl;
unsigned was_enabled = spu_readch (SPU_RdMachStat) & 0x1;
spu_idisable ();
t = __spu_timers_active;
pn = &__spu_timers_active;
/* If the active list is empty, just add the timer with the timeout set to
the interval. Otherwise find the place in the list for the timer, setting
its timeout to its interval minus the sum of timeouts ahead of it. */
start->state = SPU_TIMER_ACTIVE;
if (__likely (!t))
{
__spu_timers_active = start;
start->next = NULL;
start->tmout = my_intvl;
}
else
{
/* Update swtb and timeout val of the next timer, so all times are
relative to now. */
if (reset)
__update_spu_tb_val ();
while (t && (my_intvl >= (tmout_time + t->tmout)))
{
tmout_time += t->tmout;
pn = &t->next;;
t = t->next;
}
start->next = t;
start->tmout = my_intvl - tmout_time;
*pn = start;
/* Adjust timeout for timer after us. */
if (t)
t->tmout -= start->tmout;
}
if (reset && (__spu_timers_active == start))
__reset_spu_decr (__spu_timers_active->tmout);
if (__unlikely (was_enabled))
spu_ienable ();
}
/* SLIH for decrementer. Manages software timebase and timers.
Called by SPU FLIH. Assumes decrementer is still running
(event not yet acknowledeged). */
unsigned int
spu_clock_slih (unsigned status)
{
int decr_reset_val;
spu_timer_t *active, *handled;
unsigned was_enabled = spu_readch (SPU_RdMachStat) & 0x1;
status &= ~MFC_DECREMENTER_EVENT;
spu_idisable ();
/* The decrementer has now expired. The decrementer event was acknowledged
in the FLIH but not disabled. The decrementer will continue to run while
we're running the clock/timer handler. The software clock keeps running,
and accounts for all the time spent running handlers. Add the current
timeout to the software timebase and set the timeout to DECR_MAX. This
allows the "clock read" code to continue to work while we're in here, and
gives us the most possible time to finish before another underflow. */
__spu_tb_val += __spu_tb_timeout;
__spu_tb_timeout = DECR_MAX;
/* For all timers that have the current timeout value, move them from the
active list to the handled list and call their handlers. Note that the
handled/stopped lists may be manipulated by the handlers if they wish to
stop/free the timers. Note that only the first expired timer will reflect
the real timeout value; the rest of the timers that had the same timeout
value will have a relative value of zero. */
if (__spu_timers_active)
{
__spu_timers_active->tmout = 0;
while ((active = __spu_timers_active)
&& (active->tmout <= TIMER_INTERVAL_WINDOW))
{
__spu_timers_active = active->next;
active->next = __spu_timers_handled;
__spu_timers_handled = active;
active->state = SPU_TIMER_HANDLED;
(*active->func) (active->id);
}
}
/* put the handled timers back on the list and restart decrementer. */
while ((handled = __spu_timers_handled) != NULL)
{
__spu_timers_handled = handled->next;
__spu_timer_start (handled->id, 0);
}
/* Reset the decrementer before returning. If we have any active timers, we
set it to the timeout value for the timer at the head of the list, else
the default clock value. */
decr_reset_val = __spu_timers_active ? __spu_timers_active->tmout : CLOCK_START_VALUE;
__reset_spu_decr (decr_reset_val);
if (__likely (was_enabled))
spu_ienable ();
return status;
}

View File

@ -0,0 +1,72 @@
/*
(C) Copyright IBM Corp. 2008
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of IBM nor the names of its contributors may be
used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
/* Services for SLIH registration. */
#include <spu_intrinsics.h>
#include <spu_timer.h>
#define SPU_EVENT_ID(_mask) \
(spu_extract(spu_cntlz(spu_promote(_mask, 0)), 0))
typedef unsigned (*spu_slih_t) (unsigned);
extern spu_slih_t __spu_slih_handlers[];
/* This function is called whenever an event occurs for which no second level
event handler was registered. The default event handler does nothing and
zeros the most significant event bit indicating that the event was processed
(when in reality, it was discarded). */
unsigned
__spu_default_slih (unsigned events)
{
unsigned int mse;
mse = 0x80000000 >> SPU_EVENT_ID (events);
events &= ~mse;
return (events);
}
/* Registers a SPU second level interrupt handler for the events specified by
mask. The event mask consists of a set of bits corresponding to the event
status bits (see channel 0 description). A mask containing multiple 1 bits
will set the second level event handler for each of the events. */
void
spu_slih_register (unsigned mask, spu_slih_t func)
{
unsigned int id;
while (mask)
{
id = SPU_EVENT_ID (mask);
__spu_slih_handlers[id] = (func) ? func : __spu_default_slih;
mask &= ~(0x80000000 >> id);
}
}

View File

@ -0,0 +1,101 @@
/*
(C) Copyright IBM Corp. 2008
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of IBM nor the names of its contributors may be
used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
/* SPU timer stop library service. */
#include <spu_timer.h>
#include "spu_timer_internal.h"
/* Stop a timer. Moves it from either the active or handled list to the
stopped list. Returns 0 on sucess, timer was successfully stopped.
Returns <0 - Failure:
* SPU_TIMER_ERR_NOT_ACTIVE - timer was not active
* SPU_TIMER_ERR_INVALID_ID - invalid timer id
* SPU_TIMER_ERR_NOCLOCK - spu clock is not running */
int
spu_timer_stop (int id)
{
spu_timer_t *t, **pn;
unsigned was_enabled;
if (id < 0 || id >= SPU_TIMER_NTIMERS)
return SPU_TIMER_ERR_INVALID_ID;
if (__spu_clock_startcnt == 0)
return SPU_TIMER_ERR_NOCLOCK;
/* Free or stopped states. */
if (__spu_timers[id].state == SPU_TIMER_ACTIVE ||
__spu_timers[id].state == SPU_TIMER_HANDLED)
{
was_enabled = spu_readch (SPU_RdMachStat) & 0x1;
spu_idisable ();
/* Timer is on either active list or handled list. */
t = (__spu_timers[id].state == SPU_TIMER_ACTIVE)
? __spu_timers_active : __spu_timers_handled;
pn = (__spu_timers[id].state == SPU_TIMER_ACTIVE)
? &__spu_timers_active : &__spu_timers_handled;
while (t && t->id != id)
{
pn = &t->next;
t = t->next;
}
#ifdef SPU_TIMER_DEBUG
if (!t)
ABORT (); /* Internal error. */
#endif
/* Fix timeout of next timer and decrementer if we were at the head of
the active list. */
if (t->next)
{
t->next->tmout += t->tmout;
if (__spu_timers_active == t)
__reset_spu_decr (t->next->tmout);
}
else
__reset_spu_decr (CLOCK_START_VALUE);
*pn = t->next; /* Update this elements to pointer. */
t->next = __spu_timers_stopped;
__spu_timers_stopped = t;
__spu_timers[id].state = SPU_TIMER_STOPPED;
if (__likely (was_enabled))
spu_ienable ();
return 0;
}
return SPU_TIMER_ERR_NOT_ACTIVE;
}

View File

@ -0,0 +1,115 @@
/*
(C) Copyright IBM Corp. 2008
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of IBM nor the names of its contributors may be
used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
/* SPU timer start and alloc library services. */
#include <spu_timer.h>
#include "spu_timer_internal.h"
/* The timers. */
spu_timer_t __spu_timers[SPU_TIMER_NTIMERS] __attribute__ ((aligned (16)));
/* Active timer list. */
spu_timer_t *__spu_timers_active;
/* Stopped (allocated) timer list. */
spu_timer_t *__spu_timers_stopped;
/* List of timers being handled. */
spu_timer_t *__spu_timers_handled;
/* Bitmask of available timers. */
unsigned __spu_timers_avail =
((1 << (SPU_TIMER_NTIMERS - 1)) + ((1 << (SPU_TIMER_NTIMERS - 1)) - 1));
/* Allocates an SPU interval timer and returns the timer ID. Must be called
before starting a timer. interval specifies the expiration interval in
timebase units. func specifies the function pointer to expiration handler.
Returns the timer ID on success or <0 on Failure:
* SPU_TIMER_ERR_NONE_FREE - no free timers to allocate
* SPU_TIMER_ERR_INVALID_PARM - invalid parm */
int
spu_timer_alloc (int interval, void (*func) (int))
{
unsigned was_enabled;
int id;
if (interval < MIN_INTVL || interval > MAX_INTVL || func == NULL)
return SPU_TIMER_ERR_INVALID_PARM;
was_enabled = spu_readch (SPU_RdMachStat) & 0x1;
/* Get id of next available timer. */
id = spu_extract ((spu_sub ((unsigned) 31,
spu_cntlz (spu_promote
(__spu_timers_avail, 0)))), 0);
/* No timers avail. */
if (id == -1)
return SPU_TIMER_ERR_NONE_FREE;
/* Higher order bits represent lower timer ids. */
__spu_timers_avail &= ~(1 << (id));
id = (SPU_TIMER_NTIMERS - 1) - id;
/* Initialize timer and put it on stopped list. */
(__spu_timers + id)->func = func;
(__spu_timers + id)->intvl = interval;
(__spu_timers + id)->id = id;
(__spu_timers + id)->state = SPU_TIMER_STOPPED;
spu_idisable ();
(__spu_timers + id)->next = __spu_timers_stopped;
__spu_timers_stopped = &__spu_timers[id];
if (__likely (was_enabled))
spu_ienable ();
return id;
}
/* External interface for starting a timer. See description of
__spu_timer_start(). Returns 0 on success and <0 on failure:
* SPU_TIMER_ERR_INVALID_ID - invalid id
* SPU_TIMER_ERR_NOCLOCK - clock is off
* SPU_TIMER_ERR_NOT_STOPPED - timer not in stopped state */
int
spu_timer_start (int id)
{
if (id < 0 || id >= SPU_TIMER_NTIMERS)
return SPU_TIMER_ERR_INVALID_ID;
if (__spu_clock_startcnt == 0)
return SPU_TIMER_ERR_NOCLOCK;
if (__spu_timers[id].state != SPU_TIMER_STOPPED)
return SPU_TIMER_ERR_NOT_STOPPED;
__spu_timer_start (id, 1);
return 0;
}