📄 ns83902end.c
字号:
* context of the netTask, which was triggered by a received packet interrupt.* It resends any packet that was in the midst of transmission when the overflow* hit.* Actual processing of the packet is done by calling ns83902Recv().** RETURNS: N/A.*/LOCAL void ns83902HandleInt ( NS83902_END_DEVICE* pDrvCtrl ) { NS83902_CLUSTER pCluster; /* empties the receive ring buffer of its packets */ pDrvCtrl->rxHandling = TRUE; while ((pCluster = ns83902ReadFrame (pDrvCtrl)) != NULL) ns83902Recv (pDrvCtrl, pCluster); pDrvCtrl->rxHandling = FALSE; if (pDrvCtrl->rxOvw == TRUE) { /* Reset overflow bit */ NS83902_REG_SET (pDrvCtrl, NS83902_ISR, ISR_OVW, CR_RPAGE0); NS83902_REG_SET (pDrvCtrl, NS83902_TCR, TCR_MODE0, CR_RPAGE0); /* If resend needed, issue transmit command */ if (pDrvCtrl->txResend == TRUE) { NS83902_REG_SET (pDrvCtrl, NS83902_CR, CR_STA | CR_TXP | CR_ABORT, CR_RPAGE0); pDrvCtrl->txResend = FALSE; } pDrvCtrl->rxOvw = FALSE; } /* Re-enable interrupts */ NS83902_REG_SET (pDrvCtrl, NS83902_IMR, IMR_ENABLE, CR_RPAGE0); }/********************************************************************************* ns83902Int - The driver's interrupt handler** This function clears the cause of the device interrupt(s) and then acts* on the individual possible causes. The primary goal of this routine is to* minimize the time spent in it. This is accomplished by deferring processing* to the netTask via the netJobAdd() function.** Note that in case the receiver overruns, we promptly mark the interface as* "down" and leave error handling to task-level. This is in case netTask* is in the midst of DMA activity, we must allow it to complete. The receive* handler will give up when it discovers the interface is down, which will* then allow netTask to run our OVW handler. This provides orderly error * recovery.** RETURNS: N/A.*/LOCAL void ns83902Int ( NS83902_END_DEVICE* pDrvCtrl ) { UINT8 isr; /* copy of NS83902_ISR */ UINT8 cr; /* copy of NS83902_CR */ /* Check if interface is up and running */ if ((END_FLAGS_GET(&pDrvCtrl->endObj) & (IFF_UP | IFF_RUNNING)) != (IFF_UP | IFF_RUNNING)) return;#ifdef NS83902_INSTRUMENT ns83902IntNb++;#endif DRV_LOG (NS83902_DEBUG_INT, "Inside INT\n", 1, 2, 3, 4, 5, 6); /* Read and clear ISR */ NS83902_REG_GET (pDrvCtrl, NS83902_ISR, isr, CR_RPAGE0); NS83902_REG_SET (pDrvCtrl, NS83902_ISR, isr, CR_RPAGE0); /* handle transmit interrupts */ if (isr & (ISR_PTX | ISR_TXE)) { UINT8 tsr; NS83902_REG_GET (pDrvCtrl, NS83902_TSR, tsr, CR_RPAGE0); DRV_LOG (NS83902_DEBUG_TX, "ns83902Tx Interrupt TSR=%d \n", tsr, 2, 3, 4, 5, 6); if ((tsr & TSR_PTX) == 0) { /* PTX zero, something went wrong */ if (tsr & TSR_ABT) {#ifdef NS83902_INSTRUMENT ns83902TxTimeout++;#endif DRV_LOG (NS83902_DEBUG_TX, "ns83902Transmit Aborted \n", 1, 2, 3, 4, 5, 6); } if (tsr & TSR_FU) { DRV_LOG (NS83902_DEBUG_TX, "ns83902Transmit FIFO Underrun \n", 1, 2, 3, 4, 5, 6); } /* Notify upper layers about the error */ END_ERR_ADD (&pDrvCtrl->endObj, MIB2_OUT_ERRS, +1); pDrvCtrl->lastError.errCode = END_ERR_WARN; pDrvCtrl->lastError.pMesg = "Transmit error"; netJobAdd ((FUNCPTR) muxError, (int) &pDrvCtrl->endObj, (int) &pDrvCtrl->lastError, 0, 0, 0); DRV_LOG (NS83902_DEBUG_TX, "ns83902Transmit Error\n", 0, 0, 0, 0, 0, 0); #ifdef NS83902_INSTRUMENT ns83902TxError++;#endif } if (tsr & TSR_CRS) { DRV_LOG (NS83902_DEBUG_TX, "%s%d - no carrier\n", (int)NS83902_DEV_NAME, pDrvCtrl->unit, 3, 4, 5, 6); } #if 0 /* no collision statistics for END drivers? */ if (tsr & TSR_COL) { UINT8 ncr; NS83902_REG_GET (pDrvCtrl, NS83902_NCR, ncr, CR_RPAGE0); END_ERR_ADD (pEndObj, MIB2_COLLISIONS, ncr); }#endif if (pDrvCtrl->txBlocked == TRUE) { pDrvCtrl->txBlocked = FALSE; netJobAdd ((FUNCPTR)muxTxRestart, (int)&pDrvCtrl->endObj, 0, 0, 0, 0); } } /* handle receiver overrun */ if (isr & ISR_OVW) { /* disable interrupts */ NS83902_REG_SET (pDrvCtrl, NS83902_IMR, IMR_DISABLE, CR_RPAGE0); NS83902_CR_GET (pDrvCtrl, cr); /* mark the interface down */ END_FLAGS_CLR (&pDrvCtrl->endObj, IFF_UP | IFF_RUNNING); ns83902Restart (pDrvCtrl, cr); return; } /* handle packet received */ if (isr & ISR_PRX) if (pDrvCtrl->rxHandling == FALSE) { pDrvCtrl->rxHandling = TRUE; /* disable receive interrupts and defer work to task context */ NS83902_REG_SET (pDrvCtrl, NS83902_IMR, IMR_RX_DISABLE, CR_RPAGE0); netJobAdd ((FUNCPTR) ns83902HandleInt, (int) pDrvCtrl, 0, 0, 0, 0); } }/********************************************************************************* ns83902Send - the driver's actual output routine** This routine accepts outgoing packets from the snd queue, and then * gains exclusive access to the DMA (through a mutex semaphore),* then calls ns83902Transmit() to send the packet out onto the interface.** RETURNS: OK, or ERROR if the packet could not be transmitted.*/LOCAL STATUS ns83902Send ( NS83902_END_DEVICE* pDrvCtrl, M_BLK* pMblk ) { int status; DRV_LOG (NS83902_DEBUG_TX, "Begin ns83902Send pDrvCtrl %p pMblk %p\n", (int)pDrvCtrl, (int)pMblk, 3, 4, 5, 6); if ((END_FLAGS_GET(&pDrvCtrl->endObj) & (IFF_UP | IFF_RUNNING)) != (IFF_UP | IFF_RUNNING)) { DRV_LOG (NS83902_DEBUG_TX, "Device is NOT UP and RUNNING\n", 1, 2, 3, 4, 5, 6); return (ERROR); } /* send packet out over interface */ if ((status = ns83902Transmit (pDrvCtrl, pMblk)) == OK) { /* Success, free the Mblk chain */ if (!NS83902_IS_IN_POLL_MODE()) netMblkClChainFree (pMblk); END_ERR_ADD (&pDrvCtrl->endObj, MIB2_OUT_UCAST, +1); } else { DRV_LOG (NS83902_DEBUG_TX, "FAILED ns83902Transmit\n", 0, 0, 0, 0, 0, 0); /* update statistics */ END_ERR_ADD (&pDrvCtrl->endObj, MIB2_OUT_ERRS, +1);#ifdef NS83902_INSTRUMENT ns83902TxError++;#endif } DRV_LOG (NS83902_DEBUG_TX, "End ns83902Send \n", 0, 0, 0, 0, 0, 0);#ifdef NS83902_INSTRUMENT ns83902TxNb++;#endif return status; }/********************************************************************************* ns83902Transmit - send data over the NIC network interface** This routine transfers data to the NIC device via the remote DMA, and* then signal for a transmission.** RETURNS: OK, or ERROR if the transmitter signalled an error.*/LOCAL STATUS ns83902Transmit ( NS83902_END_DEVICE* pDrvCtrl, M_BLK* pMblk ) { int status = OK; int txLen = 0; UINT8 cr; LOCAL UINT8 txData[ETHERMTU + ENET_HDR_REAL_SIZ]; int cnt; USHORT dummyRead; /* Get exclusive access to DMA */ if (!NS83902_IS_IN_POLL_MODE()) NS83902_SEM_TAKE (pDrvCtrl, WAIT_FOREVER); txLen = netMblkToBufCopy (pMblk, txData, NULL); txLen = max (txLen, ETHERSMALL); /* Check if we are ready to transmit */ NS83902_CR_GET (pDrvCtrl, cr); if (cr & CR_TXP) { DRV_LOG (NS83902_DEBUG_TX, "ns83902Transmit: waiting for TX_IN_PROGRESS\n", 1, 2, 3, 4, 5, 6); /* Wait for end of TX */ cnt = 100; /* timeout 100 mSec */ while ((cr & CR_TXP) && (cnt-- > 0)) { SYS_MS_DELAY (1); NS83902_CR_GET (pDrvCtrl, cr); } } /* If still not ready, bail */ NS83902_CR_GET (pDrvCtrl, cr); if (cr & CR_TXP) { DRV_LOG (NS83902_DEBUG_TX, "Not Ready to transmit!\n", 1, 2, 3, 4, 5, 6); pDrvCtrl->txBlocked = TRUE; /* transmitter not ready */ if (!NS83902_IS_IN_POLL_MODE()) NS83902_SEM_GIVE (pDrvCtrl); return (END_ERR_BLOCK); } /* Dummy read with RBCR > 1 before (see DP83902 manual) */ NS83902_REG_SET (pDrvCtrl, NS83902_RBCR0, 2, CR_RPAGE0); NS83902_REG_SET (pDrvCtrl, NS83902_RBCR1, 0, CR_RPAGE0); NS83902_REG_SET (pDrvCtrl, NS83902_RSAR0, 0, CR_RPAGE0); NS83902_REG_SET (pDrvCtrl, NS83902_RSAR1, LSB(pDrvCtrl->txStartPage), CR_RPAGE0); NS83902_REG_SET (pDrvCtrl, NS83902_CR, CR_RREAD, CR_RPAGE0); if (pDrvCtrl->wide == TRUE) { SYS_IN_SHORT (pDrvCtrl, pDrvCtrl->ioPort, dummyRead); } else { SYS_IN_BYTE (pDrvCtrl, pDrvCtrl->ioPort, dummyRead); SYS_IN_BYTE (pDrvCtrl, pDrvCtrl->ioPort, dummyRead); } /* Set up remote DMA transfer */ NS83902_REG_SET (pDrvCtrl, NS83902_RSAR0, 0, CR_RPAGE0); NS83902_REG_SET (pDrvCtrl, NS83902_RSAR1, LSB(pDrvCtrl->txStartPage), CR_RPAGE0); NS83902_REG_SET (pDrvCtrl, NS83902_RBCR0, LSB(txLen), CR_RPAGE0); NS83902_REG_SET (pDrvCtrl, NS83902_RBCR1, MSB(txLen), CR_RPAGE0); /* Start remote DMA transfer */ NS83902_REG_SET (pDrvCtrl, NS83902_CR, CR_RWRITE, CR_RPAGE0); /* write data to the DMA port */ ns83902WritePort (pDrvCtrl, txData, txLen); /* Se up local DMA */ NS83902_REG_SET (pDrvCtrl, NS83902_TPSR, pDrvCtrl->txStartPage, CR_RPAGE0); NS83902_REG_SET (pDrvCtrl, NS83902_TBCR0, LSB(txLen), CR_RPAGE0); NS83902_REG_SET (pDrvCtrl, NS83902_TBCR1, MSB(txLen), CR_RPAGE0); DRV_LOG (NS83902_DEBUG_TX, "Sending %d bytes from %p \n", txLen, (int)txData, 3, 4, 5, 6); /* Start transmission while preserving DMA command bits */ NS83902_CR_GET (pDrvCtrl, cr); NS83902_REG_SET (pDrvCtrl, NS83902_CR, CR_TXP | (cr & (CR_RWRITE | CR_RREAD | CR_ABORT)), CR_RPAGE0); /* Release Semaphore */ if (!NS83902_IS_IN_POLL_MODE()) { NS83902_SEM_GIVE (pDrvCtrl); } else { UINT8 tsr; UINT8 isr; FOREVER { NS83902_REG_GET (pDrvCtrl, NS83902_ISR, isr, CR_RPAGE0); if ((isr & (ISR_PTX | ISR_TXE)) != 0) break; } /* Check for errors */ NS83902_REG_GET (pDrvCtrl, NS83902_TSR, tsr, CR_RPAGE0); if ((tsr & TSR_PTX) == 0) { /* PTX zero, something went wrong */ status = ERROR; if (tsr & TSR_ABT) {#ifdef NS83902_INSTRUMENT ns83902TxTimeout++;#endif DRV_LOG (NS83902_DEBUG_TX, "ns83902Transmit Aborted \n", 1, 2, 3, 4, 5, 6); } if (tsr & TSR_FU) { DRV_LOG (NS83902_DEBUG_TX, "ns83902Transmit FIFO Underrun \n", 1, 2, 3, 4, 5, 6); } } if (tsr & TSR_CRS) { logMsg ("%s%d - no carrier\n", (int)NS83902_DEV_NAME, pDrvCtrl->unit, 3, 4, 5, 6); } #if 0 /* no collision statistics for END drivers? */ if (tsr & TSR_COL) { UINT8 ncr; NS83902_REG_GET (pDrvCtrl, NS83902_NCR, ncr, CR_RPAGE0); END_ERR_ADD (pEndObj, MIB2_COLLISIONS, ncr); }#endif /* Clear transmit flags in ISR */ NS83902_REG_SET (pDrvCtrl, NS83902_ISR, (ISR_PTX | ISR_TXE), CR_RPAGE0); } return (status); }/********************************************************************************* ns83902Ioctl - the driver's I/O control routine** Perform device-specific commands.** RETURNS: 0, or EINVAL if the command 'cmd' is not supported.*/LOCAL int ns83902Ioctl ( NS83902_END_DEVICE* pDrvCtrl, int cmd, caddr_t data ) { int error = 0; long value; int saveFlags; DRV_LOG (NS83902_DEBUG_LOAD, "ns83902Ioctl Command %d\n", cmd, 2, 3, 4, 5, 6); switch ((UINT)cmd) { case EIOCSADDR: if (data == NULL) return (EINVAL); bcopy ((char *)data, (char *)END_HADDR(&pDrvCtrl->endObj), END_HADDR_LEN(&pDrvCtrl->endObj)); ns83902Config (pDrvCtrl); /* HELP Will it work? */ break; case EIOCGADDR: if (data == NULL) return (EINVAL); bcopy ((char *)END_HADDR(&pDrvCtrl->endObj), (char *)data, END_HADDR_LEN(&pDrvCtrl->endObj)); break; case EIOCSFLAGS: value = (long) data; if( value < 0 ) { value = -value; value--; END_FLAGS_CLR (&pDrvCtrl->endObj, value); } else { END_FLAGS_SET (&pDrvCtrl->endObj, value);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -