diff options
author | wdenk <wdenk> | 2001-11-28 17:49:55 +0000 |
---|---|---|
committer | wdenk <wdenk> | 2001-11-28 17:49:55 +0000 |
commit | 327f7a020a3037ae8ef6c94488d5e9a3aa772943 (patch) | |
tree | e9cdb59ef86fef010d1133a2589577509afe7523 /cpu/mpc824x/drivers/i2o/i2o1.c | |
parent | 12e4407c6a42284671bbcb4acceeedc00df04cb5 (diff) | |
download | u-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.c | 890 |
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 ); +} |