📄 net_3c509.cxx
字号:
} bool haveRoom = (txFree >= inv.entry.len); if (haveRoom) { /* Send the packet length: ?? why not out32 ?? */ out16(inv.entry.len, ni->ioAddr + Wn1TxFifo); out16(0x0, ni->ioAddr + Wn1TxFifo); IoWrPkt(ni, inv.entry.data, inv.entry.len);#if 0 MsgLog::printf("Written packet\n");#endif inv.exit.code = RC_OK; uint64_t ew = rdtsc(); ew -= dw; ni->stats.txCpuCycles += ew; } /* 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(); }}#define INPUT_ALIGN 0x3/* 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(); /* MsgLog::printf("Call to ReadPacket()\n"); */ 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); /* We have skipped past all the bad packets. If a good packet * remains, yank it off the FIFO, acknowledge it, and return. * Otherwise, enable the RxComplete interrupt and go back to sleep. */ if ( (rx_status & RxsIncomplete) == 0) { uint16_t len = rx_status & Rxsuint8_ts; /* We know that the input buffer is aligned and also that it is * of sufficient size: */ ins32(ni->ioAddr + Wn1RxFifo, inv.exit.data, (len+3) >> 2); ni->stats.rxPackets++; inv.exit.len = len; inv.exit.code = RC_OK; OutCmd(ni, RxDiscard, true); rx_status = in16(ni->ioAddr + Wn1RxStatus); if ((rx_status & RxsIncomplete) == 0 && ((rx_status & RxsError) == 0)) ni->stats.rxMore++;#if 0 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; } ni->stats.rdStall++; 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;}/* 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++) {#if 0 MsgLog::dprintf(true, "entvec=0x%08x, exvec=0x%08x\n", curEntryVec, curExitVec);#endif do { rx_status = in16(ni->ioAddr + Wn1RxStatus); if (rx_status & RxsIncomplete) { if (haveData) {#undef exitVec#ifdef VERBOSE MsgLog::dprintf(false, "Return w/ curX=0x%08x tmpX=0x%08x X=0x%08x\n", curExitVec, &tmpExitVec[1], &exitVec); int count = curExitVec - tmpExitVec; count--; MsgLog::dprintf(true, "Return w/ %d pkts\n", count);#endif /* Copy out to the REAL exit vec: */ bcopy(&tmpExitVec, exitVec, tmpExitVec[0].len);#define exitVec foobar uint64_t ew = rdtsc(); ew -= dw; ni->stats.rxCpuCycles += ew; return; } /* Else wait for at least one packet. */ ni->stats.rdStall++; Thread::Current()->SleepOn(ni->rdQ);#ifdef VERBOSE MsgLog::printf("Waiting for pkt on %s\n", ni->info.name);#endif ni->curInts |= RxComplete; OutCmd(ni, SetIntrMask | ni->curInts); Thread::Current()->Yield(); } if (rx_status & RxsError) { MsgLog::printf("Skipping bad pkt\n"); SkipBadRxPackets(ni); } } while (rx_status & RxsError); uint16_t len = rx_status & Rxsuint8_ts; curExitVec->len = len; /* We know that the input buffer is aligned and also that it is * of sufficient size: */ ins32(ni->ioAddr + Wn1RxFifo, inv.exit.data + curExitVec->offset, (len+3) >> 2); ni->stats.rxPackets++; haveData = true; OutCmd(ni, RxDiscard, true); } rx_status = in16(ni->ioAddr + Wn1RxStatus); if ((rx_status & RxsIncomplete) == 0 && ((rx_status & RxsError) == 0)) ni->stats.rxMore++;#undef exitVec#ifdef VERBOSE MsgLog::dprintf(true, "%s (3c509): Drop out w/ %d pkts\n", ni->name, curExitVec - &tmpExitVec[1]);#endif /* Copy out to the REAL exit vec: */ bcopy(&tmpExitVec, exitVec, tmpExitVec[0].len); uint64_t ew = rdtsc(); ew -= dw; ni->stats.rxCpuCycles += ew;}static inline voidHandleInterrupt(NetInterface * ni){ uint8_t status; /* Status is accessable from every window */ for (;;) { status = in16(ni->ioAddr + El3Status); if ( (status & (IntLatch | (RxComplete&ni->curInts) | UpdateStats)) == 0) break; /* Only run RxPacket if we are supposed to be accepting RX interrupts: */ if (status & RxComplete & ni->curInts) RxPacket(ni); if (status & TxAvail) { ni->watchDog.Disarm(); ni->wrQ.WakeAll();#ifdef ENET_DEBUG MsgLog::printf("Got txAvail intr\n");#endif OutCmd(ni, AckIntr | TxAvail); } if ( status & (AdapterFail | RxEarly | UpdateStats) ) { if (status & UpdateStats) UpdateStatistics(ni); if (status & RxEarly) MsgLog::fatal("RxEarly interrupt\n"); if (status & AdapterFail) { /* Reset receiver and re-init the adapter: */ OutCmd(ni, RxReset); /* Reset the RX filter to current settings: */ OutCmd(ni, SetRxFilter | ni->rxFilter); /* Re-enable the RX FIFO: */ OutCmd(ni, RxEnable); /* Ack this part of the interrupt: */ OutCmd(ni, AckIntr | AdapterFail); } } /* Acknowledge the interrupt: */ OutCmd(ni, AckIntr | IntRequested | IntLatch); } /* MsgLog::dprintf(true, "3c509: Unrecognized intr, status=0x%04x\n", status); */}static voidHandleInterrupt(IntAction *ia){ /* Previous interrupt architecture line. Left in for reference. * EL3Type *elink = EL3Type::FindCard(interfaces[0]->irq); */ NetInterface* ni = (NetInterface*) ia->drvr_ptr; HandleInterrupt(ni);}static voidEnable(NetInterface * ni){ if (ni->info.niStatus & NI_ENABLED) return; if ( (ni->info.niStatus & NI_ATTACHED) == 0 ) return; /* This is EXACTLY as written in the el3_open routine from linux: */ OutCmd(ni, TxReset, true); /* long-running cmd */ OutCmd(ni, RxReset); OutCmd(ni, SetStatusMask | 0x0); /* DISABLES INTERRUPTS */ uint32_t picen = IRQ::GetEnableMaskFromPIC(); MsgLog::printf("PICEN=0x%08x. Enable interrupt %d\n", picen, ni->irq); IRQ::Enable(ni->irq); picen = IRQ::GetEnableMaskFromPIC(); MsgLog::printf("PICEN=0x%08x\n", picen);#if 0 (void) /* uint32_t probeirq = */ IRQ::BeginProbe();#endif SetWindow(ni, 0); /* Enable the adapter: */ out16(0x1, ni->ioAddr + Wn0ConfigCtrl); /* Set the adaptor IRQ: */ out16(ni->irq << 12 | 0x0f00, ni->ioAddr + Wn0Irq); /* Set the station address: */ SetWindow(ni, 2); for (int i = 0; i < 6; i++) out8(ni->info.niAddr[i], ni->ioAddr + i); /* Activate the transceiver: */ switch(ni->xcvr) { case XcvrTwistedPair: { /* Enable link beat and jabber. */ SetWindow(ni, 4); uint16_t curStatus = inh(ni->ioAddr + Wn4MediaType); curStatus |= MediaStatusLK | MediaStatusJE; out16(curStatus, ni->ioAddr + Wn4MediaType); OutCmd(ni, StopCoax); break; } case XcvrAUI: /* AUI port enabled. Using external transceiver. */ break; case XcvrReserved: MsgLog::fatal("This adapter has a bad setting for the selected " "transceiver.\nRerun the accompanying 3Com setup " "program.\n"); break; case XcvrBNC: /* Output start coaxial transceiver command. */ OutCmd(ni, StartCoax); /* In theory, we ought to delay here, but the lost packets are * okay on an ethernet... */ break; default: MsgLog::fatal("Bad xcvr type %d\n", ni->xcvr); break; } /* Clear out the statistics buffers: */ OutCmd(ni, StatsDisable); SetWindow(ni, 6); for (int i = 0; i < 9; i++) in8(ni->ioAddr + i); in16(ni->ioAddr + 10); in16(ni->ioAddr + 12); SetWindow(ni, 1); /* Set RX filter to accept individual and broadcast addresses: */ ni->rxFilter = RxIndividual | RxBroadcast; ni->info.niStatus |= NI_BROADCAST | NI_STATION; OutCmd(ni, SetRxFilter | ni->rxFilter); OutCmd(ni, StatsEnable); /* Enable TX and RX. */ OutCmd(ni, RxEnable); OutCmd(ni, TxEnable); OutCmd(ni, SetStatusMask | 0xff); /* Ack all pending events, and set active interrupt mask */ OutCmd(ni, AckIntr | IntLatch | TxAvail | RxEarly | IntRequested); /* Note: NOT RxComplete or RxEarly! */ ni->curInts = TxAvail | UpdateStats | IntLatch; OutCmd(ni, SetIntrMask | ni->curInts); Machine::SpinWaitMs(1);}static voidUpdateStatistics(NetInterface *ni){ IRQ::DISABLE(); OutCmd(ni, StatsDisable); SetWindow(ni, 6); ni->stats.txCarrierErrors += in8(ni->ioAddr + 0); ni->stats.txHeartbeatErrors += in8(ni->ioAddr + 1); /* multiple collisions */ (void) in8(ni->ioAddr + 2); ni->stats.collisions += in8(ni->ioAddr + 3); ni->stats.txWindowErrors += in8(ni->ioAddr + 4); ni->stats.rxFifoErrors += in8(ni->ioAddr + 5); ni->stats.txPackets += in8(ni->ioAddr + 6); /* rxPackets */ (void) in8(ni->ioAddr + 7); /* txDeferrals */ (void) in8(ni->ioAddr + 8); /* FIX: What about byt 9??? */ /* total RX octets */ (void) in16(ni->ioAddr + 10); /* total TX octets */ (void) in16(ni->ioAddr + 12); SetWindow(ni, 1); OutCmd(ni, StatsEnable); IRQ::ENABLE();}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -