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);
}