www.pudn.com > MPC8241BSP.rar > i2o.c


 
/*************************************************************************** 
 *     Copyright Motorola, Inc. 1989-2001 ALL RIGHTS RESERVED 
 * 
 *  $ID:$ 
 * 
 * You are hereby granted a copyright license to use, modify, and 
 * distribute the SOFTWARE, also know as DINK32 (Dynamic Interactive Nano  
 * Kernel for 32-bit processors) solely in conjunction with the development  
 * and marketing of your products which use and incorporate microprocessors  
 * which implement the PowerPC(TM) architecture manufactured by  
 * Motorola and provided you comply with all of the following restrictions  
 * i) this entire notice is retained without alteration in any 
 * modified and/or redistributed versions, and  
 * ii) that such modified versions are clearly identified as such.  
 * No licenses are granted by implication, estoppel or 
 * otherwise under any patents or trademarks of Motorola, Inc. 
 *  
 * The SOFTWARE is provided on an "AS IS" basis and without warranty. To 
 * the maximum extent permitted by applicable law, MOTOROLA DISCLAIMS ALL 
 * WARRANTIES WHETHER EXPRESS OR IMPLIED, INCLUDING IMPLIED WARRANTIES OF 
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE AND ANY WARRANTY  
 * AGAINST INFRINGEMENT WITH REGARD TO THE SOFTWARE  
 * (INCLUDING ANY MODIFIED VERSIONS THEREOF) AND ANY ACCOMPANYING  
 * WRITTEN MATERIALS. 
 *  
 * To the maximum extent permitted by applicable law, IN NO EVENT SHALL 
 * MOTOROLA BE LIABLE FOR ANY DAMAGES WHATSOEVER (INCLUDING WITHOUT  
 * LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS, BUSINESS  
 * INTERRUPTION, LOSS OF BUSINESS INFORMATION, 
 * OR OTHER PECUNIARY LOSS) ARISING OF THE USE OR INABILITY TO USE THE 
 * SOFTWARE. 
 * Motorola assumes no responsibility for the maintenance and support of 
 * the SOFTWARE. 
 ************************************************************************/ 
 
#include "vxWorks.h" 
#include "logLib.h" 
#include "iv.h" 
#include "intLib.h" 
#include "config.h" 
#include "sysLib.h"   
#include "i2o.h" 
extern void    led12(unsigned short ); 
extern unsigned int get_kahlua_pcsrbar( ); /* for I2O_ISR_host */ 
extern unsigned int get_eumbbar( );        /* for I2O_ISR_agent */ 
 
  
extern unsigned int load_runtime_reg( unsigned int eumbbar, unsigned int reg ); 
/*#pragma Alias( load_runtime_reg, "load_runtime_reg" );*/ 
 
extern void store_runtime_reg( unsigned int eumbbar, unsigned int reg, unsigned int val ); 
/*#pragma Alias( store_runtime_reg, "store_runtime_reg" );*/ 
void useI2O(void); 
int runled12; 
typedef struct _fifo_stat 
{ 
    QUEUE_SIZE   qsz; 
    unsigned int qba; 
} FIFOSTAT; 
 
FIFOSTAT fifo_stat = { QSIZE_4K, 0xffffffff }; 
 
/********************************************************************************** 
 * function: I2OMsgEnable 
 * 
 * description: Enable the interrupt associated with in/out bound msg 
 *              return I2OSUCCESS if no error, otherwise return I2OMSGINVALID. 
 * 
 *              All previously enabled interrupts are preserved. 
 * note: 
 * Inbound message interrupt generated by PCI master and serviced by local processor 
 * Outbound message interrupt generated by local processor and serviced by PCI master 
 * 
 * local processor needs to enable its inbound interrupts it wants to handle(LOCAL) 
 * PCI master needs to enable the outbound interrupts of devices it wants to handle(REMOTE) 
 ************************************************************************************/ 
I2OSTATUS I2OMsgEnable ( LOCATION loc,        /*  REMOTE/LOCALA   */ 
                         unsigned int base,   /* pcsrbar/eumbbar */ 
                         unsigned char n )    /* b'1' - msg 0 
				               * b'10'- msg 1 
		 		               * b'11'- both 
					       */ 
{ 
    unsigned int reg, val; 
    if ( ( n & 0x3 ) == 0 ) 
    { 
	/* neither msg 0, nor msg 1 */ 
	return I2OMSGINVALID; 
    } 
 
    n = (~n) & 0x3; 
    /* LOCATION - REMOTE : enable outbound message of device, pcsrbar as base 
     *            LOCALA  : enable local inbound message, eumbbar as base 
     */ 
    reg = ( loc == REMOTE ? I2O_OMIMR : I2O_IMIMR ); 
    val = load_runtime_reg( base, reg ); 
 
    val &= 0xfffffffc; /* masked out the msg interrupt bits */ 
    val |= n;          /* LSB are the one we want */ 
    store_runtime_reg( base, reg, val ); 
 
    return I2OSUCCESS; 
} 
 
/********************************************************************************* 
 * function: I2OMsgDisable 
 * 
 * description: Disable the interrupt associated with in/out bound msg 
 *              Other previously enabled interrupts are preserved. 
 *              return I2OSUCCESS if no error otherwise return I2OMSGINVALID 
 * 
 * note: 
 *  local processor needs to disable its inbound interrupts it is not interested(LOCAL) 
 *  PCI master needs to disable outbound interrupts of devices it is not interested(REMOTE) 
 *********************************************************************************/ 
I2OSTATUS I2OMsgDisable( LOCATION loc,      /*  REMOTE/LOCALA   */ 
                         unsigned int base, /* pcsrbar/eumbbar */ 
                         unsigned char n )  /* b'1' - msg 0 
					     * b'10'- msg 1 
					     * b'11'- both 
					     */ 
{ 
    unsigned int reg, val; 
     
    if ( ( n & 0x3 ) == 0 ) 
    { 
	/* neither msg 0, nor msg 1 */ 
	return I2OMSGINVALID; 
    } 
 
    /* LOCATION - REMOTE : disable outbound message interrupt of device, pcsrbar as base 
     *            LOCALA  : disable local inbound message interrupt, eumbbar as base 
     */ 
    reg = ( loc == REMOTE ? I2O_OMIMR : I2O_IMIMR ); 
    val = load_runtime_reg( base, reg ); 
 
    val &= 0xfffffffc; /* masked out the msg interrupt bits */ 
    val |= ( n & 0x3 ); 
    store_runtime_reg( base, reg, val ); 
 
    return I2OSUCCESS; 
     
} 
 
/************************************************************************** 
 * function: I2OMsgGet 
 * 
 * description: Local processor reads the nth Msg register from its inbound msg, 
 *              or a PCI Master reads nth outbound msg from device 
 * 
 *              return I2OSUCCESS if no error, otherwise return I2OMSGINVALID. 
 * 
 * note: 
 * If it is not local, pcsrbar must be passed to the function. Otherwise eumbbar is passed. 
 * If it is remote, outbound msg on the device is read; otherwise local inbound msg is read 
 *************************************************************************/ 
I2OSTATUS I2OMsgGet ( LOCATION loc,             /* REMOTE/LOCAL */ 
                         unsigned int base,        /*pcsrbar/eumbbar */ 
                         unsigned int n,           /* 0 or 1 */ 
                         unsigned int *msg ) 
{ 
    if ( n >= I2O_NUM_MSG || msg == 0 ) 
    { 
	return I2OMSGINVALID; 
    } 
 
    if ( loc == REMOTE ) 
    { 
	/* read the outbound msg of the device, pcsrbar as base */ 
	*msg = load_runtime_reg( base, I2O_OMR0+n*I2O_REG_OFFSET ); 
    } 
    else 
    { 
	/* read the inbound msg sent by PCI master, eumbbar as base */ 
	*msg = load_runtime_reg( base, I2O_IMR0+n*I2O_REG_OFFSET ); 
    } 
	     
    return I2OSUCCESS; 
} 
 
/*************************************************************** 
 * function: I2OMsgPost 
 * 
 * description: Kahlua  writes to its nth outbound msg register 
 *              PCI master writes to nth inbound msg register of device 
 * 
 *              return I2OSUCCESS if no error, otherwise return I2OMSGINVALID. 
 * 
 * note: 
 * If it is not local, pcsrbar must be passed to the function. Otherwise eumbbar is passed. 
 * 
 * If it is remote, inbound msg on the device is written; otherwise local outbound msg is written 
 ***************************************************************/ 
I2OSTATUS I2OMsgPost( LOCATION loc,             /* REMOTE/LOCAL */ 
                      unsigned int base,        /*pcsrbar/eumbbar */ 
                      unsigned int n,           /* 0 or 1 */ 
                      unsigned int msg ) 
{ 
    if ( n >= I2O_NUM_MSG ) 
    { 
	return I2OMSGINVALID; 
    } 
     
    if ( loc == REMOTE ) 
    { 
	/* write to the inbound msg register of the device, pcsrbar as base  */ 
	store_runtime_reg( base, I2O_IMR0+n*I2O_REG_OFFSET, msg ); 
    } 
    else 
    { 
	/* write to the outbound msg register for PCI master to read, eumbbar as base */ 
	store_runtime_reg( base, I2O_OMR0+n*I2O_REG_OFFSET, msg );	 
    } 
     
    return I2OSUCCESS; 
} 
 
/*********************************************************************** 
 * function: I2ODBEnable 
 * 
 * description: Local processor enables it's inbound doorbell interrupt 
 *              PCI master enables outbound doorbell interrupt of devices 
 *              Other previously enabled interrupts are preserved. 
 *              Return I2OSUCCESS if no error otherwise return I2ODBINVALID 
 * 
 * note: 
 * In DoorBell interrupt is generated by PCI master and serviced by local processor 
 * Out Doorbell interrupt is generated by local processor and serviced by PCI master 
 * PCI master needs to enable the outbound doorbell interrupts of device it wants to handle 
 **********************************************************************/ 
I2OSTATUS I2ODBEnable( LOCATION loc,        /*  REMOTE/LOCAL   */ 
                  unsigned int base,   /* pcsrbar/eumbbar */ 
                  unsigned int in_db ) /* when LOCAL, I2O_IN_DB, MC, I2O_IN_DB|MC */ 
{ 
 
    /* LOCATION - REMOTE : PCI master initializes outbound doorbell message of device 
     *            LOCAL  : Kahlua initializes its inbound doorbell message 
     */ 
    unsigned int val; 
 
    if ( loc == LOCALA && ( in_db & 0x3 ) == 0 ) 
    { 
	return I2ODBINVALID; 
    } 
     
    if ( loc == REMOTE ) 
    { 
	/* pcsrbar is base, clear the ODIM bit to enable interrupt */ 
	val = load_runtime_reg( base, I2O_OMIMR ); 
	val &= 0xfffffff7; 
        store_runtime_reg( base, I2O_OMIMR , val );	     
    } 
    else 
    { 
	/* eumbbar is base, clear the IDIM and/or MCIM bit(s) to enable 
         * interrupt 
         */ 
	val = load_runtime_reg( base, I2O_IMIMR); 
        in_db = ( (~in_db) & 0x3 ) << 3; 
        val = ( val & 0xffffffe7) | in_db; 
        store_runtime_reg( base,  I2O_IMIMR, val ); 	     
    } 
 
    return I2OSUCCESS; 
} 
 
/********************************************************************************** 
 * function: I2ODBDisable 
 * 
 * description: local processor disables its inbound DoorBell Interrupt 
 *              PCI master disables outbound DoorBell interrupt of device 
 *              Other previously enabled interrupts are preserved. 
 *              return I2OSUCCESS if no error.Otherwise return I2ODBINVALID 
 * 
 * note: 
 * local processor needs to disable its inbound doorbell interrupts it is not interested 
 * 
 * PCI master needs to disable outbound doorbell interrupts of device it is not interested 
 ************************************************************************************/ 
I2OSTATUS I2ODBDisable( LOCATION loc,          /*  REMOTE/LOCAL   */ 
                        unsigned int base,     /* pcsrbar/eumbbar */ 
                        unsigned int in_db )   /* when LOCAL, I2O_IN_DB, MC, I2O_IN_DB|MC */ 
{ 
    /* LOCATION - REMOTE : handle device's out bound message initialization 
     *            LOCAL  : handle local in bound message initialization 
     */ 
    unsigned int val; 
 
    if ( loc == LOCALA && ( in_db & 0x3 ) == 0 ) 
    { 
	    return I2ODBINVALID; 
    } 
     
    if ( loc == REMOTE ) 
    { 
	/* pcsrbar is the base */ 
	val = load_runtime_reg( base, I2O_OMIMR ); 
	val |= 0x8; /* set ODIM to disable */ 
        store_runtime_reg( base, I2O_OMIMR, val );	     
    } 
    else 
    { 
	    val = load_runtime_reg( base, I2O_IMIMR); 
            in_db = ( in_db & 0x3 ) << 3; 
            val |= in_db; /* set IDIM and/or MC to disable */ 
            store_runtime_reg( base, I2O_IMIMR, val ); 	     
    } 
 
    return I2OSUCCESS; 
} 
 
/********************************************************************************** 
 * function: I2ODBGet 
 * 
 * description: Local processor reads its in doorbell register, 
 *              PCI master reads the outdoorbell register of device. 
 *              After a doorbell register is read, the whole register will be cleared. 
 *              Otherwise, HW keeps generating interrupt. 
 * 
 * note: 
 * If it is not local, pcsrbar must be passed to the function. 
 * Otherwise eumbbar is passed. 
 * 
 * If it is remote, out doorbell register on the device is read. 
 * Otherwise local in doorbell is read 
 * 
 * If the register is not cleared by write to it, any remaining bit of b'1's 
 * will cause interrupt pending. 
 *********************************************************************************/ 
unsigned int I2ODBGet( LOCATION loc,         /*  REMOTE/LOCAL   */ 
                       unsigned int base)    /* pcsrbar/eumbbar */ 
{ 
    unsigned int msg =0; 
	unsigned int val,i; 
	UINT32 *addr; 
    if ( loc == REMOTE ) 
    { 
	/* read outbound doorbell register of device, pcsrbar is the base */ 
     /*   val = load_runtime_reg( base, 0 );	 
        msg = val & ~0x00000000;*/ 
        
       /* if((*(UINT32 *)(0x88000000))==0x55555555) 
        	logMsg("\ndoorbell receive is ok",0,0,0,0,0,0); 
        else  
        	logMsg("\ndoorbell receive is wrong",0,0,0,0,0,0);*/ 
        
        addr=(UINT32 *)(0x88000000); 
        for(i=0;i<2*1024;i++) 
        addr[i]=0; 
        store_runtime_reg( base, 0, (0x1<<1) ); 
         /* clear the register */ 
    } 
    else 
    { 
	/* read the inbound doorbell register, eumbbar is the base */ 
        val = load_runtime_reg( base, I2O_IDBR ); 
        store_runtime_reg( base, I2O_IDBR, val ); /* clear the register */ 
	 
	msg = val; 
    } 
 
    return msg; 
} 
 
/********************************************************************** 
 * function: I2ODBPost 
 * 
 * description: local processor writes to a outbound doorbell register, 
 *              PCI master writes to the inbound doorbell register of device 
 * 
 * note: 
 * If it is not local, pcsrbar must be passed to the function. 
 * Otherwise eumbbar is passed. 
 * 
 * If it is remote, in doorbell register on the device is written. 
 * Otherwise local out doorbell is written 
 *********************************************************************/ 
void I2ODBPost( LOCATION loc,             /*  REMOTE/LOCAL   */ 
                unsigned int base,        /* pcsrbar/eumbbar */ 
                unsigned int msg )        /*   in   / out    */ 
{ 
    if ( loc == REMOTE ) 
    { 
	/* write to inbound doorbell register of device, pcsrbar is the base */ 
	store_runtime_reg( base, I2O_IDBR, msg ); 
    } 
    else 
    { 
	/* write to local outbound doorbell register, eumbbar is the base */ 
	store_runtime_reg( base, I2O_ODBR, msg & 0x1fffffff ); 
    } 
 
} 
 
/******************************************************************** 
 * function: I2O_ISR_host 
 * 
 * This function is a very simple interrupt service routine to be 
 * installed in the host.  It must poll the Kahlua agent to 
 * determine the cause of the interrupt, without knowing anything 
 * about the nature.  Note that the agent's ISR is already aware  
 * that the interrupt is for the Message unit.  At first, this ISR 
 * only looks at the message unit, but it must be extended in the 
 * future to examine any part of the Kahlua's status registers for 
 * any kind of expected interrupt.  If it doesn't find a cause, it 
 * reports that an unexpected interrupt occurred. 
 * 
 ********************************************************************/ 
/*extern int dink_printff( unsigned char *, ... ); 
#define printf dink_printff*/ 
 
void I2O_ISR_host () 
{ 
/*  unsigned int kahlua_pcsrbar = get_kahlua_pcsrbar(); 
  unsigned int found_cause = 0; 
 
  I2OOMSTAT i2o_status;*/ 
  /*unsigned int db_reg_content;*/ 
 
  /* Try the Message Unit status */ 
 /* if (I2OOutMsgStatGet(kahlua_pcsrbar, &i2o_status) != I2OSUCCESS) 
    logMsg("Unable to read Kahlua's Message Unit status.\n",0,0,0,0,0,0);*/ 
/*  else 
  {*/ 
    /* check the doorbell status */ 
/*    if (i2o_status.odi) 
    {*/ 
      /*logMsg("Doorbell interrupt detected:\n",0,0,0,0,0,0);*/ 
      	 store_runtime_reg(0x84000060, 0, (0x1<<31)); 
 
      	if(runled12%2)	 
	led12(0); 
	else 
	led12(1); 
	runled12++; 
       store_runtime_reg( 0x84000060, 0, (0x1<<1) ); 
	logMsg("\n come to net 1200 interrupt",0,0,0,0,0,0); 
      /*db_reg_content =*/ /*I2ODBGet(REMOTE,0x84000060);*/ 
      /*logMsg("Agent's outbound doorbell register: 0x%x\n",db_reg_content,0,0,0,0,0);*/ 
     /* found_cause++;*/ 
   /* }*/ 
    /* check for Outbound Message 0/1 and Outbound Post Queue interrupts here */ 
/*  }*/ 
 
  /* can't find the cause */ 
  /*if (found_cause == 0) 
    logMsg("A non-Message Unit external interrupt has been detected.\n",0,0,0,0,0,0);*/ 
  return; 
} 
 
 
/******************************************************************** 
 * function: I2O_ISR_agent 
 * 
 * This function is a very simple interrupt service routine to be 
 * installed in the Kahlua agent.  It knows that it is servicing 
 * Message Unit interrupts only.  Initially, it only reports doorbell 
 * interrupts, but should be extended to handle message 0/1 and 
 * the inbound FIFO. 
 * If it doesn't find a cause, it reports that an unexpected message 
 * unit interrupt occurred. 
 * 
 ********************************************************************/ 
void I2O_ISR_agent () 
{ 
  unsigned int eumbbar = get_eumbbar(); 
  unsigned int found_cause = 0; 
 
  I2OIMSTAT i2o_status; 
  unsigned int db_reg_content; 
 
  /* Get the Inbound Message Unit status */ 
  if (I2OInMsgStatGet(eumbbar, &i2o_status) != I2OSUCCESS) 
    logMsg("Unable to read Inbound Message Unit status.\n",0,0,0,0,0,0); 
  else 
  { 
    #ifdef I2O_DBG 
    union{ 
      I2OIMSTAT status; 
      unsigned int raw; 
    } s; 
    s.status = i2o_status; 
    logMsg("inbound message status register, masked: 0x%x\n",s.raw,0,0,0,0,0,0); 
    #endif 
    /* check the doorbell status */ 
    if (i2o_status.idi) 
    { 
      logMsg("Doorbell interrupt detected:\n",0,0,0,0,0,0); 
      db_reg_content = I2ODBGet(LOCALA,eumbbar); 
      logMsg("Agent's inbound doorbell register: 0x%x\n",db_reg_content,0,0,0,0,0); 
      found_cause++; 
    } 
    /* handle Inbound Message 0/1 and Outbound Post Queue interrupts here */ 
  } 
 
  /* can't find the cause */ 
  if (found_cause == 0) 
    logMsg("Unable to determine cause of Inbound Message Unit interrupt.\n",0,0,0,0,0,0); 
  return; 
} 
 
/******************************************************************** 
 * function: I2OOutMsgStatGet 
 * 
 * description: PCI master reads device's outbound msg unit interrupt status. 
 *              Reading an interrupt status register, 
 *              the register will be cleared. 
 * Only the two outbound message interrupt bits (OM1I and OM0I) are cleared, 
 * the other bits are reserved (so leave them alone), or are read only and 
 * are cleared by reading all MFA's or by the host writing 1's to the outbound 
 * doorbell bits. 
 * 
 *              The value of the status register is AND with the outbound 
 *              interrupt mask and result is returned. 
 * The outbound message interrupt mask register has a 1 to mask an interrupt 
 * and a 0 to allow an interrupt, so the mask has to be complemented prior 
 * to the AND operation.  Also note that the OPQI bit may be set irrespective 
 * of the OPQIM bit setting.  I don't see why there is a  OPQIM bit in the 
 * OMIMR, but this is what book IV says.  Since the OPQI status cannot be masked, 
 * do not use the OPQIM bit from the OMIMR. 
 * 
 * note: 
 * pcsrbar must be passed to the function. 
 ********************************************************************/ 
I2OSTATUS I2OOutMsgStatGet( unsigned int pcsrbar, I2OOMSTAT *val ) 
{ 
    union { 
      unsigned int raw_value; 
      I2OOMSTAT status; 
    } s; 
       
    unsigned int mask; 
 
    if ( val == 0 ) 
    { 
	    return I2OINVALID; 
    } 
     
    /* read device's outbound status */ 
    s.raw_value = load_runtime_reg( pcsrbar, I2O_OMISR ); 
    mask = load_runtime_reg( pcsrbar, I2O_OMIMR ); 
 
    /* Use only the ODIM and OM1IM and OM0IM bits, OPQIM doesn't do  
     * anything, others are reserved. 
     */ 
    mask &= 0xb; 
 
    /* only clear the OM1I and OM0I status bits */ 
    store_runtime_reg( pcsrbar, I2O_OMISR, s.raw_value & 0x3); 
     
    /* complement the mask, a 0 means the interrupt is NOT masked */ 
    s.raw_value &= ~mask; 
 
    /* use status register mapping part of the union */ 
    *val = s.status; 
 
    return I2OSUCCESS;    
} 
 
/******************************************************************** 
 * function: I2OInMsgStatGet 
 * 
 * description: Local processor reads its inbound msg unit interrupt status. 
 *              Reading an interrupt status register, 
 *              the register will be cleared. 
 * Only the defined bits in the register are cleared. 
 * 
 *              The inbound msg interrupt status is AND with the inbound 
 *              msg interrupt mask and result is returned. 
 * As in the outbound, the mask register has a 0 to NOT mask the status, 
 * so the mask register is complemented prior to the AND operation. 
 * 
 * note: 
 * eumbbar must be passed to the function. 
 ********************************************************************/ 
I2OSTATUS I2OInMsgStatGet(unsigned int eumbbar, I2OIMSTAT *val) 
{ 
    union { 
      unsigned int raw_value; 
      I2OIMSTAT status; 
    } s; 
 
    unsigned int mask; 
 
    if ( val == 0 ) 
    { 
	    return I2OINVALID; 
    } 
     
    /* read device's inbound status */ 
    s.raw_value = load_runtime_reg( eumbbar, I2O_IMISR ); 
    #ifdef I2O_DBG 
    printf("inbound message status register, not masked: 0x%x\n",s.raw_value); 
    #endif 
    mask = load_runtime_reg( eumbbar, I2O_IMIMR ); 
 
    /* only use defined parts of the mask register, ignore reserved parts */ 
    mask &= 0x1bb; 
 
    /* When resetting, leave the reserved parts alone and do not write to 
     * the MCI and IDI bits which are cleared by writing to the doorbell 
     * register, not the status bits. 
     */ 
    store_runtime_reg( eumbbar, I2O_IMISR, s.raw_value & 0x1a3 ); 
 
    /* use the complement of the mask, a 0 means NOT mask the status bit */ 
    s.raw_value &= ~mask; 
 
    /* use the status register mapping part of the union */ 
    *val = s.status; 
     
    return I2OSUCCESS; 
	    
} 
 
/*********************************************************** 
 * function: I2OFIFOInit 
 * 
 * description: Configure the I2O FIFO, including QBAR, 
 *              IFHPR/IFTPR, IPHPR/IPTPR, OFHPR/OFTPR, 
 *              OPHPR/OPTPR, MUCR. 
 * 
 *              return I2OSUCCESS if no error, 
 *              otherwise return I2OQUEINVALID 
 * 
 * note: It is NOT this driver's responsibility of initializing 
 *       MFA blocks, i.e., FIFO queue itself. The MFA blocks 
 *       must be initialized before I2O unit can be used. 
 ***********************************************************/ 
I2OSTATUS I2OFIFOInit( unsigned int eumbbar, 
		       QUEUE_SIZE   sz,      /* value of CQS of MUCR */ 
		       unsigned int qba)     /* queue base address that must be aligned at 1M */ 
{ 
     
    if ( ( qba & 0xfffff ) != 0 ) 
    { 
	/* QBA must be aligned at 1Mbyte boundary */ 
	return I2OQUEINVALID; 
    } 
 
    store_runtime_reg( eumbbar, I2O_QBAR, qba ); 
    store_runtime_reg( eumbbar, I2O_MUCR, (unsigned int)sz ); 
    store_runtime_reg( eumbbar, I2O_IFHPR, qba ); 
    store_runtime_reg( eumbbar, I2O_IFTPR, qba ); 
    store_runtime_reg( eumbbar, I2O_IPHPR, qba + 1 * ( sz << 11 )); 
    store_runtime_reg( eumbbar, I2O_IPTPR, qba + 1 * ( sz << 11 )); 
    store_runtime_reg( eumbbar, I2O_OFHPR, qba + 2 * ( sz << 11 )); 
    store_runtime_reg( eumbbar, I2O_OFTPR, qba + 2 * ( sz << 11 ));     
    store_runtime_reg( eumbbar, I2O_OPHPR, qba + 3 * ( sz << 11 )); 
    store_runtime_reg( eumbbar, I2O_OPTPR, qba + 3 * ( sz << 11 )); 
 
    fifo_stat.qsz = sz; 
    fifo_stat.qba = qba; 
 
    return I2OSUCCESS; 
} 
 
/************************************************** 
 * function: I2OFIFOEnable 
 * 
 * description: Enable the circular queue 
 *              return I2OSUCCESS if no error. 
 *              Otherwise I2OQUEINVALID is returned. 
 * 
 * note: 
 *************************************************/ 
I2OSTATUS I2OFIFOEnable( unsigned int eumbbar ) 
{ 
    unsigned int val; 
 
    if ( fifo_stat.qba == 0xfffffff ) 
    { 
	return I2OQUEINVALID; 
    } 
	     
    val = load_runtime_reg( eumbbar, I2O_MUCR ); 
    store_runtime_reg( eumbbar, I2O_MUCR, val | 0x1 ); 
 
    return I2OSUCCESS; 
} 
 
/************************************************** 
 * function: I2OFIFODisable 
 * 
 * description: Disable the circular queue 
 * 
 * note: 
 *************************************************/ 
void I2OFIFODisable( unsigned int eumbbar ) 
{ 
    unsigned int val = load_runtime_reg( eumbbar, I2O_MUCR ); 
    if ( fifo_stat.qba == 0xffffffff ) 
    { 
	/* not enabled */ 
	return; 
    } 
     
    store_runtime_reg( eumbbar, I2O_MUCR, val & 0xfffffffe ); 
} 
 
/**************************************************** 
 * function: I2OFIFOAlloc 
 * 
 * description: Allocate a free MFA from free FIFO. 
 *              return I2OSUCCESS if no error. 
 *              return I2OQUEEMPTY if no more free MFA. 
 *              return I2OINVALID on other errors. 
 * 
 *              A free MFA must be allocated before a 
 *              message can be posted. 
 * 
 * note: 
 * PCI Master allocates a free MFA from inbound queue of device 
 * (pcsrbar is the base,) through the inbound queue port of device 
 * while local processor allocates a free MFA from its outbound 
 * queue (eumbbar is the base.) 
 * 
 ****************************************************/ 
I2OSTATUS I2OFIFOAlloc( LOCATION loc, 
		        unsigned int base, 
		        void         **pMsg ) 
{ 
    I2OSTATUS stat = I2OSUCCESS; 
    void *pHdr, *pTil; 
     
    if ( pMsg == 0 || *pMsg == 0 || fifo_stat.qba == 0xffffffff ) 
    { 
	/* not configured */ 
	return I2OQUEINVALID; 
    } 
 
    if ( loc == REMOTE ) 
    { 
	/* pcsrbar is the base and read the inbound free tail ptr */ 
	pTil = (void *)load_runtime_reg( base, I2O_IFQPR ); 
        if ( ( (unsigned int)pTil & 0xFFFFFFF ) == 0xFFFFFFFF ) 
        { 
	    stat = I2OQUEEMPTY; 
        } 
	else 
        { 
	    *pMsg = pTil; 
	} 
    } 
    else 
    { 
	/* eumbbar is the base and read the outbound free tail ptr */ 
	pHdr = (void *)load_runtime_reg( base, I2O_OFHPR ); /* queue head */ 
	pTil = (void *)load_runtime_reg( base, I2O_OFTPR ); /* queue tail */ 
 
	/* check underflow */ 
	if ( pHdr == pTil ) 
	{ 
	    /* hdr and til point to the same fifo item, no free MFA */ 
            stat = I2OQUEEMPTY; 
	} 
	else 
	{ 
	  /* update OFTPR */ 
	  *pMsg = (void *)(*(unsigned int *)pTil); /* modified by zoutl 2003/2/21 */ 
	  pTil = (void *)((unsigned int)pTil + 4); 
	  if ( (unsigned int)pTil == fifo_stat.qba + ( 4 * ( fifo_stat.qsz << 11 ) ) ) 
	  { 
		/* reach the upper limit */ 
		pTil = (void *)(fifo_stat.qba + ( 3 * (fifo_stat.qsz << 11) )); 
	  } 
	  store_runtime_reg( base, I2O_OFTPR, (unsigned int)pTil ); 
	} 
    } 
     
    return stat; 
} 
 
/****************************************************** 
 * function: I2OFIFOFree 
 * 
 * description: Free a used MFA back to free queue after 
 *              use. 
 *              return I2OSUCCESS if no error. 
 *              return I2OQUEFULL if inbound free queue 
 *              overflow 
 * 
 * note: PCI Master frees a MFA into device's outbound queue 
 *       (OFQPR) while local processor frees a MFA into its 
 *       inbound queue (IFHPR).  
 *****************************************************/ 
I2OSTATUS I2OFIFOFree( LOCATION loc, 
		  unsigned int base, 
		  void *pMsg ) 
{ 
    void **pHdr, **pTil; 
    I2OSTATUS stat = I2OSUCCESS; 
     
    if ( fifo_stat.qba == 0xffffffff || pMsg == 0 ) 
    { 
	    return I2OQUEINVALID; 
    } 
     
    if ( loc == REMOTE ) 
    { 
	/* pcsrbar is the base */	 
	store_runtime_reg( base, I2O_OFQPR, (unsigned int)pMsg ); 
    } 
    else 
    { 
	/* eumbbar is the base */ 
	pHdr = (void **)load_runtime_reg( base, I2O_IFHPR ); 
        pTil = (void **)load_runtime_reg( base, I2O_IFTPR ); 
	 
	/* store MFA */ 
	*pHdr = pMsg; 
 
	/* update IFHPR */ 
	pHdr += 4; 
 
	if ( (unsigned int)pHdr == fifo_stat.qba + ( fifo_stat.qsz << 11 ) ) 
	{ 
	  /* reach the upper limit */ 
	  pHdr = (void **)fifo_stat.qba; 
	} 
 
	/* check inbound free queue overflow */ 
	if ( pHdr != pTil ) 
	{ 
	   store_runtime_reg( base, I2O_OPHPR, (unsigned int)pHdr); 
        } 
	else 
	{ 
	    stat = I2OQUEFULL; 
	} 
 
    } 
 
    return stat; 
     
} 
 
/********************************************* 
 * function: I2OFIFOPost 
 * 
 * description: Post a msg into FIFO post queue 
 *              the value of msg must be the one 
 *              returned by I2OFIFOAlloc 
 * 
 * note: PCI Master posts a msg into device's inbound queue 
 *       (IFQPR) while local processor post a msg into device's 
 *       outbound queue (OPHPR) 
 *********************************************/ 
I2OSTATUS I2OFIFOPost( LOCATION loc, 
		       unsigned int base, 
		       void *pMsg ) 
{ 
    void **pHdr, **pTil; 
    I2OSTATUS stat = I2OSUCCESS; 
     
    if ( fifo_stat.qba == 0xffffffff || pMsg == 0 ) 
    { 
	return I2OQUEINVALID; 
    } 
     
    if ( loc == REMOTE ) 
    { 
	/* pcsrbar is the base */ 
	store_runtime_reg( base, I2O_IFQPR, (unsigned int)pMsg ); 
    } 
    else 
    { 
	/* eumbbar is the base */ 
	pHdr = (void **)load_runtime_reg( base, I2O_OPHPR ); 
        pTil = (void **)load_runtime_reg( base, I2O_OPTPR ); 
	 
	/* store MFA */ 
	*pHdr = pMsg; 
 
	/* update IFHPR */ 
	pHdr += 4; 
 
	if ( (unsigned int)pHdr == fifo_stat.qba + 3 * ( fifo_stat.qsz << 11 ) ) 
	{ 
	  /* reach the upper limit */ 
	  pHdr = (void **)(fifo_stat.qba + 2 * ( fifo_stat.qsz << 11 ) ); 
	} 
 
	/* check post queue overflow */ 
	if ( pHdr != pTil ) 
	{ 
	   store_runtime_reg( base, I2O_OPHPR, (unsigned int)pHdr); 
        } 
	else 
	{ 
	    stat = I2OQUEFULL; 
	} 
    } 
 
    return stat; 
} 
 
/************************************************ 
 * function: I2OFIFOGet 
 * 
 * description:  Read a msg from FIFO 
 *               This function should be called 
 *               only when there is a corresponding 
 *               msg interrupt. 
 * 
 * note: PCI Master reads a msg from device's outbound queue 
 *       (OFQPR) while local processor reads a msg from device's 
 *       inbound queue (IPTPR) 
 ************************************************/ 
I2OSTATUS I2OFIFOGet( LOCATION loc, 
		       unsigned int base, 
		       void **pMsg ) 
{ 
    I2OSTATUS stat = I2OSUCCESS;     
    void *pHdr, *pTil; 
 
    if ( pMsg == 0 || *pMsg == 0 || fifo_stat.qba == 0xffffffff ) 
    { 
	/* not configured */ 
	return I2OQUEINVALID; 
    } 
     
    if ( loc == REMOTE ) 
    { 
	/* pcsrbar is the base */ 
	pTil = (void *)load_runtime_reg( base, I2O_OFQPR ); 
        if ( ( (unsigned int)pTil & 0xFFFFFFF ) == 0xFFFFFFFF ) 
        { 
	    stat = I2OQUEEMPTY; 
        } 
	else 
        { 
	    *pMsg = pTil; 
	} 
    } 
    else 
    { 
	/* eumbbar is the base and read the outbound free tail ptr */ 
	pHdr = (void *)load_runtime_reg( base, I2O_IPHPR ); /* queue head */ 
	pTil = (void *)load_runtime_reg( base, I2O_IPTPR ); /* queue tail */ 
 
	/* check underflow */ 
	if ( pHdr == pTil ) 
	{ 
	    /* no free MFA */ 
            stat = I2OQUEEMPTY; 
	} 
	else 
	{ 
	  /* update OFTPR */ 
	  *pMsg = (void *)(*(unsigned int *)pTil); /* modified by zoutl 2003/2/21 */ 
	  pTil = (void *)((unsigned int)pTil + 4); 
	  if ( (unsigned int)pTil == fifo_stat.qba + 2 * ( fifo_stat.qsz << 11 ) ) 
	  { 
		/* reach the upper limit */ 
		pTil = (void *)(fifo_stat.qba + 1 * (fifo_stat.qsz << 11) ); 
	  } 
	   
	  store_runtime_reg( base, I2O_IPTPR, (unsigned int)pTil ); 
	} 
    } 
 
    return stat; 
} 
 
/******************************************************** 
 * function: I2OIOP 
 * 
 * description: Get the I2O PCI configuration identification 
 *              register. 
 * 
 * note: PCI master should pass pcsrbar while local processor 
 *       should pass eumbbar. 
 *********************************************************/ 
I2OSTATUS I2OPCIConfigGet( LOCATION loc, 
		        unsigned int base, 
		        I2OIOP * val) 
{ 
    unsigned int tmp; 
    if ( val == 0 ) 
    { 
	    return I2OINVALID; 
    } 
    tmp = load_runtime_reg( base, PCI_CFG_CLA ); 
    val->base_class = ( tmp & 0xFF) << 16; 
    tmp = load_runtime_reg( base, PCI_CFG_SCL ); 
    val->sub_class= ( (tmp & 0xFF) << 8 ); 
    tmp = load_runtime_reg( base, PCI_CFG_PIC ); 
    val->prg_code = (tmp & 0xFF); 
    return I2OSUCCESS; 
} 
 
/********************************************************* 
 * function: I2OFIFOIntEnable 
 * 
 * description: Enable the circular post queue interrupt 
 * 
 * note: 
 * PCI master enables outbound FIFO interrupt of device 
 * pscrbar is the base 
 * Device enables its inbound FIFO interrupt 
 * eumbbar is the base 
 *******************************************************/ 
void I2OFIFOIntEnable( LOCATION loc, unsigned int base  ) 
{ 
    unsigned int reg, val; 
 
    /* LOCATION - REMOTE : enable outbound message of device, pcsrbar as base 
     *            LOCAL  : enable local inbound message, eumbbar as base 
     */ 
    reg = ( loc == REMOTE ? I2O_OMIMR : I2O_IMIMR ); 
    val = load_runtime_reg( base, reg ); 
 
    val &= 0xffffffdf; /* clear the msg interrupt bits */ 
    store_runtime_reg( base, reg, val ); 
 
} 
 
/**************************************************** 
 * function: I2OFIFOIntDisable 
 * 
 * description: Disable the circular post queue interrupt 
 * 
 * note: 
 * PCI master disables outbound FIFO interrupt of device 
 * (pscrbar is the base) 
 * Device disables its inbound FIFO interrupt 
 * (eumbbar is the base) 
 *****************************************************/ 
void I2OFIFOIntDisable( LOCATION loc, unsigned int base ) 
{ 
 
    /* LOCATION - REMOTE : disable outbound message interrupt of device, pcsrbar as base 
     *            LOCALA  : disable local inbound message interrupt, eumbbar as base 
     */ 
    unsigned int reg = ( loc == REMOTE ? I2O_OMIMR : I2O_IMIMR ); 
    unsigned int val = load_runtime_reg( base, reg ); 
 
    val |= 0x00000020; /* masked out the msg interrupt bits */ 
    store_runtime_reg( base, reg, val ); 
 
} 
 
/********************************************************* 
 * function: I2OFIFOOverflowIntEnable 
 * 
 * description: Enable the circular queue overflow interrupt 
 * 
 * note: 
 * Device enables its inbound FIFO post overflow interrupt 
 * and outbound free overflow interrupt. 
 * eumbbar is the base 
 *******************************************************/ 
void I2OFIFOOverflowIntEnable( unsigned int eumbbar  ) 
{ 
    unsigned int val = load_runtime_reg( eumbbar, I2O_IMIMR ); 
 
    val &= 0xfffffe7f; /* clear the two overflow interrupt bits */ 
    store_runtime_reg( eumbbar, I2O_IMIMR, val ); 
 
} 
 
/**************************************************** 
 * function: I2OFIFOOverflowIntDisable 
 * 
 * description: Disable the circular queue overflow interrupt 
 * 
 * note: 
 * Device disables its inbound post FIFO overflow interrupt 
 * and outbound free FIFO overflow interrupt 
 * (eumbbar is the base) 
 *****************************************************/ 
void I2OFIFOOverflowIntDisable( unsigned int eumbbar ) 
{ 
 
    unsigned int val = load_runtime_reg( eumbbar, I2O_IMIMR ); 
 
    val |= 0x00000180; /* masked out the msg overflow interrupt bits */ 
    store_runtime_reg( eumbbar, I2O_IMIMR, val ); 
} 
void useI2O(void) 
{ 
	 
	 
	 (void) intConnect (INUM_TO_IVEC(0x12),I2O_ISR_host, NULL ); 
 
             intEnable (0x12);  
	 
}