📄 i2o.c
字号:
/**********************************************************************
* 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 )
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -