From e95bc9d8f95ddf1d7c4cbc4ceb7c822b02fde1cf Mon Sep 17 00:00:00 2001 From: Ali Saidi Date: Tue, 27 Mar 2007 20:44:21 -0400 Subject: some more fixes... non-tso stuff seems to work --HG-- extra : convert_revision : da604d20443376d04826397d0aaff0bdd744053b --- src/dev/i8254xGBe.cc | 101 ++++++++++++++++++++++++++++------------------ src/dev/i8254xGBe.hh | 54 +++++++++++++++++++------ src/dev/i8254xGBe_defs.hh | 2 +- 3 files changed, 105 insertions(+), 52 deletions(-) (limited to 'src/dev') diff --git a/src/dev/i8254xGBe.cc b/src/dev/i8254xGBe.cc index c38a9e873..60ea45a60 100644 --- a/src/dev/i8254xGBe.cc +++ b/src/dev/i8254xGBe.cc @@ -57,8 +57,8 @@ using namespace Net; IGbE::IGbE(Params *p) : PciDev(p), etherInt(NULL), useFlowControl(p->use_flow_control), rxFifo(p->rx_fifo_size), txFifo(p->tx_fifo_size), rxTick(false), - txTick(false), rdtrEvent(this), radvEvent(this), tadvEvent(this), - tidvEvent(this), tickEvent(this), interEvent(this), + txTick(false), txFifoTick(false), rdtrEvent(this), radvEvent(this), + tadvEvent(this), tidvEvent(this), tickEvent(this), interEvent(this), rxDescCache(this, name()+".RxDesc", p->rx_desc_cache_size), txDescCache(this, name()+".TxDesc", p->tx_desc_cache_size), clock(p->clock) { @@ -223,6 +223,7 @@ IGbE::read(PacketPtr pkt) pkt->set(regs.rdtr()); if (regs.rdtr.fpd()) { rxDescCache.writeback(0); + DPRINTF(EthernetIntr, "Posting interrupt because of RDTR.FPD write\n"); postInterrupt(IT_RXT); regs.rdtr.fpd(0); } @@ -411,6 +412,7 @@ IGbE::write(PacketPtr pkt) regs.itr = val; break; case REG_ICS: + DPRINTF(EthernetIntr, "Posting interrupt because of ICS write\n"); postInterrupt((IntTypes)val); break; case REG_IMS: @@ -429,6 +431,7 @@ IGbE::write(PacketPtr pkt) regs.rctl = val; if (regs.rctl.rst()) { rxDescCache.reset(); + DPRINTF(EthernetSM, "RXS: Got RESET!\n"); rxFifo.clear(); regs.rctl.rst(0); } @@ -568,8 +571,8 @@ IGbE::postInterrupt(IntTypes t, bool now) } else { DPRINTF(EthernetIntr, "EINT: Scheduling timer interrupt for %d ticks\n", Clock::Int::ns * 256 * regs.itr.interval()); - assert(!interEvent.scheduled()); - interEvent.schedule(curTick + Clock::Int::ns * 256 * regs.itr.interval()); + if (!interEvent.scheduled()) + interEvent.schedule(curTick + Clock::Int::ns * 256 * regs.itr.interval()); } } } @@ -676,39 +679,39 @@ IGbE::RxDescCache::pktComplete() // no support for anything but starting at 0 assert(igbe->regs.rxcsum.pcss() == 0); - DPRINTF(EthernetDesc, "RxDesc: Packet written to memory updating Descriptor\n"); + DPRINTF(EthernetDesc, "Packet written to memory updating Descriptor\n"); uint8_t status = RXDS_DD | RXDS_EOP; uint8_t err = 0; IpPtr ip(pktPtr); if (ip) { if (igbe->regs.rxcsum.ipofld()) { - DPRINTF(EthernetDesc, "RxDesc: Checking IP checksum\n"); + DPRINTF(EthernetDesc, "Checking IP checksum\n"); status |= RXDS_IPCS; desc->csum = htole(cksum(ip)); if (cksum(ip) != 0) { err |= RXDE_IPE; - DPRINTF(EthernetDesc, "RxDesc: Checksum is bad!!\n"); + DPRINTF(EthernetDesc, "Checksum is bad!!\n"); } } TcpPtr tcp(ip); if (tcp && igbe->regs.rxcsum.tuofld()) { - DPRINTF(EthernetDesc, "RxDesc: Checking TCP checksum\n"); + DPRINTF(EthernetDesc, "Checking TCP checksum\n"); status |= RXDS_TCPCS; desc->csum = htole(cksum(tcp)); if (cksum(tcp) != 0) { - DPRINTF(EthernetDesc, "RxDesc: Checksum is bad!!\n"); + DPRINTF(EthernetDesc, "Checksum is bad!!\n"); err |= RXDE_TCPE; } } UdpPtr udp(ip); if (udp && igbe->regs.rxcsum.tuofld()) { - DPRINTF(EthernetDesc, "RxDesc: Checking UDP checksum\n"); + DPRINTF(EthernetDesc, "Checking UDP checksum\n"); status |= RXDS_UDPCS; desc->csum = htole(cksum(udp)); if (cksum(tcp) != 0) { - DPRINTF(EthernetDesc, "RxDesc: Checksum is bad!!\n"); + DPRINTF(EthernetDesc, "Checksum is bad!!\n"); err |= RXDE_TCPE; } } @@ -748,10 +751,12 @@ IGbE::RxDescCache::pktComplete() // If the packet is small enough, interrupt appropriately // I wonder if this is delayed or not?! - if (pktPtr->length <= igbe->regs.rsrpd.idv()) + if (pktPtr->length <= igbe->regs.rsrpd.idv()) { + DPRINTF(EthernetSM, "RXS: Posting IT_SRPD beacuse small packet received\n"); igbe->postInterrupt(IT_SRPD); + } - DPRINTF(EthernetDesc, "RxDesc: Processing of this descriptor complete\n"); + DPRINTF(EthernetDesc, "Processing of this descriptor complete\n"); unusedCache.pop_front(); usedCache.push_back(desc); pktPtr = NULL; @@ -792,10 +797,10 @@ IGbE::TxDescCache::getPacketSize() TxDesc *desc; - DPRINTF(EthernetDesc, "TxDesc: Starting processing of descriptor\n"); + DPRINTF(EthernetDesc, "Starting processing of descriptor\n"); while (unusedCache.size() && TxdOp::isContext(unusedCache.front())) { - DPRINTF(EthernetDesc, "TxDesc: Got context descriptor type... skipping\n"); + DPRINTF(EthernetDesc, "Got context descriptor type... skipping\n"); // I think we can just ignore these for now? desc = unusedCache.front(); @@ -813,7 +818,7 @@ IGbE::TxDescCache::getPacketSize() if (!unusedCache.size()) return -1; - DPRINTF(EthernetDesc, "TxDesc: Next TX packet is %d bytes\n", + DPRINTF(EthernetDesc, "Next TX packet is %d bytes\n", TxdOp::getLen(unusedCache.front())); return TxdOp::getLen(unusedCache.front()); @@ -833,7 +838,7 @@ IGbE::TxDescCache::getPacketData(EthPacketPtr p) pktWaiting = true; - DPRINTF(EthernetDesc, "TxDesc: Starting DMA of packet\n"); + DPRINTF(EthernetDesc, "Starting DMA of packet\n"); igbe->dmaRead(igbe->platform->pciToDma(TxdOp::getBuf(desc)), TxdOp::getLen(desc), &pktEvent, p->data + hLen); @@ -848,7 +853,7 @@ IGbE::TxDescCache::pktComplete() assert(unusedCache.size()); assert(pktPtr); - DPRINTF(EthernetDesc, "TxDesc: DMA of packet complete\n"); + DPRINTF(EthernetDesc, "DMA of packet complete\n"); desc = unusedCache.front(); @@ -865,7 +870,7 @@ IGbE::TxDescCache::pktComplete() pktWaiting = false; pktPtr = NULL; - DPRINTF(EthernetDesc, "TxDesc: Partial Packet Descriptor Done\n"); + DPRINTF(EthernetDesc, "Partial Packet Descriptor Done\n"); return; } @@ -888,33 +893,33 @@ IGbE::TxDescCache::pktComplete() // Checksums are only ofloaded for new descriptor types if (TxdOp::isData(desc) && ( TxdOp::ixsm(desc) || TxdOp::txsm(desc)) ) { - DPRINTF(EthernetDesc, "TxDesc: Calculating checksums for packet\n"); + DPRINTF(EthernetDesc, "Calculating checksums for packet\n"); IpPtr ip(pktPtr); if (TxdOp::ixsm(desc)) { ip->sum(0); ip->sum(cksum(ip)); - DPRINTF(EthernetDesc, "TxDesc: Calculated IP checksum\n"); + DPRINTF(EthernetDesc, "Calculated IP checksum\n"); } if (TxdOp::txsm(desc)) { if (isTcp) { TcpPtr tcp(ip); tcp->sum(0); tcp->sum(cksum(tcp)); - DPRINTF(EthernetDesc, "TxDesc: Calculated TCP checksum\n"); + DPRINTF(EthernetDesc, "Calculated TCP checksum\n"); } else { UdpPtr udp(ip); udp->sum(0); udp->sum(cksum(udp)); - DPRINTF(EthernetDesc, "TxDesc: Calculated UDP checksum\n"); + DPRINTF(EthernetDesc, "Calculated UDP checksum\n"); } } } if (TxdOp::ide(desc)) { // Deal with the rx timer interrupts - DPRINTF(EthernetDesc, "TxDesc: Descriptor had IDE set\n"); + DPRINTF(EthernetDesc, "Descriptor had IDE set\n"); if (igbe->regs.tidv.idv()) { - DPRINTF(EthernetDesc, "TxDesc: setting tidv\n"); + DPRINTF(EthernetDesc, "setting tidv\n"); if (igbe->tidvEvent.scheduled()) igbe->tidvEvent.reschedule(curTick + igbe->regs.tidv.idv() * igbe->intClock()); @@ -924,7 +929,7 @@ IGbE::TxDescCache::pktComplete() } if (igbe->regs.tadv.idv() && igbe->regs.tidv.idv()) { - DPRINTF(EthernetDesc, "TxDesc: setting tadv\n"); + DPRINTF(EthernetDesc, "setting tadv\n"); if (!igbe->tadvEvent.scheduled()) igbe->tadvEvent.schedule(curTick + igbe->regs.tadv.idv() * igbe->intClock()); @@ -940,13 +945,13 @@ IGbE::TxDescCache::pktComplete() pktPtr = NULL; hLen = 0; - DPRINTF(EthernetDesc, "TxDesc: Descriptor Done\n"); + DPRINTF(EthernetDesc, "Descriptor Done\n"); if (igbe->regs.txdctl.wthresh() == 0) { - DPRINTF(EthernetDesc, "TxDesc: WTHRESH == 0, writing back descriptor\n"); + DPRINTF(EthernetDesc, "WTHRESH == 0, writing back descriptor\n"); writeback(0); } else if (igbe->regs.txdctl.wthresh() >= usedCache.size()) { - DPRINTF(EthernetDesc, "TxDesc: used > WTHRESH, writing back descriptor\n"); + DPRINTF(EthernetDesc, "used > WTHRESH, writing back descriptor\n"); writeback((igbe->cacheBlockSize()-1)>>4); } @@ -998,8 +1003,10 @@ IGbE::txStateMachine() bool success; DPRINTF(EthernetSM, "TXS: packet placed in TX FIFO\n"); success = txFifo.push(txPacket); + txFifoTick = true; assert(success); txPacket = NULL; + txDescCache.writeback((cacheBlockSize()-1)>>4); return; } @@ -1021,6 +1028,7 @@ IGbE::txStateMachine() txDescCache.writeback(0); txTick = false; postInterrupt(IT_TXQE, true); + return; } @@ -1038,11 +1046,17 @@ IGbE::txStateMachine() "DMA of next packet\n", size); txFifo.reserve(size); txDescCache.getPacketData(txPacket); - } else { + } else if (size <= 0) { DPRINTF(EthernetSM, "TXS: No packets to get, writing back used descriptors\n"); txDescCache.writeback(0); + } else { + DPRINTF(EthernetSM, "TXS: FIFO full, stopping ticking until space " + "available in FIFO\n"); + txDescCache.writeback((cacheBlockSize()-1)>>4); + txTick = false; } + return; } } @@ -1095,9 +1109,9 @@ IGbE::rxStateMachine() } if (descLeft == 0) { - DPRINTF(EthernetSM, "RXS: No descriptors left in ring, forcing writeback\n"); + DPRINTF(EthernetSM, "RXS: No descriptors left in ring, forcing" + " writeback and stopping ticking\n"); rxDescCache.writeback(0); - DPRINTF(EthernetSM, "RXS: No descriptors left, stopping ticking\n"); rxTick = false; } @@ -1119,9 +1133,9 @@ IGbE::rxStateMachine() } if (rxDescCache.descUnused() == 0) { - DPRINTF(EthernetSM, "RXS: No descriptors available in cache, stopping ticking\n"); + DPRINTF(EthernetSM, "RXS: No descriptors available in cache, " + "fetching descriptors and stopping ticking\n"); rxTick = false; - DPRINTF(EthernetSM, "RXS: Fetching descriptors because none available\n"); rxDescCache.fetchDescriptors(); } return; @@ -1159,15 +1173,18 @@ void IGbE::txWire() { if (txFifo.empty()) { + txFifoTick = false; return; } - txTick = true; if (etherInt->sendPacket(txFifo.front())) { DPRINTF(Ethernet, "TxFIFO: Successful transmit, bytes in fifo: %d\n", txFifo.avail()); txFifo.pop(); + } else { + // We'll get woken up when the packet ethTxDone() gets called + txFifoTick = false; } } @@ -1180,20 +1197,26 @@ IGbE::tick() if (rxTick) rxStateMachine(); - if (txTick) { + if (txTick) txStateMachine(); + + if (txFifoTick) txWire(); - } - if (rxTick || txTick) + + if (rxTick || txTick || txFifoTick) tickEvent.schedule(curTick + cycles(1)); } void IGbE::ethTxDone() { - // restart the state machines if they are stopped + // restart the tx state machines if they are stopped + // fifo to send another packet + // tx sm to put more data into the fifo + txFifoTick = true; txTick = true; + restartClock(); DPRINTF(Ethernet, "TxFIFO: Transmission complete\n"); } diff --git a/src/dev/i8254xGBe.hh b/src/dev/i8254xGBe.hh index a2b9f38d5..3304f0862 100644 --- a/src/dev/i8254xGBe.hh +++ b/src/dev/i8254xGBe.hh @@ -76,24 +76,44 @@ class IGbE : public PciDev // Should to Rx/Tx State machine tick? bool rxTick; bool txTick; + bool txFifoTick; // Event and function to deal with RDTR timer expiring - void rdtrProcess() { rxDescCache.writeback(0); postInterrupt(iGbReg::IT_RXT, true); } + void rdtrProcess() { + rxDescCache.writeback(0); + DPRINTF(EthernetIntr, "Posting RXT interrupt because RDTR timer expired\n"); + postInterrupt(iGbReg::IT_RXT, true); + } + //friend class EventWrapper; EventWrapper rdtrEvent; // Event and function to deal with RADV timer expiring - void radvProcess() { rxDescCache.writeback(0); postInterrupt(iGbReg::IT_RXT, true); } + void radvProcess() { + rxDescCache.writeback(0); + DPRINTF(EthernetIntr, "Posting RXT interrupt because RADV timer expired\n"); + postInterrupt(iGbReg::IT_RXT, true); + } + //friend class EventWrapper; EventWrapper radvEvent; // Event and function to deal with TADV timer expiring - void tadvProcess() { postInterrupt(iGbReg::IT_TXDW, true); } + void tadvProcess() { + txDescCache.writeback(0); + DPRINTF(EthernetIntr, "Posting TXDW interrupt because TADV timer expired\n"); + postInterrupt(iGbReg::IT_TXDW, true); + } + //friend class EventWrapper; EventWrapper tadvEvent; // Event and function to deal with TIDV timer expiring - void tidvProcess() { postInterrupt(iGbReg::IT_TXDW, true); }; + void tidvProcess() { + txDescCache.writeback(0); + DPRINTF(EthernetIntr, "Posting TXDW interrupt because TIDV timer expired\n"); + postInterrupt(iGbReg::IT_TXDW, true); + } //friend class EventWrapper; EventWrapper tidvEvent; @@ -202,8 +222,10 @@ class IGbE : public PciDev */ void areaChanged() { - if (usedCache.size() > 0 || unusedCache.size() > 0) + if (usedCache.size() > 0 || curFetching || wbOut) panic("Descriptor Address, Length or Head changed. Bad\n"); + reset(); + } void writeback(Addr aMask) @@ -229,7 +251,7 @@ class IGbE : public PciDev moreToWb = false; wbAlignment = aMask; - if (max_to_wb + curHead > descLen()) { + if (max_to_wb + curHead >= descLen()) { max_to_wb = descLen() - curHead; moreToWb = true; // this is by definition aligned correctly @@ -265,10 +287,14 @@ class IGbE : public PciDev */ void fetchDescriptors() { - size_t max_to_fetch = descTail() - cachePnt; - if (max_to_fetch < 0) + size_t max_to_fetch; + + if (descTail() >= cachePnt) + max_to_fetch = descTail() - cachePnt; + else max_to_fetch = descLen() - cachePnt; + max_to_fetch = std::min(max_to_fetch, (size - usedCache.size() - unusedCache.size())); @@ -311,8 +337,9 @@ class IGbE : public PciDev #endif cachePnt += curFetching; - if (cachePnt > descLen()) - cachePnt -= descLen(); + assert(cachePnt <= descLen()); + if (cachePnt == descLen()) + cachePnt = 0; curFetching = 0; @@ -337,8 +364,8 @@ class IGbE : public PciDev curHead += wbOut; wbOut = 0; - if (curHead > descLen()) - curHead = 0; + if (curHead >= descLen()) + curHead -= descLen(); // Update the head updateHead(curHead); @@ -390,6 +417,9 @@ class IGbE : public PciDev usedCache.clear(); unusedCache.clear(); + + cachePnt = 0; + } }; diff --git a/src/dev/i8254xGBe_defs.hh b/src/dev/i8254xGBe_defs.hh index 8538c155b..6820b96c4 100644 --- a/src/dev/i8254xGBe_defs.hh +++ b/src/dev/i8254xGBe_defs.hh @@ -162,7 +162,7 @@ struct TxDesc { namespace TxdOp { const uint8_t TXD_CNXT = 0x0; -const uint8_t TXD_DATA = 0x0; +const uint8_t TXD_DATA = 0x1; bool isLegacy(TxDesc *d) { return !bits(d->d2,29,29); } uint8_t getType(TxDesc *d) { return bits(d->d2, 23,20); } -- cgit v1.2.3