📄 if_qu.c
字号:
/* set promiscuous bit according to flags */ if (pDrvCtrl->idr.ac_if.if_flags & IFF_PROMISC) pDrvCtrl->ether.pSccReg->psmr |= SCC_ETHER_PSMR_PRO; else pDrvCtrl->ether.pSccReg->psmr &= ~SCC_ETHER_PSMR_PRO; break; default: error = EINVAL; } splx (s); return (error); }/********************************************************************************* quReset - 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 sys360EnetDisable() to do any target specific disabling.** The complement of this rotuine is quInit(). Once a unit is reset in this* routine, it may be re-initialized to a running state by quInit().** RETURNS: N/A*/LOCAL void quReset ( int unit /* unit number */ ) { DRV_CTRL * pDrvCtrl; int counter = 0xffff; if (unit < 0 || unit >= MAX_UNITS) /* sanity check the unit number */ return; pDrvCtrl = & drvCtrl[unit]; /* disable the SCC interrupts */ *M360_CPM_CIMR(pDrvCtrl->regBase) &= ~pDrvCtrl->ether.intMask; /* issue the CP graceful stop command to the transmitter if necessary */ if (pDrvCtrl->ether.pSccReg->gsmrl & SCC_GSMRL_ENT) { while (*M360_CPM_CR(pDrvCtrl->regBase) & CPM_CR_FLG); *M360_CPM_CR(pDrvCtrl->regBase) = ((pDrvCtrl->ether.sccNum - 1) << 6) | CPM_CR_SCC_GRSTOP | CPM_CR_FLG; while (*M360_CPM_CR(pDrvCtrl->regBase) & CPM_CR_FLG); /* wait for graceful stop to register */ while ((counter--) && (!(pDrvCtrl->ether.pSccReg->scce & SCC_ETHER_SCCX_GRA))); } /* 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) */ sys360EnetDisable (unit, pDrvCtrl->regBase); /* mark the driver as down */ pDrvCtrl->idr.ac_if.if_flags &= ~(IFF_UP | IFF_RUNNING); /* mark the driver as no longer initialized */ pDrvCtrl->initialized = FALSE; }/********************************************************************************* quIntr - 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 quIntr ( int unit /* unit number */ ) { DRV_CTRL * pDrvCtrl = & drvCtrl[unit]; BOOL rxHandle = FALSE; BOOL txbHandle = FALSE; /* check for spurious interrupt -> attached & initialized ? */ if ((!pDrvCtrl->attached) || (!pDrvCtrl->initialized)) { pDrvCtrl->ether.pSccReg->scce = 0xffff; *M360_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) quHandleInt, (int) pDrvCtrl, 0, 0, 0, 0); /* turn off receive interrupts for now - quHandleInt 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) quTxRestart, (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)) {#ifdef BSD43_DRIVER (void) netJobAdd ((FUNCPTR) quStartOutput, unit, 0, 0, 0, 0); #else (void) netJobAdd ((FUNCPTR) quStartOutput, (int)pDrvCtrl, 0, 0, 0, 0); #endif /* BSD43_DRIVER */ pDrvCtrl->ether.pSccReg->sccm &= ~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; /* 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; } /* 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)); /* 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; *M360_CPM_CISR(pDrvCtrl->regBase) = pDrvCtrl->ether.intMask; }/********************************************************************************* quTxRestart - issue RESTART Tx command to the CP** This routine issues a RESTART transmitter command to the CP. It is* executed by netTask (quIntr() did a netJobAdd). quIntr() cannot do* a RESTART directly because the CPM flag must be taken before a command* can be written. After a restart, a netJobAdd of quStartOutput() is* performed in order to send any packets remaining in the interface output* queue.** RETURNS: N/A*/LOCAL void quTxRestart ( DRV_CTRL * pDrvCtrl /* pointer to DRV_CTRL structure */ ) { /* update error counter */ pDrvCtrl->idr.ac_if.if_oerrors++; /* restart transmitter */ while (*M360_CPM_CR(pDrvCtrl->regBase) & CPM_CR_FLG); *M360_CPM_CR(pDrvCtrl->regBase) = ((pDrvCtrl->ether.sccNum - 1) << 6) | CPM_CR_SCC_RESTART | CPM_CR_FLG; while (*M360_CPM_CR(pDrvCtrl->regBase) & CPM_CR_FLG); /* restart transmit routine */ pDrvCtrl->txStop = FALSE;#ifdef BSD43_DRIVER (void) netJobAdd ((FUNCPTR) quStartOutput, pDrvCtrl->idr.ac_if.if_unit, 0, 0, 0, 0); #else (void) netJobAdd ((FUNCPTR) quStartOutput, (int)pDrvCtrl, 0, 0, 0, 0); #endif /* BSD43_DRIVER */ }/********************************************************************************* quHandleInt - task-level interrupt handler** This is the task-level interrupt handler, which is called from * netTask(). quHandleInt() gets input frames from the device and then calls * quRecv() to process each frame. quRecv() 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 quIntr().* Receive interrupts are turned back on by this routine before exiting.** RETURNS: N/A*/LOCAL void quHandleInt ( 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))) quRecv (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; }/********************************************************************************* quRecv - 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 quRecv ( DRV_CTRL * pDrvCtrl, /* pointer to DRV_CTRL structure */ SCC_BUF * pRxBd /* receive buffer descriptor */ ) { FAST ETH_HDR * pEtherHdr; /* pointer to the ethernet header */ MBUF * pMbuf = NULL; /* MBUF pointer */ u_char * pData; int length;#ifdef BSD43_DRIVER UINT16 type;#endif /* BSD43_DRIVER */ /* call hook if one is connected */ if ((etherInputHookRtn != NULL) && ((*etherInputHookRtn) (& pDrvCtrl->idr.ac_if, pRxBd->dataPointer, pRxBd->dataLength) != 0)) return; /* filter frame if controller is in promiscuous mode - M bit is buggy */ if (pDrvCtrl->ether.pSccReg->psmr & SCC_ETHER_PSMR_PRO) { if ((bcmp ((char *) ((ETH_HDR *) pRxBd->dataPointer)->ether_dhost, (char *) pDrvCtrl->idr.ac_enaddr, ENET_ADDR_SIZE)) && (bcmp ((char *) ((ETH_HDR *) pRxBd->dataPointer)->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 ethernet header */ pEtherHdr = (ETH_HDR *) pRxBd->dataPointer; /* point to data */ pData = (u_char *)pEtherHdr + SIZEOF_ETHERHEADER;#ifdef BSD43_DRIVER /* save type - build_cluster trashes the type field */ type = ((ETH_HDR *) pRxBd->dataPointer)->ether_type;#endif /* BSD43_DRIVER */ /* OK to loan out buffer ? -> build a mbuf cluster */ if ((pDrvCtrl->nLoanRxBd > 0) && (USE_CLUSTER (length))) pMbuf = build_cluster ( pData, length, & pDrvCtrl->idr.ac_if, MC_QU, pDrvCtrl->pRefCnt [(pDrvCtrl->nLoanRxBd - 1)], (FUNCPTR)quLoanFree, (int) pDrvCtrl, (int) pRxBd->dataPointer, (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 (pEtherHdr, pMbuf, &pDrvCtrl->idr, length);#endif /* bump input packet counter */ pDrvCtrl->idr.ac_if.if_ipackets++; }/********************************************************************************* quLoanFree - 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 quLoanFree ( DRV_CTRL * pDrvCtrl, u_char * 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 + -