📄 motcpmend.c
字号:
* and the waiting for the device to decide to transmit it.
*
* If it detects a transmission error, the restart command is issued.
*
* These routine should not call any kernel functions.
*
* RETURNS: OK or EAGAIN
*/
LOCAL STATUS motCpmEndPollSend
(
END_CTRL *pDrvCtrl, /* pointer to END_CTRL structure */
M_BLK_ID pMblk /* data to send */
)
{
int length;
SCC_BUF * pTxBd;
u_char * pad;
char * pBuf;
MOTCPMLOGMSG(("motCpmEndPollSend \n", 0, 0, 0, 0, 0, 0));
if (pDrvCtrl->txStop)
return (ERROR);
/* get a free transmit frame descriptor */
pTxBd = & pDrvCtrl->ether.txBdBase[pDrvCtrl->ether.txBdNext];
/* check if a transmit buffer descriptor is available */
if ((pTxBd->statusMode & SCC_ETHER_TX_BD_R) ||
(((pDrvCtrl->ether.txBdNext + 1) % pDrvCtrl->ether.txBdNum)
== pDrvCtrl->txBdIndexC))
{
return (EAGAIN);
}
/* fill the transmit frame descriptor */
pBuf = pDrvCtrl->txPoolBuf;
length = netMblkToBufCopy (pMblk, (char *)pBuf, NULL);
pTxBd->dataPointer = (u_char *) pBuf;
/* padding mechanism in Rev A is buggy - do in software */
if (length < FRAME_MIN)
{
pad = pTxBd->dataPointer + length;
for (; length != FRAME_MIN; length++, pad++)
*pad = 0x88;
}
pTxBd->dataLength = length;
if (pTxBd->statusMode & SCC_ETHER_TX_BD_W)
pTxBd->statusMode = SCC_ETHER_TX_BD_I | SCC_ETHER_TX_BD_PAD |
SCC_ETHER_TX_BD_L | SCC_ETHER_TX_BD_TC |
SCC_ETHER_TX_BD_W | SCC_ETHER_TX_BD_R;
else
pTxBd->statusMode = SCC_ETHER_TX_BD_I | SCC_ETHER_TX_BD_PAD |
SCC_ETHER_TX_BD_L | SCC_ETHER_TX_BD_TC |
SCC_ETHER_TX_BD_R;
/* incr BD count */
pDrvCtrl->ether.txBdNext = (pDrvCtrl->ether.txBdNext + 1) %
pDrvCtrl->ether.txBdNum;
/* Bump the statistic counter. */
END_ERR_ADD (&pDrvCtrl->endObject, MIB2_OUT_UCAST, +1);
/*
* Spin until we've sent it.
*/
while (pTxBd->statusMode & SCC_ETHER_TX_BD_R)
;
if (pTxBd->statusMode & (SCC_ETHER_TX_BD_RL | SCC_ETHER_TX_BD_UN |
SCC_ETHER_TX_BD_CSL | SCC_ETHER_TX_BD_LC))
{
/* An error has occured, restart the transmitter */
pDrvCtrl->txStop = TRUE;
motCpmTxRestart (pDrvCtrl);
}
/*
* we are allow to do this because transmit queue is empty when we
* start polling mode.
*/
pDrvCtrl->txBdIndexC = pDrvCtrl->ether.txBdNext;
return (OK);
}
/*******************************************************************************
*
* motCpmEndPollReceive - receive a packet in polled mode
*
* This routine is called by a user to try and get a packet from the
* device. It returns EAGAIN if no packet is available. The caller must
* supply a M_BLK_ID with enough space to contain the receiving packet. If
* enough buffer is not available then EAGAIN is returned.
*
* These routine should not call any kernel functions.
*
* RETURNS: OK or EAGAIN
*/
LOCAL STATUS motCpmEndPollReceive
(
END_CTRL *pDrvCtrl, /* pointer to END_CTRL structure */
M_BLK_ID pMblk
)
{
SCC_BUF * pRxBd = & pDrvCtrl->ether.rxBdBase[pDrvCtrl->ether.rxBdNext];
int length;
int status = EAGAIN;
MOTCPMLOGMSG(("motCpmEndPollReceive \n", 0, 0, 0, 0, 0, 0));
/* if we have not received packets, leave immediatly */
if (pRxBd->statusMode & SCC_ETHER_RX_BD_E)
return (EAGAIN);
/* check packets for errors */
if (((pRxBd->statusMode & (SCC_ETHER_RX_BD_F | SCC_ETHER_RX_BD_L))
== (SCC_ETHER_RX_BD_F | SCC_ETHER_RX_BD_L))
&& !(pRxBd->statusMode & (SCC_ETHER_RX_BD_CL |
SCC_ETHER_RX_BD_OV | SCC_ETHER_RX_BD_CR |
SCC_ETHER_RX_BD_SH | SCC_ETHER_RX_BD_NO |
SCC_ETHER_RX_BD_LG)))
{
/* adjust length to data only */
length = pRxBd->dataLength - 4;
if ((length - SIZEOF_ETHERHEADER) <= 0)
{
/* bump input error packet counter */
END_ERR_ADD (&pDrvCtrl->endObject, MIB2_IN_ERRS, +1);
goto cleanRxBd;
}
/*
* Upper layer provides the buffer.
* If buffer is not large enough, we return.
*/
/* copy data */
if ((pMblk->mBlkHdr.mLen < length) ||
(!(pMblk->mBlkHdr.mFlags & M_EXT)))
{
goto cleanRxBd;
}
bcopy ((char *) pRxBd->dataPointer, (char *)pMblk->mBlkHdr.mData,
length);
pMblk->mBlkHdr.mLen = length;
pMblk->mBlkPktHdr.len = length;
pMblk->mBlkHdr.mFlags |= M_PKTHDR;
/* bump input packet counter */
END_ERR_ADD (&pDrvCtrl->endObject, MIB2_IN_UCAST, +1);
status = OK;
}
else
{
/* bump input error packet counter */
END_ERR_ADD (&pDrvCtrl->endObject, MIB2_IN_ERRS, +1);
}
cleanRxBd:
motCpmCleanRxBd (pDrvCtrl, pRxBd); /* reset buffer descriptor as empty */
return (status);
}
/*******************************************************************************
*
* motCpmIntr - network interface interrupt handler
*
* This routine gets called at interrupt level. It handles work that
* requires minimal processing. Interrupt processing that is more
* extensive gets handled at task level. The network task, netTask(), is
* provided for this function. Routines get added to the netTask() work
* queue via the netJobAdd() command.
*
* RETURNS: N/A
*/
LOCAL void motCpmIntr
(
END_CTRL * pDrvCtrl /* pointer to END_CTRL structure */
)
{
BOOL rxHandle = FALSE;
BOOL txbHandle = FALSE;
/* check for spurious interrupt -> initialized ? */
if (!pDrvCtrl->endObject.attached)
{
pDrvCtrl->ether.pSccReg->scce = 0xffff;
*CPM_CISR(pDrvCtrl->regBase) = pDrvCtrl->ether.intMask;
return;
}
/* handle receive events */
if ((pDrvCtrl->ether.pSccReg->sccm & SCC_ETHER_SCCX_RXF) &&
(pDrvCtrl->ether.pSccReg->scce & SCC_ETHER_SCCX_RXF))
{
(void) netJobAdd ((FUNCPTR) motCpmHandleInt, (int) pDrvCtrl,
0, 0, 0, 0);
/* turn off receive interrupts for now - motCpmHandleIt turns back on */
pDrvCtrl->ether.pSccReg->sccm &= ~SCC_ETHER_SCCX_RXF;
rxHandle = TRUE;
}
/* check for output errors */
if (pDrvCtrl->ether.pSccReg->scce & SCC_ETHER_SCCX_TXE)
{
/* clean the transmit buffer descriptor queue */
/* NOTE: HBC error not supported -> always RESTART Tx here */
(void) netJobAdd ((FUNCPTR) motCpmTxRestart, (int) pDrvCtrl,
0, 0, 0, 0);
pDrvCtrl->txStop = TRUE;
}
/* handle transmitter events - BD full condition -> ever happen ? */
if ((pDrvCtrl->ether.pSccReg->sccm & SCC_ETHER_SCCX_TXB) &&
(pDrvCtrl->ether.pSccReg->scce & SCC_ETHER_SCCX_TXB))
{
txbHandle = TRUE;
}
/* check for input busy condition */
if (pDrvCtrl->ether.pSccReg->scce & SCC_ETHER_SCCX_BSY)
pDrvCtrl->ether.pSccReg->scce = SCC_ETHER_SCCX_BSY;
/* acknowledge all other interrupts - ignore events */
pDrvCtrl->ether.pSccReg->scce = (pDrvCtrl->ether.pSccReg->scce &
~(SCC_ETHER_SCCX_RXF |
SCC_ETHER_SCCX_TXE |
SCC_ETHER_SCCX_TXB |
SCC_ETHER_SCCX_BSY));
/*
* clean the transmit buffer descriptor queue if we have
* received a transmit interrupt and if we are not already
* cleaning this transmit queue.
*/
if ((pDrvCtrl->txStop || txbHandle) && !pDrvCtrl->txCleaning)
{
motCpmCleanTxBdQueue (pDrvCtrl);
if (pDrvCtrl->txBlocked)
{
pDrvCtrl->txBlocked = FALSE;
(void) netJobAdd ((FUNCPTR) muxTxRestart,
(int)&pDrvCtrl->endObject,
0, 0, 0, 0);
}
}
/* acknowledge interrupts */
if (rxHandle)
pDrvCtrl->ether.pSccReg->scce = SCC_ETHER_SCCX_RXF;
if (pDrvCtrl->txStop)
pDrvCtrl->ether.pSccReg->scce = SCC_ETHER_SCCX_TXE;
if (txbHandle)
pDrvCtrl->ether.pSccReg->scce = SCC_ETHER_SCCX_TXB;
*CPM_CISR(pDrvCtrl->regBase) = pDrvCtrl->ether.intMask;
}
/*******************************************************************************
*
* motCpmMCastFilterSet - set the group addres filter for a multicast addresse.
*
* To add an address in the processor group address hash filter, we use
* the SET GROUP ADDRESS command. This command can be executed at any
* time, regadless of whether the Ethernet channel is enabled.
*
* RETURNS : N/A
*
*/
LOCAL void motCpmMCastFilterSet
(
END_CTRL * pDrvCtrl, /* pointer to END_CTRL structure */
char * pAddress /* Address to delete from the table. */
)
{
MOTCPMLOGMSG(("motCpmMCastFilterSet \n", 0, 0, 0, 0, 0, 0));
/* add multicast address */
((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->taddr_h =
(pAddress[5] << 8) + pAddress[4];
((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->taddr_m =
(pAddress[3] << 8) + pAddress[2];
((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->taddr_l =
(pAddress[1] << 8) + pAddress[0];
/* issue the set group address command to the CP */
while (*CPM_CPCR(pDrvCtrl->regBase) & CPM_CR_FLG);
*CPM_CPCR(pDrvCtrl->regBase) = ((pDrvCtrl->ether.sccNum - 1) << 6) |
CPM_CR_SCC_SET_GROUP |
CPM_CR_FLG;
while (*CPM_CPCR(pDrvCtrl->regBase) & CPM_CR_FLG);
}
/*******************************************************************************
*
* motCpmMCastConfig - reconfigure the interface under us.
*
* Reconfigure the interface changing the multicast interface list.
*
* In order to delete an address from the hash tabke, the Ethernet channel
* should be disabled, the hash table registers should be cleared, and
* the SET GROUP ADDRESS command must be executed for the remaining
* desired addresses. This is required because the hash table may have mapped
* multiple addresses to the same hash table bit.
*
* RETURNS : N/A
*/
LOCAL void motCpmMCastConfig
(
END_CTRL * pDrvCtrl /* pointer to END_CTRL structure */
)
{
ETHER_MULTI * pCurr;
MOTCPMLOGMSG(("motCpmMCastConfig \n",0,0,0,0,0,0));
/* disable the ethernet channel */
motCpmReset (pDrvCtrl);
/* clear hash table group registers */
((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->gaddr1 = 0x0000;
((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->gaddr2 = 0x0000;
((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->gaddr3 = 0x0000;
((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->gaddr4 = 0x0000;
/* restore remaining addresses */
for (pCurr = END_MULTI_LST_FIRST(&pDrvCtrl->endObject); pCurr != NULL;
pCurr = (ETHER_MULTI *)lstNext(&pCurr->node))
{
/* add multicast address */
motCpmMCastFilterSet (pDrvCtrl, pCurr->addr);
}
/* restart the ethernet channel */
motCpmRestart (pDrvCtrl);
}
/*******************************************************************************
*
* motCpmRestart - network interface restart routine
*
* This routine restarts the device. This includes enabling interrupts,
* starting the transmitter and receiver, and calling the bsp-specific
* LAN enable routine to do any target specific enabling.
*
* This routine follows the instructions in MC68EN360/MPC821 Users's Manual :
* "Disabling the SCCs on the Fly"
*
* The complement
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -