📄 net_3c59x.cxx
字号:
continue; } if (ni->updateStats != UpdateStatistics) { continue; } ni_Attach(ni); } return true;}#define SUPER_SLOW_MOstatic voidHydrant(Timer* t){ NetInterface *ni = (NetInterface *) t->client_ptr; SetWindow(ni, 1);#if 0#ifdef BOOMERANG MsgLog::dprintf(false, "%s: UpStatus 0x%08x DnStatus 0x%08x\n", ni->name, in32(ni->ioAddr + Wn1UpStatus), in32(ni->ioAddr + Wn1DnStatus));#endif MsgLog::dprintf(false, "%s: elink (xmit?) timeout. TxStatus: 0x%02x" " Status 0x%04x\n txFifo room %d rxStatus 0x%x curInts 0x%x\n", ni->name, in8(ni->ioAddr + Wn1TxStatus), in16(ni->ioAddr + El3Status), in16(ni->ioAddr + Wn1TxFree), in16(ni->ioAddr + Wn1RxStatus), ni->curInts);#endif OutCmd(ni, ReqIntr); /* long-running cmd */ ni->stats.txWatchdog++; OutCmd(ni, TxReset, true); /* long-running cmd */ OutCmd(ni, TxEnable); ni->wrQ.WakeAll();}inline static voidClearTxStatusStack(NetInterface *ni){ uint16_t tx_status = 0; int i = 4; while (--i > 0 && (tx_status = in8(ni->ioAddr + Wn1TxStatus)) > 0) {#if 1 if (tx_status & 0x3C) { /* A Tx-disabling error occurred. */ if (vortex_debug > 2) MsgLog::dprintf(true, "%s: Tx error, status 0x%2x.\n", ni->name, tx_status); if (tx_status & 0x04) {#if 0 ni->stats.txFifoErrors++;#endif vortex_private *vp = (vortex_private *) ni->private; vp->txStartThresh += 16; MsgLog::printf("!!Growing start threshold\n"); OutCmd(ni, SetTxStartThresh | vp->txStartThresh); } if (tx_status & 0x38) ni->stats.txAbort++; if (tx_status & 0x34) OutCmd(ni, TxReset, true); OutCmd(ni, TxEnable); }#else /* This generates printfs on collisions, which happens with acks. * MsgLog::printf("3c509: tx_status = 0x%08x\n", tx_status); */ if (tx_status & (TxsJabber | TxsUnderrun | TxsCollisions)) ni->stats.txAbort++; if (tx_status & (TxsJabber|TxsUnderrun)) OutCmd(ni, TxReset, true); if (tx_status & (TxsJabber|TxsUnderrun|TxsCollisions|TxsStatusOverflow)) OutCmd(ni, TxEnable);#endif /* Pop the status stack. */ out8(0x00, ni->ioAddr + Wn1TxStatus); }}inline voidIoWrPkt(NetInterface *ni, uint8_t *buf, uint32_t len){ /* Begin sending the packet, but be careful about send buffer * alignment: */ assert (((uint32_t)buf&3) == 0); /* sndBufPtr is now word aligned. Send as many words as we can: */ outs32(ni->ioAddr + Wn1TxFifo, buf, (len+3) >> 2);}static voidWritePacket(NetInterface * ni, Invocation& inv){ uint64_t dw = rdtsc(); ClearTxStatusStack(ni);#ifdef SUPER_SLOW_MO /* I/O version -- do this first to get something running quickly. */ /* See if the TX Fifo has room for the outbound packet: */ uint16_t txFree = in16(ni->ioAddr + Wn1TxFree);#if 0 MsgLog::printf("inv.entry.len=%d\n", inv.entry.len);#endif bool haveRoom = (txFree >= inv.entry.len); if (inv.entry.len < MIN_ENET_PACKET_SZ || inv.entry.len > MAX_ENET_PACKET_SZ) { /* input buffer not aligned properly. */ inv.exit.code = RC_RequestError; return; } if (haveRoom) { /* Put out the doubleword header... */ out32(inv.entry.len, ni->ioAddr + Wn1TxFifo); IoWrPkt(ni, inv.entry.data, inv.entry.len); inv.exit.code = RC_OK; uint64_t ew = rdtsc(); ew -= dw; ni->stats.txCpuCycles += ew; }#else#endif /* Sleep if we are supposed to: */ if (!haveRoom) {#ifdef ENET_DEBUG MsgLog::printf("net_wr: txFree: %d, pkt-len %d, sleeping\n", txFree, inv.entry.len);#endif /* Wake us up when there is sufficient room in the TX FIFO for a * complete enet packet: */ ni->stats.wrStall++; ni->watchDog.Disarm(); ni->watchDog.WakeupIn(500, Hydrant); assert (ni->curInts & TxAvail); OutCmd(ni, SetTxAvailThresh + TX_FIFO_THRESH); Thread::Current()->SleepOn(ni->wrQ); Thread::Current()->Yield(); }}static voidSkipBadRxPackets(NetInterface* ni){ /* The uppermost bit of the rx_status register indicates an * incomplete packet. Since we don't use early RX notification, * this means a runt packet, which should simply be discarded. */ for (;;) { uint16_t rx_status = in16(ni->ioAddr + Wn1RxStatus); if (rx_status & RxsIncomplete) return;#ifdef DEBUG MsgLog::printf("rxskip: rx_status: 0x%04x curint 0x%x\n", rx_status, ni->curInts);#endif /* Keep tossing packets until we find a good one. */ if ((rx_status & RxsError) == 0) break; uint8_t rx_error = inb(ni->ioAddr + Wn1RxErrors); if (rx_error & 0x01) ni->stats.rxOverrun++; if (rx_error & 0x02) ni->stats.rxLengthErrors++; if (rx_error & 0x04) ni->stats.rxFrameErrors++; if (rx_error & 0x08) ni->stats.rxCrcErrors++; if (rx_error & 0x10) ni->stats.rxLengthErrors++; ni->stats.rxDropped++; OutCmd(ni, RxDiscard, true); }}static voidRxPacket(NetInterface *ni){#ifdef DEBUG MsgLog::dprintf(false, "Call to RxPacket()\n");#endif SkipBadRxPackets(ni); uint16_t rx_status = in16(ni->ioAddr + Wn1RxStatus); if ( (rx_status & RxsIncomplete) == 0 ) { /* Disable receive completion interrupts */ ni->curInts &= ~RxComplete; /* MsgLog::printf("Disable RxComplete interrupt\n"); */ OutCmd(ni, SetIntrMask | ni->curInts); ni->rdQ.WakeAll(0, true); } /* Finally, ack this interrupt: */ OutCmd(ni, AckIntr | RxComplete | RxEarly);}#define INPUT_ALIGN 0x7/* ReadPacket logic: * * 1. Skip past all bad packets in the FIFO. * 2. See if there are any remaining packets. * if so, read them * if not, set the RxComplete interrupt bit. * */static voidReadPacket(NetInterface *ni, Invocation& inv){ uint64_t dw = rdtsc(); #ifdef DEBUG MsgLog::dprintf(false, "ReadPacket() on %s\n", ni->name);#endif if ((uint32_t)inv.exit.data & INPUT_ALIGN || inv.validLen < MAX_ENET_PACKET_SZ) { /* input buffer not aligned properly. */ inv.exit.code = RC_RequestError; MsgLog::printf(" Bad format - inv.exit.data=0x%x inv.validLen=%d\n", (uint32_t)inv.exit.data, inv.validLen); return; } SkipBadRxPackets(ni); uint16_t rx_status = in16(ni->ioAddr + Wn1RxStatus); #ifdef DEBUG MsgLog::printf("rdpkt() rxskip: rx_status: 0x%04x curint 0x%x\n", rx_status, ni->curInts);#endif /* MsgLog::printf("Call to ReadPacket()\n"); */ /* The next packet is either good or incomplete: */ if ( (rx_status & RxsIncomplete) == 0 ) { uint16_t len = rx_status & 0x1fff; ins32(ni->ioAddr + Wn1RxFifo, inv.exit.data, (len + 3) >> 2); inv.exit.len = len; inv.exit.code = RC_OK; ni->stats.rxPackets++; OutCmd(ni, RxDiscard, true); rx_status = in16(ni->ioAddr + Wn1RxStatus); if ((rx_status & RxsIncomplete) == 0 && ((rx_status & RxsError) == 0)) ni->stats.rxMore++;#ifdef DEBUG MsgLog::printf(" Got packet on %s, irq %d\n", ni->name, ni->irq);#endif uint64_t ew = rdtsc(); ew -= dw; ni->stats.rxCpuCycles += ew; return; }#ifdef DEBUG MsgLog::printf("reader queues...\n");#endif#if 0 ni->rdStall++; ni->watchDog.Disarm(); ni->watchDog.WakeupIn(500, Hydrant);#endif Thread::Current()->SleepOn(ni->rdQ); /* MsgLog::printf(" Enable RxComplete interrupt\n"); */ ni->curInts |= RxComplete; OutCmd(ni, SetIntrMask | ni->curInts); Thread::Current()->Yield();}inline boolValidIoVec(IoVec* iov, uint32_t n, uint32_t limit){ for (uint32_t i = 0; i < n; i++, iov++) { if (iov->len && (iov->len + iov->offset > limit)) { MsgLog::printf("iov [%d] offset 0x%08x len %d sum 0x%08x limit 0x%08x\n", i, iov->offset, iov->len, iov->offset + iov->len, limit); return false; } /* First entry describes IOV, so don't check that! */ if (i && (iov->len < MAX_ENET_PACKET_SZ)) { MsgLog::printf("iov [%d] offset 0x%08x len %d sum 0x%08x limit 0x%08x\n", i, iov->offset, iov->len, iov->offset + iov->len, limit); return false; } if (iov->offset & INPUT_ALIGN) { /* require word aligned start addr -- * buffer known to be word aligned already */ MsgLog::printf("iov [%d] offset 0x%08x len %d sum 0x%08x limit 0x%08x\n", i, iov->offset, iov->len, iov->offset + iov->len, limit); return false; } } return true;}#ifdef NET_MULTIREAD/* MultiReadPacket almost never wins on 3c509. It's here just for * compatibility with 100Mbit cards. */static voidMultiReadPacket(NetInterface *ni, Invocation& inv){ uint64_t dw = rdtsc(); IoVec *entryVec = (IoVec *) inv.entry.data; if (inv.entry.len < sizeof(IoVec)) { inv.exit.code = RC_RequestError; MsgLog::dprintf(true, " No Send IoVec!!!\n"); return; } uint32_t nEntryVec = entryVec->len / sizeof(IoVec); if ( (entryVec->len % sizeof(IoVec)) || nEntryVec > MAX_IOVEC || (nEntryVec == 0) ) { inv.exit.code = RC_RequestError; MsgLog::dprintf(true, " Bad Send IoVec len %d\n", entryVec->len); return; } if (! ValidIoVec(entryVec, nEntryVec, inv.validLen) ) { inv.exit.code = RC_RequestError; MsgLog::dprintf(true, " Bad Send IoVec (ranges)\n"); return; } IoVec *exitVec = (IoVec *) (entryVec->offset + inv.exit.data); uint32_t nExitVec = entryVec->len / sizeof(IoVec); if ( (uint32_t)inv.exit.data & INPUT_ALIGN ) { /* input buffer not aligned properly. */ inv.exit.code = RC_RequestError; MsgLog::dprintf(true, " misaligned rcv buffer\n"); return; } assert (nExitVec == nEntryVec); IoVec tmpExitVec[MAX_IOVEC]; #define exitVec foobar /* Careful -- must not overwrite if user entryvec == user exitvec. * Don't dork entry 0. */ for (uint32_t i = 1; i < nExitVec; i++) { tmpExitVec[i].offset = entryVec[i].offset; tmpExitVec[i].len = 0; } IoVec *lastEntryVec = entryVec + nEntryVec; /* Exit block descriptor[0] entry block descriptor[0] */ tmpExitVec[0].len = entryVec->len; tmpExitVec[0].offset = entryVec->offset; /* Process starting with slot 1: */ IoVec *curExitVec = tmpExitVec + 1; IoVec *curEntryVec = entryVec + 1; bool haveData = false; /* If we return rather than yield, it will be with ok status from * now on. */ inv.exit.code = RC_OK; inv.exit.len = inv.validLen; uint16_t rx_status; for ( ; curEntryVec != lastEntryVec; curEntryVec++, curExitVec++) { do { rx_status = in16(ni->ioAddr + Wn1RxStatus); if (rx_status & RxsIncomplete) { if (haveData) {#undef exitVec int count = curExitVec - tmpExitVec; count--;#ifdef VERBOSE MsgLog::dprintf(true, "Return w/ %d pkts\n", count);#endif /* Copy out to the REAL exit vec: */ bcopy(&tmpExitVec, exitVec, tmpExitVec[0].len);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -