📄 if_elt.c
字号:
} } else if (pDrvCtrl->interruptTime == -1) ++pDrvCtrl->eltStat.timerInvalid; pDrvCtrl->interruptTime = -2; }#endif /* ELT_TIMING */ while ( (pFrame = pDrvCtrl->pRxCurrent) != NULL) { statusRx = sysInWord(port + RX_STATUS); if (statusRx & RX_S_INCOMPLETE) /* incomplete */ { if (statusRx == RX_S_INCOMPLETE) /* no bytes available */ break; while ((statusRx != (statusRxNew = sysInWord(port + RX_STATUS))) && (ix < 10000)) { statusRx = statusRxNew; ix++; /* XXX */ } }#ifdef ELT_DEBUG logMsg ("eltInt: statusRx=%04x ix=%d\n", statusRx, ix, 0, 0, 0, 0);#endif /* ELT_DEBUG */ /* Copy the FIFO data into the buffer */ length = statusRx & RX_S_CNT_MASK; /* Prevent buffer overflow. * should we discard the packet? that's hard to do safely here. * so truncate packet */ if ( (pFrame->count + length) > MAX_FRAME_SIZE) length = MAX_FRAME_SIZE - pFrame->count; /* transfer only an even number of bytes to leave the pointer * on an even boundary until we reach the end of the frame */ if ( (statusRx & RX_S_INCOMPLETE) != 0) length &= PARTIAL_TRANSFER_MASK; sysInWordString (port + DATA_REGISTER, (short *) pFrame->nextByte, (length + 1) / 2); pFrame->count += length; pFrame->nextByte += length; /* partial packet, wait for complete packet */ if ( (statusRx & RX_S_INCOMPLETE) != 0) break; /* * Packet is now complete. Use 'Discard' command to complete the * transfer */ sysOutWord (port + ELT_COMMAND, RX_DISCARD); /* discard packet */ while ( (sysInWord (port + ELT_STATUS) & COMMAND_IN_PROGRESS) != 0) ; /* wait for command to finish */ /* Check for errors in completed packet */ if ( (statusRx & RX_S_ERROR) != 0) { switch (statusRx & RX_S_CODE_MASK) { case RX_S_OVERRUN: /* handled by statistics registers */ break; case RX_S_RUNT: ++pDrvCtrl->eltStat.shortPacket; break; case RX_S_ALIGN: ++pDrvCtrl->eltStat.aligns; break; case RX_S_CRC: ++pDrvCtrl->eltStat.crcs; break; case RX_S_OVERSIZE: ++pDrvCtrl->eltStat.badPacket; break; default: /* no other codes are defined */ break; } ++pDrvCtrl->eltStat.rxerror; ++pDrvCtrl->idr.ac_if.if_ierrors; /* bump error counter */ pFrame->count = 0; pFrame->nextByte = pFrame->header; pFrame->length = 0; continue; } /* Got a complete packet, count it. */ ++pDrvCtrl->idr.ac_if.if_ipackets; pFrame->length = statusRx; pDrvCtrl->pRxCurrent = pDrvCtrl->pRxCurrent->lNext; }#ifdef ELT_TIMING pDrvCtrl->interruptTime = -1;#endif /* ELT_TIMING */ /* receive no more for now */ if (pDrvCtrl->pRxCurrent == NULL) pDrvCtrl->intMask &= ~(RX_COMPLETE | RX_EARLY); if (!pDrvCtrl->rxHandling && (pDrvCtrl->pRxHead->length != 0)) { result = netJobAdd ( (FUNCPTR) eltRxDeliver, (int) pDrvCtrl, 0, 0, 0, 0);#ifdef ELT_DEBUG if (result == ERROR) logMsg ("elt: netJobAdd (eltRxDeliver) failed\n", 0, 0, 0, 0, 0, 0);#endif /* ELT_DEBUG */#ifdef ELT_TIMING if (result != ERROR) if ( (int)++pDrvCtrl->eltStat.taskQRxOuts > (int)pDrvCtrl->eltStat.maxRxTaskQ) pDrvCtrl->eltStat.maxRxTaskQ = pDrvCtrl->eltStat.taskQRxOuts;#endif /* ELT_TIMING */ pDrvCtrl->rxHandling = TRUE; } } /* Handle transmitter interrupts */ if ( (status & TX_COMPLETE) != 0) { if ( ( (statusTx = sysInByte (port + TX_STATUS)) & TX_S_COMPLETE) != 0) { sysOutByte (port + TX_STATUS, 0); /* clear old status */ /* other errors are tabulated by reading the statistics registers */ if ( (statusTx & TX_S_MAX_COLL) != 0) pDrvCtrl->idr.ac_if.if_collisions += 16; if ( (statusTx & TX_S_JABBER) != 0) ++pDrvCtrl->eltStat.jabbers; if ((statusTx & (TX_S_JABBER | TX_S_MAX_COLL | TX_S_UNDERRUN)) != 0) { needTxStart = TRUE; /* restart transmitter */ /* packet not sent */ pDrvCtrl->idr.ac_if.if_oerrors++; /* incr err count */ pDrvCtrl->idr.ac_if.if_opackets--; /* decr sent count */ } if ( (statusTx & (TX_S_JABBER | TX_S_UNDERRUN)) != 0) { /* Must reset transmitter; this clears the tx FIFO */ sysOutWord (port + ELT_COMMAND, TX_RESET); } } if (needTxStart) /* check flag */ eltTxStart (pDrvCtrl); if (pDrvCtrl->idr.ac_if.if_snd.ifq_head != NULL) { if (!pDrvCtrl->txHandling) { if (netJobAdd ( (FUNCPTR) eltTxFlush, (int) pDrvCtrl, (int) TRUE, 0, 0, 0) == ERROR) {#ifdef ELT_DEBUG logMsg ("elt: netJobAdd (eltTxFlush) failed\n", 0, 0, 0, 0, 0, 0);#endif /* ELT_DEBUG */ } else pDrvCtrl->txHandling = TRUE;#ifdef ELT_TIMING if ( (int)++pDrvCtrl->eltStat.taskQTxOuts > (int)pDrvCtrl->eltStat.maxTxTaskQ) pDrvCtrl->eltStat.maxTxTaskQ = pDrvCtrl->eltStat.taskQTxOuts;#endif /* ELT_TIMING */ } } } /* Handle update statistics interrupt */ if ( (status & UPDATE_STATS) != 0) eltStatFlush (pDrvCtrl); /* mask and ack the events we've just handled or queued handlers for */ sysOutWord (pDrvCtrl->port + ELT_COMMAND, MASK_STATUS | pDrvCtrl->intMask); sysOutWord (pDrvCtrl->port + ELT_COMMAND, ACK_INTERRUPT | status); sysBusIntAck (pDrvCtrl->intLevel); }/********************************************************************************* eltTxFlush - transmit a packet from the output queue** This routine, if the transmitter is currently idle, and if there is a* packet in the output queue, dequeues a packet and transmits it. The* next transmit activity will be a completion interrupt, which will cause* this routine to be scheduled again if there is a packet in the output* queue.*/static void eltTxFlush ( ELT_CTRL * pDrvCtrl, BOOL netJob ) { int port; ELT_FRAME * pFrame; UINT16 outputCount; MBUF * m; port = pDrvCtrl->port; pFrame = pDrvCtrl->pTxFrame; do { if (netJob) pDrvCtrl->txHandling = TRUE; /* Don't dequeue if currently sending */ while ( (sysInWord (pDrvCtrl->port + TX_FREE_BYTES) >= TX_IDLE_COUNT) && (pDrvCtrl->idr.ac_if.if_snd.ifq_head != NULL)) { IF_DEQUEUE (&pDrvCtrl->idr.ac_if.if_snd, m); copy_from_mbufs (pFrame->header, m, outputCount); outputCount = max (ETHERSMALL, outputCount); if ( (etherOutputHookRtn != NULL) && (* etherOutputHookRtn) (&pDrvCtrl->idr, pFrame->header, outputCount)) continue; pFrame->length = outputCount | TX_F_INTERRUPT; outputCount = (outputCount + TX_F_PREAMBLE_SIZE + 3) & TX_F_DWORD_MASK; sysOutWordString (port + DATA_REGISTER, (short *) & pFrame->length, outputCount / 2); /* Bump the statistic counter. */#ifdef ELT_DEBUG printf ("Packet sent.\n"); fflush (stdout);#endif /* ELT_DEBUG */#ifndef BSD43_DRIVER pDrvCtrl->idr.ac_if.if_opackets++;#endif break; /* ISR must call eltTxCleanup() */ } if (netJob) pDrvCtrl->txHandling = FALSE; } while ( (sysInWord (pDrvCtrl->port + TX_FREE_BYTES) >= TX_IDLE_COUNT) && (pDrvCtrl->idr.ac_if.if_snd.ifq_head != NULL));#ifdef ELT_TIMING --pDrvCtrl->eltStat.taskQTxOuts;#endif /* ELT_TIMING */ }/********************************************************************************* eltRxDeliver - pass received frames to the next layer up** Strips the Ethernet header and passes the packet to the appropriate* protocol. If there are enough received frame buffers, the packet may* be passed to the protocol in the frame buffer.* In this latter case, the frame buffer will* eventually be returned by the protocol, via a call to our eltLoanFree().*/static void eltRxDeliver ( ELT_CTRL * pDrvCtrl ) { volatile ELT_FRAME * pFrame; UINT16 length; struct ether_header * pEh; u_char * pData; UINT16 etherType; MBUF * pMbuf;#ifdef ELT_DEBUG printf ("Elt: Handling received packet.\n"); fflush (stdout);#endif /* ELT_DEBUG */ do { pDrvCtrl->rxHandling = TRUE; while ( ( (pFrame = pDrvCtrl->pRxHead) != NULL) && (pFrame->length != 0)) { pDrvCtrl->pRxHead = pFrame->lNext; length = pFrame->count - EH_SIZE; pEh = (struct ether_header *)pFrame->header; pData = (u_char *) pFrame->data; etherType = ntohs (pEh->ether_type); /* Service input hook */ if (etherInputHookRtn != NULL) { if ( (* etherInputHookRtn) (&pDrvCtrl->idr, (char *)pEh, length) ) { eltRxFree (pDrvCtrl, (ELT_FRAME *)pFrame); continue; } }#ifdef ELT_DEBUG printf ("elt: rxDeliver: frame at %08lx, type %04x, length %d, count %d\n", (long) pFrame, etherType, pFrame->length, pFrame->count);#endif /* ELT_DEBUG */ /* we can loan out receive frames from our pool if: * * 1) we have enough (nLoanFrames > 0) and * 2) size of the input ethernet frame is large enough to be used * with clustering. */ pFrame->refCnt = 0; if ( (pDrvCtrl->nLoanFrames > 0) && (USE_CLUSTER (length)) && ( (pMbuf = build_cluster (pData, length, &pDrvCtrl->idr, MC_EI, &pFrame->refCnt, eltLoanFree, (int) pDrvCtrl, (int) pFrame, NULL)) != NULL)) { pDrvCtrl->nLoanFrames -= 1; /* one less to loan */ } else { pMbuf = copy_to_mbufs (pData, length, 0, &pDrvCtrl->idr); eltRxFree (pDrvCtrl, (ELT_FRAME *)pFrame); } /* deliver mbufs to protocol */#ifdef BSD43_DRIVER if (pMbuf != NULL) do_protocol_with_type (etherType, pMbuf, &pDrvCtrl->idr,length);#else if (pMbuf != NULL) do_protocol (pEh, pMbuf, &pDrvCtrl->idr, length);#endif else ++pDrvCtrl->idr.ac_if.if_ierrors; } pDrvCtrl->rxHandling = FALSE; /* allow self to be rescheduled */ } while ( ( (pFrame = pDrvCtrl->pRxHead) != NULL) && (pFrame->length != 0));#ifdef ELT_TIMING --pDrvCtrl->eltStat.taskQRxOuts;#endif /* ELT_TIMING */ }/********************************************************************************* eltLoanFree - return a loaned receive frame buffer** This routine is called by the protocol code when it has completed use of* a frame buffer that we loaned to it.*/static void eltLoanFree ( ELT_CTRL * pDrvCtrl, ELT_FRAME * pFrame ) { eltRxFree (pDrvCtrl, pFrame); pDrvCtrl->nLoanFrames += 1; /* one more to loan */ }/********************************************************************************* eltRxFree - free a received frame buffer** Reinitialize necessary fields in the frame structure and link it to the* tail of the free frames list. If there was no current frame (the receive* routine had run out of empty buffers), make this the current frame and* unmask receive interrupts in case they were waiting for a buffer.*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -