summaryrefslogtreecommitdiff
path: root/cpu/mpc824x/drivers/i2o/i2o1.c
diff options
context:
space:
mode:
authorwdenk <wdenk>2001-11-28 17:49:55 +0000
committerwdenk <wdenk>2001-11-28 17:49:55 +0000
commit327f7a020a3037ae8ef6c94488d5e9a3aa772943 (patch)
treee9cdb59ef86fef010d1133a2589577509afe7523 /cpu/mpc824x/drivers/i2o/i2o1.c
parent12e4407c6a42284671bbcb4acceeedc00df04cb5 (diff)
downloadu-boot-imx-327f7a020a3037ae8ef6c94488d5e9a3aa772943.zip
u-boot-imx-327f7a020a3037ae8ef6c94488d5e9a3aa772943.tar.gz
u-boot-imx-327f7a020a3037ae8ef6c94488d5e9a3aa772943.tar.bz2
Initial revision
Diffstat (limited to 'cpu/mpc824x/drivers/i2o/i2o1.c')
-rw-r--r--cpu/mpc824x/drivers/i2o/i2o1.c890
1 files changed, 890 insertions, 0 deletions
diff --git a/cpu/mpc824x/drivers/i2o/i2o1.c b/cpu/mpc824x/drivers/i2o/i2o1.c
new file mode 100644
index 0000000..d840af0
--- /dev/null
+++ b/cpu/mpc824x/drivers/i2o/i2o1.c
@@ -0,0 +1,890 @@
+/*********************************************************
+ * $Id
+ *
+ * copyright @ Motorola, 1999
+ *********************************************************/
+#include "i2o.h"
+
+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" );
+
+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/LOCAL */
+ 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
+ * LOCAL : 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/LOCAL */
+ 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
+ * LOCAL : 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
+ *
+ * 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 == LOCAL && ( in_db & 0x3 ) == 0 )
+ {
+ return I2ODBINVALID;
+ }
+
+ if ( loc == REMOTE )
+ {
+ /* pcsrbar is base */
+ val = load_runtime_reg( base, I2O_OMIMR );
+ val &= 0xfffffff7;
+ store_runtime_reg( base, I2O_OMIMR , val );
+ }
+ else
+ {
+ /* eumbbar is base */
+ 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 == LOCAL && ( in_db & 0x3 ) == 0 )
+ {
+ return I2ODBINVALID;
+ }
+
+ if ( loc == REMOTE )
+ {
+ /* pcsrbar is the base */
+ val = load_runtime_reg( base, I2O_OMIMR );
+ val |= 0x8;
+ store_runtime_reg( base, I2O_OMIMR, val );
+ }
+ else
+ {
+ val = load_runtime_reg( base, I2O_IMIMR);
+ in_db = ( in_db & 0x3 ) << 3;
+ val |= in_db;
+ 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, val;
+
+ if ( loc == REMOTE )
+ {
+ /* read outbound doorbell register of device, pcsrbar is the base */
+ val = load_runtime_reg( base, I2O_ODBR );
+ msg = val & 0xe0000000;
+ store_runtime_reg( base, I2O_ODBR, val ); /* 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: I2OOutMsgStatGet
+ *
+ * description: PCI master reads device's outbound msg unit interrupt status.
+ * Reading an interrupt status register,
+ * the register will be cleared.
+ *
+ * The value of the status register is AND with the outbound
+ * interrupt mask and result is returned.
+ *
+ * note:
+ * pcsrbar must be passed to the function.
+ ********************************************************************/
+I2OSTATUS I2OOutMsgStatGet( unsigned int pcsrbar, I2OOMSTAT *val )
+{
+ unsigned int stat;
+ unsigned int mask;
+
+ if ( val == 0 )
+ {
+ return I2OINVALID;
+ }
+
+ /* read device's outbound status */
+ stat = load_runtime_reg( pcsrbar, I2O_OMISR );
+ mask = load_runtime_reg( pcsrbar, I2O_OMIMR );
+ store_runtime_reg( pcsrbar, I2O_OMISR, stat & 0xffffffd7);
+
+ stat &= mask;
+ val->rsvd0 = ( stat & 0xffffffc0 ) >> 6;
+ val->opqi = ( stat & 0x00000020 ) >> 5;
+ val->rsvd1 = ( stat & 0x00000010 ) >> 4;
+ val->odi = ( stat & 0x00000008 ) >> 3;
+ val->rsvd2 = ( stat & 0x00000004 ) >> 2;
+ val->om1i = ( stat & 0x00000002 ) >> 1;
+ val->om0i = ( stat & 0x00000001 );
+
+ return I2OSUCCESS;
+}
+
+/********************************************************************
+ * function: I2OInMsgStatGet
+ *
+ * description: Local processor reads its inbound msg unit interrupt status.
+ * Reading an interrupt status register,
+ * the register will be cleared.
+ *
+ * The inbound msg interrupt status is AND with the inbound
+ * msg interrupt mask and result is returned.
+ *
+ * note:
+ * eumbbar must be passed to the function.
+ ********************************************************************/
+I2OSTATUS I2OInMsgStatGet(unsigned int eumbbar, I2OIMSTAT *val)
+{
+ unsigned int stat;
+ unsigned int mask;
+
+ if ( val == 0 )
+ {
+ return I2OINVALID;
+ }
+
+ /* read device's outbound status */
+ stat = load_runtime_reg( eumbbar, I2O_OMISR );
+ mask = load_runtime_reg( eumbbar, I2O_OMIMR );
+ store_runtime_reg( eumbbar, I2O_OMISR, stat & 0xffffffe7 );
+
+ stat &= mask;
+ val->rsvd0 = ( stat & 0xfffffe00 ) >> 9;
+ val->ofoi = ( stat & 0x00000100 ) >> 8;
+ val->ipoi = ( stat & 0x00000080 ) >> 7;
+ val->rsvd1 = ( stat & 0x00000040 ) >> 6;
+ val->ipqi = ( stat & 0x00000020 ) >> 5;
+ val->mci = ( stat & 0x00000010 ) >> 4;
+ val->idi = ( stat & 0x00000008 ) >> 3;
+ val->rsvd2 = ( stat & 0x00000004 ) >> 2;
+ val->im1i = ( stat & 0x00000002 ) >> 1;
+ val->im0i = ( stat & 0x00000001 );
+
+ 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 )
+{
+ if ( fifo_stat.qba == 0xffffffff )
+ {
+ /* not enabled */
+ return;
+ }
+
+ unsigned int val = load_runtime_reg( eumbbar, I2O_MUCR );
+ 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 char *)pTil);
+ 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 char *)pTil);
+ 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
+ * LOCAL : 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 );
+}