| /********************************************************* |
| * $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 ); |
| } |