📄 m8260sccend.c
字号:
* motSccEndPollSend - transmit a packet in polled mode** This routine is called by a user to try and send a packet on the* device. It sends a packet directly on the network from the caller without* going through the normal processes of queuing a pacet on an output queue* 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 motSccEndPollSend ( 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(("motSccEndPollSend \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)) { motSccCleanTxBdQueue (pDrvCtrl); return(EAGAIN); } /* fill the transmit frame descriptor */ pBuf = netClusterGet (pDrvCtrl->endObject.pNetPool, pDrvCtrl->pClPoolId); if (pBuf == NULL) { return(ERROR); } 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; motSccTxRestart (pDrvCtrl); } /* * we are allow to do this because transmit queue is empty when we * start polling mode. */ netClFree (pDrvCtrl->endObject.pNetPool, pBuf); pDrvCtrl->txBdIndexC = pDrvCtrl->ether.txBdNext; return(OK); }/********************************************************************************* motSccEndPollReceive - 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 motSccEndPollReceive ( 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(("motSccEndPollReceive \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 */#ifdef REVA_M8260 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))) {#else 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_SH | SCC_ETHER_RX_BD_NO | SCC_ETHER_RX_BD_LG))) { if (pRxBd->statusMode & SCC_ETHER_RX_BD_CR) /* CRC error ? */ { /* On Pre-revA parts, a false CRC error may occur and if */ /* so the packet length will be 1 less than the correct */ /* value. Adjust length and mask off false error */ pRxBd->dataLength++; pRxBd->statusMode &= ~SCC_ETHER_RX_BD_CR; }#endif length = pRxBd->dataLength; 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: motSccCleanRxBd (pDrvCtrl, pRxBd); /* reset buffer descriptor as empty */ return(status); }/********************************************************************************* motSccIntr - 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 motSccIntr ( 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; *M8260_SIPNR_L(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) motSccHandleInt, (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) motSccTxRestart, (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) { motSccCleanTxBdQueue (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; *M8260_SIPNR_L(pDrvCtrl->regBase) = pDrvCtrl->ether.intMask; }/********************************************************************************* motSccMCastFilterSet - 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 motSccMCastFilterSet ( END_CTRL * pDrvCtrl, /* pointer to END_CTRL structure */ char * pAddress /* Address to delete from the table. */ ) { MOTCPMLOGMSG(("motSccMCastFilterSet \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 (*M8260_CPCR(pDrvCtrl->regBase) & M8260_CPCR_FLG); *M8260_CPCR(pDrvCtrl->regBase) = (M8260_CPCR_PAGE(pDrvCtrl->ether.sccNum - 1) | M8260_CPCR_SBC(pDrvCtrl->ether.sccNum + 3) | M8260_CPCR_OP(M8260_CPCR_SET_GROUP) | M8260_CPCR_FLG); while (*M8260_CPCR(pDrvCtrl->regBase) & M8260_CPCR_FLG); }/********************************************************************************* motSccMCastConfig - 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 motSccMCastConfig ( END_CTRL * pDrvCtrl /* pointer to END_CTRL structure */ ) { ETHER_MULTI * pCurr;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -