sptask.c 4.85 KB

/**************************************************************************
 *                                                                        *
 *               Copyright (C) 1994, Silicon Graphics, Inc.               *
 *                                                                        *
 *  These coded instructions, statements, and computer programs  contain  *
 *  unpublished  proprietary  information of Silicon Graphics, Inc., and  *
 *  are protected by Federal copyright  law.  They  may not be disclosed  *
 *  to  third  parties  or copied or duplicated in any form, in whole or  *
 *  in part, without the prior written consent of Silicon Graphics, Inc.  *
 *                                                                        *
 *************************************************************************/

/*
 * File:	sptask.c
 * Creator:	hsa@sgi.com
 * Create Date:	Fri May 19 15:54:04 PDT 1995
 *
 * This file has the routines to manage RSP tasks. Load them, start them,
 * stop them, ...
 *
 */


#define	F3DEX_GBI
#include <sptask.h>
#undef	F3DEX_GBI
#include "osint.h"
#include "rcp.h"

/* temporary copy */
static OSTask   tmp_task;

/*
 * This procedure takes all the addresses in a task header and
 * 'physical-izes' them. We do that here, in the library, in order
 * to hide this ugliness from the user.
 */
static OSTask *
_VirtualToPhysicalTask(OSTask *intp)
{
    OSTask      *tp = &tmp_task;
    
    /*
     * do virtual to physical address translation:
     */
    bcopy((char *)intp, (char *)tp, sizeof(OSTask));
    
    /* boot ucode remains virtutal, DMA fixes. */
    
    /* all these 'if' checks are pessimistic protection so that
     * values like 0x0 can survive the error detection of osVirtualToPhysical()
     */
    if (tp->t.ucode != 0x0)
	tp->t.ucode = ((u64 *)
		       osVirtualToPhysical((void *) tp->t.ucode));
    if (tp->t.ucode_data != 0x0)
	tp->t.ucode_data = ((u64 *)
			    osVirtualToPhysical((void *) tp->t.ucode_data));
    if (tp->t.dram_stack != 0x0)
	tp->t.dram_stack = ((u64 *)
			    osVirtualToPhysical((void *) tp->t.dram_stack));
    if (tp->t.output_buff != 0x0)
	tp->t.output_buff = ((u64 *)
			     osVirtualToPhysical((void *) tp->t.output_buff));
    if (tp->t.output_buff_size != 0x0)
	tp->t.output_buff_size = ((u64 *)
				  osVirtualToPhysical((void *) tp->t.output_buff_size));
    if (tp->t.data_ptr != 0x0)
	tp->t.data_ptr = ((u64 *)
			  osVirtualToPhysical((void *) tp->t.data_ptr));
    if (tp->t.yield_data_ptr != 0x0)
	tp->t.yield_data_ptr = ((u64 *)
			osVirtualToPhysical((void *) tp->t.yield_data_ptr));
    return(tp);
}



/*
 * Load a task into the SP. This is the first part of starting off
 * a task.
 * 
 * Also handle the yield case, if this was a restart.
 *
 */
void
osSpTaskLoad(OSTask *intp)
{
    OSTask	*tp;

#ifdef _DEBUG
    if ((intp->t.dram_stack != 0x0) &&
	((u32)intp->t.dram_stack & 0xf)) {
	__osError(ERR_OSSPTASKLOAD_DRAM, 1, intp->t.dram_stack);
	return;
    }
    if ((intp->t.output_buff != 0x0) &&
	((u32)intp->t.output_buff & 0xf)) {
	__osError(ERR_OSSPTASKLOAD_OUT, 1, intp->t.output_buff);
	return;
    }
    if ((intp->t.output_buff_size != 0x0) &&
	((u32)intp->t.output_buff_size & 0xf)) {
	__osError(ERR_OSSPTASKLOAD_OUTSIZE, 1, intp->t.output_buff_size);
	return;
    }
    if ((intp->t.yield_data_ptr != 0x0) &&
	((u32)intp->t.yield_data_ptr & 0xf)) {
	__osError(ERR_OSSPTASKLOAD_YIELD, 1, intp->t.yield_data_ptr);
	return;
    }
#endif

    /* make a copy of the task header, fix the pointers: */
    tp = _VirtualToPhysicalTask(intp);

    if (tp->t.flags & OS_TASK_YIELDED) {
        /* use yielded data (saved when task yielded) */
        tp->t.ucode_data = tp->t.yield_data_ptr;
        tp->t.ucode_data_size = tp->t.yield_data_size;

	/* clear flag in ORIGINAL copy of task header: */
        intp->t.flags &= ~OS_TASK_YIELDED;

	/* support yielding for gSPLoadUcode */
	if (tp->t.flags & OS_TASK_LOADABLE){
	  /* Get ucode ptr already loaded */
	  tp->t.ucode = (u64 *)IO_READ(((u32)intp->t.yield_data_ptr)+
				       OS_YIELD_DATA_SIZE-4);
	}
    }

    osWritebackDCache(tp, sizeof(*tp));	/* don't forget to do this */
    /*
     * We must do the following state setting safely:
     */
    __osSpSetStatus((SP_CLR_TASKDONE | SP_CLR_YIELDED | SP_CLR_YIELD | 
		     SP_SET_INTR_BREAK));
    while(__osSpSetPc(SP_IMEM_START) == -1)
	;
    while(__osSpRawStartDma((u32) OS_WRITE,
			    (u32) (SP_DMEM_END - sizeof(OSTask) + 1),
			    tp, (u32) sizeof(OSTask)) == -1)
	;
    while(__osSpDeviceBusy())
	;
    while(__osSpRawStartDma((u32) OS_WRITE, (u32) SP_IMEM_START,
			    tp->t.ucode_boot, 
			    (u32) tp->t.ucode_boot_size) == -1)
	;
}

/*
 * Start a task running on the SP. Basically just flips the 'run' bit...
 */
void
osSpTaskStartGo(OSTask *tp)
{
    /* be sure all DMA activity is complete: */
    while(__osSpDeviceBusy())
	;
    __osSpSetStatus(SP_SET_INTR_BREAK|SP_CLR_SSTEP|SP_CLR_BROKE|SP_CLR_HALT);
}