📄 if_cpm.c
字号:
default: error = EINVAL; } splx (s); return (error); }/********************************************************************************* cpmReset - network interface reset routine** This routine marks the interface as down and resets the device. This* includes disabling interrupts, stopping the transmitter and receiver,* and calling sysCpmEnetDisable() to do any target specific disabling.** The complement of this rotuine is cpmInit(). Once a unit is reset in this* routine, it may be re-initialized to a running state by cpmInit().** RETURNS: N/A*/LOCAL STATUS cpmReset ( int unit /* unit number */ ) { DRV_CTRL * pDrvCtrl; if (unit < 0 || unit >= MAX_UNITS) /* sanity check the unit number */ return (ERROR); pDrvCtrl = & drvCtrl[unit]; sysCpmEnetIntDisable (unit); /* disable the SCC interrupts */ /* issue the CP graceful stop command to the transmitter if necessary */ if (pDrvCtrl->ether.pSccReg->gsmrl & SCC_GSMRL_ENT) { (void) sysCpmEnetCommand (unit, CPM_CR_SCC_GRSTOP); /* wait for graceful stop to register */ /* wait for graceful stop to register */ taskDelay (sysClkRateGet ()); if (!(pDrvCtrl->ether.pSccReg->scce & SCC_ETHER_SCCX_GRA)) return (ERROR); /* Stop not registered. */ } /* disable the SCC receiver and transmitter */ pDrvCtrl->ether.pSccReg->gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT); /* call the BSP to do any other disabling (e.g., *TENA) */ sysCpmEnetDisable (unit); /* mark the driver as down */ pDrvCtrl->idr.ac_if.if_flags &= ~(IFF_UP | IFF_RUNNING); return (OK); }/********************************************************************************* cpmIntr - 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 cpmIntr ( int unit /* unit number */ ) { DRV_CTRL * pDrvCtrl = & drvCtrl[unit]; BOOL rxHandle = FALSE; BOOL txHandle = FALSE; int events; /* identify and acknowledge all interrupt events */ events = (pDrvCtrl->ether.pSccReg->scce & pDrvCtrl->ether.pSccReg->sccm); /* check for spurious interrupt */ if (!pDrvCtrl->attached) { pDrvCtrl->ether.pSccReg->scce = 0xffff; sysCpmEnetIntClear (unit); return; } /* handle receive events */ if (events & SCC_ETHER_SCCX_RXF) { (void) netJobAdd ((FUNCPTR) cpmHandleInt, (int) pDrvCtrl, 0, 0, 0, 0); /* turn off receive interrupts for now - cpmHandleInt 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) { /* NOTE: HBC error not supported -> always RESTART Tx here */ (void) netJobAdd ((FUNCPTR) cpmTxRestart, unit, 0, 0, 0, 0); pDrvCtrl->txStop = TRUE; } /* handle transmitter events - BD full condition -> ever happen ? */ if (events & SCC_ETHER_SCCX_TXB) {#ifdef BSD43_DRIVER (void) netJobAdd ((FUNCPTR) cpmStartOutput, unit, 0, 0, 0, 0); #else (void) netJobAdd ((FUNCPTR) cpmStartOutput, (int)pDrvCtrl, 0, 0, 0, 0); #endif pDrvCtrl->ether.pSccReg->sccm &= ~SCC_ETHER_SCCX_TXB; } /* check for input busy condition, we don't enable this interrupt but we check for it with each interrupt. */ if (pDrvCtrl->ether.pSccReg->scce & SCC_ETHER_SCCX_BSY) { pDrvCtrl->ether.pSccReg->scce = SCC_ETHER_SCCX_BSY; /* count discarded frames as errors */ pDrvCtrl->idr.ac_if.if_ierrors += ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->disfc; ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->disfc = 0; } /* ignore and reset all other 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)); if (rxHandle) pDrvCtrl->ether.pSccReg->scce = SCC_ETHER_SCCX_RXF; if (pDrvCtrl->txStop) pDrvCtrl->ether.pSccReg->scce = SCC_ETHER_SCCX_TXE; if (txHandle) pDrvCtrl->ether.pSccReg->scce = SCC_ETHER_SCCX_TXB; sysCpmEnetIntClear (unit); }/********************************************************************************* cpmTxRestart - issue RESTART Tx command to the CP** This routine issues a RESTART transmitter command to the CP. It is* executed by netTask (cpmIntr() did a netJobAdd). cpmIntr() cannot do* a RESTART directly because the CPM flag must be taken before a command* can be written. After a restart, a netJobAdd of cpmStartOutput() is* performed in order to send any packets remaining in the interface output* queue.** RETURNS: N/A*/LOCAL void cpmTxRestart ( int unit /* unit number */ ) { DRV_CTRL * pDrvCtrl = & drvCtrl[unit]; /* update error counter */ pDrvCtrl->idr.ac_if.if_oerrors++; /* correct packet counter */ pDrvCtrl->idr.ac_if.if_opackets--; /* restart the transmitter */ (void) sysCpmEnetCommand (unit, CPM_CR_SCC_RESTART); /* restart transmit routine */ pDrvCtrl->txStop = FALSE;#ifdef BSD43_DRIVER (void) netJobAdd ((FUNCPTR) cpmStartOutput, unit, 0, 0, 0, 0); #else (void) netJobAdd ((FUNCPTR) cpmStartOutput, (int)pDrvCtrl, 0, 0, 0, 0); #endif }/********************************************************************************* cpmHandleInt - task-level interrupt handler** This is the task-level interrupt handler, which is called from * netTask(). cpmHandleInt() gets input frames from the device and then calls * cpmRecv() to process each frame. cpmRecv() only gets called if no error* stats were reported in the buffer descriptor. Data chaining is not* supported.** This routine should be called with SCC receive interrupts masked so that* more netJobAdds of this routine are not performed by cpmIntr().* Receive interrupts are turned back on by this routine before exiting.** RETURNS: N/A*/LOCAL void cpmHandleInt ( DRV_CTRL * pDrvCtrl /* pointer to DRV_CTRL structure */ ) { SCC_BUF * pRxBd = & pDrvCtrl->ether.rxBdBase[pDrvCtrl->ether.rxBdNext]; while (!(pRxBd->statusMode & SCC_ETHER_RX_BD_E)) { /* data chaining is not supported - check all error conditions */ 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))) cpmRecv (pDrvCtrl, pRxBd); else pDrvCtrl->idr.ac_if.if_ierrors++; /* reset buffer descriptor as empty */ if (pRxBd->statusMode & SCC_ETHER_RX_BD_W) pRxBd->statusMode = SCC_ETHER_RX_BD_E | SCC_ETHER_RX_BD_I | SCC_ETHER_RX_BD_W; else pRxBd->statusMode = SCC_ETHER_RX_BD_E | SCC_ETHER_RX_BD_I; /* incr BD count */ pDrvCtrl->ether.rxBdNext = (pDrvCtrl->ether.rxBdNext + 1) % pDrvCtrl->ether.rxBdNum; pRxBd = & pDrvCtrl->ether.rxBdBase[pDrvCtrl->ether.rxBdNext]; /* clear Rx events */ pDrvCtrl->ether.pSccReg->scce = SCC_ETHER_SCCX_RXF; } /* re-enable Rx interrupts */ pDrvCtrl->ether.pSccReg->sccm |= SCC_ETHER_SCCX_RXF; }/********************************************************************************* cpmRecv - process an input frame** This routine processes an input frame, then passes it up to the higher * level in a form it expects. Buffer loaning, promiscuous mode, and* etherInputHookRtns are all supported. Trailer protocols is not supported.** RETURNS: N/A*/LOCAL void cpmRecv ( DRV_CTRL * pDrvCtrl, /* pointer to DRV_CTRL structure */ SCC_BUF * pRxBd /* receive buffer descriptor */ ) { MBUF * pMbuf = NULL; /* MBUF pointer */ UINT8 * pData; int length;#ifdef BSD43_DRIVER UINT16 type;#endif struct ether_header * pEh; /* bump input packet counter */ pDrvCtrl->idr.ac_if.if_ipackets++; /* call hook if one is connected */ if ((etherInputHookRtn != NULL) && ((*etherInputHookRtn) (& pDrvCtrl->idr.ac_if, pRxBd->dataPointer, pRxBd->dataLength) != 0)) return; /* get Ethernet header */ pEh = (struct ether_header *) pRxBd->dataPointer; /* filter frame if controller is in promiscuous mode - M bit is buggy */ if (pDrvCtrl->ether.pSccReg->psmr & SCC_ETHER_PSMR_PRO) { if ((bcmp ( (char *) pEh->ether_dhost, (char *) pDrvCtrl->idr.ac_enaddr, ENET_ADDR_SIZE)) && (bcmp ((char *) pEh->ether_dhost, (char *) etherbroadcastaddr, ENET_ADDR_SIZE))) return; } /* adjust length to data only */ length = pRxBd->dataLength - SIZEOF_ETHERHEADER; if (length <= 0) { pDrvCtrl->idr.ac_if.if_ierrors++; return; } /* point to data */ pData = ((char *)pEh) + SIZEOF_ETHERHEADER;#ifdef BSD43_DRIVER /* save type - build_cluster trashes the type field */ type = pEh->ether_type;#endif /* OK to loan out buffer ? -> build a mbuf cluster */ if ((pDrvCtrl->nLoanRxBd > 0) && (USE_CLUSTER (length))) pMbuf = build_cluster (pData, length, & pDrvCtrl->idr, MC_CPM, pDrvCtrl->pRefCnt[(pDrvCtrl->nLoanRxBd - 1)], cpmLoanFree, (int) pDrvCtrl, (int) pEh, (int) pDrvCtrl->pRefCnt[(pDrvCtrl->nLoanRxBd - 1)]); /* if buffer was successfully turned into mbuf cluster */ if (pMbuf != NULL) pRxBd->dataPointer = pDrvCtrl->lPool[--pDrvCtrl->nLoanRxBd]; else { /* else do same ol' copy to mbuf */ pMbuf = copy_to_mbufs (pData, length, 0, & pDrvCtrl->idr.ac_if); if (pMbuf == NULL) { pDrvCtrl->idr.ac_if.if_ierrors++; return; } } /* send up to protocol */#ifdef BSD43_DRIVER do_protocol_with_type (type, pMbuf, & pDrvCtrl->idr, length);#else do_protocol (pEh, pMbuf, & pDrvCtrl->idr, length);#endif }/********************************************************************************* cpmLoanFree - return the given buffer to loaner pool** This routine returns <pRxBuf> to the pool of available loaner buffers.* It also returns <pRef> to the pool of available loaner reference counters,* then zeroes the reference count.** RETURNS: N/A*/LOCAL void cpmLoanFree ( DRV_CTRL * pDrvCtrl, UINT8 * pRxBuf, UINT8 * pRef ) { /* return loaned buffer to pool */ pDrvCtrl->lPool[pDrvCtrl->nLoanRxBd] = pRxBuf; /* return loaned reference count to pool */ pDrvCtrl->pRefCnt[pDrvCtrl->nLoanRxBd++] = pRef; /* reset reference count - should have been done from above, but... */ *pRef = 0; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -