X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fdev%2Fi8254xGBe.cc;h=0fbda1897a67a37699202450f273bbbf48e66775;hb=27e8f3c98a4b1c56e16ce5f80c7ad992083ccef9;hp=81a111f71277ff5abaac6038ed41b6ca3cf9f9c2;hpb=9791b0f9270695c7bbc552bc4a5f92f40c4e7ec7;p=gem5.git diff --git a/src/dev/i8254xGBe.cc b/src/dev/i8254xGBe.cc index 81a111f71..0fbda1897 100644 --- a/src/dev/i8254xGBe.cc +++ b/src/dev/i8254xGBe.cc @@ -57,10 +57,15 @@ using namespace Net; IGbE::IGbE(const Params *p) : EtherDevice(p), etherInt(NULL), drainEvent(NULL), useFlowControl(p->use_flow_control), rxFifo(p->rx_fifo_size), txFifo(p->tx_fifo_size), rxTick(false), - txTick(false), txFifoTick(false), rxDmaPacket(false), rdtrEvent(this), radvEvent(this), + txTick(false), txFifoTick(false), rxDmaPacket(false), + fetchDelay(p->fetch_delay), wbDelay(p->wb_delay), + fetchCompDelay(p->fetch_comp_delay), wbCompDelay(p->wb_comp_delay), + rxWriteDelay(p->rx_write_delay), txReadDelay(p->tx_read_delay), + 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) + txDescCache(this, name()+".TxDesc", p->tx_desc_cache_size), + clock(p->clock), lastInterrupt(0) { etherInt = new IGbEInt(name() + ".int", this); @@ -580,16 +585,23 @@ IGbE::postInterrupt(IntTypes t, bool now) return; regs.icr = regs.icr() | t; - if (regs.itr.interval() == 0 || now) { + + Tick itr_interval = Clock::Int::ns * 256 * regs.itr.interval(); + DPRINTF(EthernetIntr, "EINT: postInterrupt() curTick: %d itr: %d interval: %d\n", + curTick, regs.itr.interval(), itr_interval); + + if (regs.itr.interval() == 0 || now || lastInterrupt + itr_interval <= curTick) { if (interEvent.scheduled()) { - interEvent.deschedule(); + deschedule(interEvent); } cpuPostInt(); } else { - DPRINTF(EthernetIntr, "EINT: Scheduling timer interrupt for %d ticks\n", - Clock::Int::ns * 256 * regs.itr.interval()); + Tick int_time = lastInterrupt + itr_interval; + assert(int_time > 0); + DPRINTF(EthernetIntr, "EINT: Scheduling timer interrupt for tick %d\n", + int_time); if (!interEvent.scheduled()) { - interEvent.schedule(curTick + Clock::Int::ns * 256 * regs.itr.interval()); + schedule(interEvent, int_time); } } } @@ -605,6 +617,8 @@ void IGbE::cpuPostInt() { + postedInterrupts++; + if (!(regs.icr() & regs.imr)) { DPRINTF(Ethernet, "Interrupt Masked. Not Posting\n"); return; @@ -614,24 +628,24 @@ IGbE::cpuPostInt() if (interEvent.scheduled()) { - interEvent.deschedule(); + deschedule(interEvent); } if (rdtrEvent.scheduled()) { regs.icr.rxt0(1); - rdtrEvent.deschedule(); + deschedule(rdtrEvent); } if (radvEvent.scheduled()) { regs.icr.rxt0(1); - radvEvent.deschedule(); + deschedule(radvEvent); } if (tadvEvent.scheduled()) { regs.icr.txdw(1); - tadvEvent.deschedule(); + deschedule(tadvEvent); } if (tidvEvent.scheduled()) { regs.icr.txdw(1); - tidvEvent.deschedule(); + deschedule(tidvEvent); } regs.icr.int_assert(1); @@ -640,6 +654,7 @@ IGbE::cpuPostInt() intrPost(); + lastInterrupt = curTick; } void @@ -662,7 +677,7 @@ IGbE::chkInterrupt() if (!(regs.icr() & regs.imr)) { DPRINTF(Ethernet, "Mask cleaned all interrupts\n"); if (interEvent.scheduled()) - interEvent.deschedule(); + deschedule(interEvent); if (regs.icr.int_assert()) cpuClearInt(); } @@ -676,7 +691,8 @@ IGbE::chkInterrupt() if (!interEvent.scheduled()) { DPRINTF(Ethernet, "Scheduling for %d\n", curTick + Clock::Int::ns * 256 * regs.itr.interval()); - interEvent.schedule(curTick + Clock::Int::ns * 256 * regs.itr.interval()); + schedule(interEvent, + curTick + Clock::Int::ns * 256 * regs.itr.interval()); } } } @@ -691,7 +707,7 @@ IGbE::RxDescCache::RxDescCache(IGbE *i, const std::string n, int s) { } -bool +void IGbE::RxDescCache::writePacket(EthPacketPtr packet) { // We shouldn't have to deal with any of these yet @@ -699,14 +715,14 @@ IGbE::RxDescCache::writePacket(EthPacketPtr packet) packet->length, igbe->regs.rctl.descSize()); assert(packet->length < igbe->regs.rctl.descSize()); - if (!unusedCache.size()) - return false; + assert(unusedCache.size()); + //if (!unusedCache.size()) + // return false; pktPtr = packet; pktDone = false; igbe->dmaWrite(igbe->platform->pciToDma(unusedCache.front()->buf), - packet->length, &pktEvent, packet->data); - return true; + packet->length, &pktEvent, packet->data, igbe->rxWriteDelay); } void @@ -716,7 +732,6 @@ IGbE::RxDescCache::pktComplete() RxDesc *desc; desc = unusedCache.front(); - uint16_t crcfixup = igbe->regs.rctl.secrc() ? 0 : 4 ; desc->len = htole((uint16_t)(pktPtr->length + crcfixup)); DPRINTF(EthernetDesc, "pktPtr->length: %d stripcrc offset: %d value written: %d %d\n", @@ -741,6 +756,7 @@ IGbE::RxDescCache::pktComplete() DPRINTF(EthernetDesc, "Checking IP checksum\n"); status |= RXDS_IPCS; desc->csum = htole(cksum(ip)); + igbe->rxIpChecksums++; if (cksum(ip) != 0) { err |= RXDE_IPE; DPRINTF(EthernetDesc, "Checksum is bad!!\n"); @@ -751,6 +767,7 @@ IGbE::RxDescCache::pktComplete() DPRINTF(EthernetDesc, "Checking TCP checksum\n"); status |= RXDS_TCPCS; desc->csum = htole(cksum(tcp)); + igbe->rxTcpChecksums++; if (cksum(tcp) != 0) { DPRINTF(EthernetDesc, "Checksum is bad!!\n"); err |= RXDE_TCPE; @@ -762,6 +779,7 @@ IGbE::RxDescCache::pktComplete() DPRINTF(EthernetDesc, "Checking UDP checksum\n"); status |= RXDS_UDPCS; desc->csum = htole(cksum(udp)); + igbe->rxUdpChecksums++; if (cksum(udp) != 0) { DPRINTF(EthernetDesc, "Checksum is bad!!\n"); err |= RXDE_TCPE; @@ -782,21 +800,21 @@ IGbE::RxDescCache::pktComplete() if (igbe->regs.rdtr.delay()) { DPRINTF(EthernetSM, "RXS: Scheduling DTR for %d\n", igbe->regs.rdtr.delay() * igbe->intClock()); - igbe->rdtrEvent.reschedule(curTick + igbe->regs.rdtr.delay() * - igbe->intClock(),true); + igbe->reschedule(igbe->rdtrEvent, + curTick + igbe->regs.rdtr.delay() * igbe->intClock(), true); } - if (igbe->regs.radv.idv() && igbe->regs.rdtr.delay()) { + if (igbe->regs.radv.idv()) { DPRINTF(EthernetSM, "RXS: Scheduling ADV for %d\n", igbe->regs.radv.idv() * igbe->intClock()); if (!igbe->radvEvent.scheduled()) { - igbe->radvEvent.schedule(curTick + igbe->regs.radv.idv() * - igbe->intClock()); + igbe->schedule(igbe->radvEvent, + curTick + igbe->regs.radv.idv() * igbe->intClock()); } } // if neither radv or rdtr, maybe itr is set... - if (!igbe->regs.rdtr.delay()) { + if (!igbe->regs.rdtr.delay() && !igbe->regs.radv.idv()) { DPRINTF(EthernetSM, "RXS: Receive interrupt delay disabled, posting IT_RXT\n"); igbe->postInterrupt(IT_RXT); } @@ -823,8 +841,10 @@ IGbE::RxDescCache::pktComplete() void IGbE::RxDescCache::enableSm() { - igbe->rxTick = true; - igbe->restartClock(); + if (!igbe->drainEvent) { + igbe->rxTick = true; + igbe->restartClock(); + } } bool @@ -918,9 +938,9 @@ IGbE::TxDescCache::getPacketData(EthPacketPtr p) pktWaiting = true; - DPRINTF(EthernetDesc, "Starting DMA of packet\n"); + DPRINTF(EthernetDesc, "Starting DMA of packet at offset %d\n", p->length); igbe->dmaRead(igbe->platform->pciToDma(TxdOp::getBuf(desc)), - TxdOp::getLen(desc), &pktEvent, p->data + p->length); + TxdOp::getLen(desc), &pktEvent, p->data + p->length, igbe->txReadDelay); } @@ -935,25 +955,29 @@ IGbE::TxDescCache::pktComplete() DPRINTF(EthernetDesc, "DMA of packet complete\n"); + desc = unusedCache.front(); assert((TxdOp::isLegacy(desc) || TxdOp::isData(desc)) && TxdOp::getLen(desc)); DPRINTF(EthernetDesc, "TxDescriptor data d1: %#llx d2: %#llx\n", desc->d1, desc->d2); if (!TxdOp::eop(desc)) { - // This only supports two descriptors per tx packet - assert(pktPtr->length == 0); - pktPtr->length = TxdOp::getLen(desc); + pktPtr->length += TxdOp::getLen(desc); unusedCache.pop_front(); usedCache.push_back(desc); pktDone = true; pktWaiting = false; + pktMultiDesc = true; + + DPRINTF(EthernetDesc, "Partial Packet Descriptor of %d bytes Done\n", + pktPtr->length); pktPtr = NULL; - DPRINTF(EthernetDesc, "Partial Packet Descriptor Done\n"); enableSm(); + igbe->checkDrain(); return; } + pktMultiDesc = false; // Set the length of the data in the EtherPacket pktPtr->length += TxdOp::getLen(desc); @@ -985,10 +1009,11 @@ IGbE::TxDescCache::pktComplete() if (TxdOp::isData(desc) && ( TxdOp::ixsm(desc) || TxdOp::txsm(desc)) ) { DPRINTF(EthernetDesc, "Calculating checksums for packet\n"); IpPtr ip(pktPtr); - + assert(ip); if (TxdOp::ixsm(desc)) { ip->sum(0); ip->sum(cksum(ip)); + igbe->txIpChecksums++; DPRINTF(EthernetDesc, "Calculated IP checksum\n"); } if (TxdOp::txsm(desc)) { @@ -997,11 +1022,13 @@ IGbE::TxDescCache::pktComplete() if (tcp) { tcp->sum(0); tcp->sum(cksum(tcp)); + igbe->txTcpChecksums++; DPRINTF(EthernetDesc, "Calculated TCP checksum\n"); } else if (udp) { assert(udp); udp->sum(0); udp->sum(cksum(udp)); + igbe->txUdpChecksums++; DPRINTF(EthernetDesc, "Calculated UDP checksum\n"); } else { panic("Told to checksum, but don't know how\n"); @@ -1014,15 +1041,15 @@ IGbE::TxDescCache::pktComplete() DPRINTF(EthernetDesc, "Descriptor had IDE set\n"); if (igbe->regs.tidv.idv()) { DPRINTF(EthernetDesc, "setting tidv\n"); - igbe->tidvEvent.reschedule(curTick + igbe->regs.tidv.idv() * - igbe->intClock(), true); + igbe->reschedule(igbe->tidvEvent, + curTick + igbe->regs.tidv.idv() * igbe->intClock(), true); } if (igbe->regs.tadv.idv() && igbe->regs.tidv.idv()) { DPRINTF(EthernetDesc, "setting tadv\n"); if (!igbe->tadvEvent.scheduled()) { - igbe->tadvEvent.schedule(curTick + igbe->regs.tadv.idv() * - igbe->intClock()); + igbe->schedule(igbe->tadvEvent, + curTick + igbe->regs.tadv.idv() * igbe->intClock()); } } } @@ -1055,6 +1082,7 @@ IGbE::TxDescCache::serialize(std::ostream &os) SERIALIZE_SCALAR(pktDone); SERIALIZE_SCALAR(isTcp); SERIALIZE_SCALAR(pktWaiting); + SERIALIZE_SCALAR(pktMultiDesc); } void @@ -1064,6 +1092,7 @@ IGbE::TxDescCache::unserialize(Checkpoint *cp, const std::string §ion) UNSERIALIZE_SCALAR(pktDone); UNSERIALIZE_SCALAR(isTcp); UNSERIALIZE_SCALAR(pktWaiting); + UNSERIALIZE_SCALAR(pktMultiDesc); } bool @@ -1079,8 +1108,10 @@ IGbE::TxDescCache::packetAvailable() void IGbE::TxDescCache::enableSm() { - igbe->txTick = true; - igbe->restartClock(); + if (!igbe->drainEvent) { + igbe->txTick = true; + igbe->restartClock(); + } } bool @@ -1096,9 +1127,9 @@ IGbE::TxDescCache::hasOutstandingEvents() void IGbE::restartClock() { - if (!tickEvent.scheduled() && (rxTick || txTick || txFifoTick) && getState() == - SimObject::Running) - tickEvent.schedule((curTick/cycles(1)) * cycles(1) + cycles(1)); + if (!tickEvent.scheduled() && (rxTick || txTick || txFifoTick) && + getState() == SimObject::Running) + schedule(tickEvent, (curTick / ticks(1)) * ticks(1) + ticks(1)); } unsigned int @@ -1117,7 +1148,7 @@ IGbE::drain(Event *de) rxTick = false; if (tickEvent.scheduled()) - tickEvent.deschedule(); + deschedule(tickEvent); if (count) changeState(Draining); @@ -1167,12 +1198,13 @@ IGbE::txStateMachine() // If we have a packet available and it's length is not 0 (meaning it's not // a multidescriptor packet) put it in the fifo, otherwise an the next // iteration we'll get the rest of the data - if (txPacket && txDescCache.packetAvailable() && txPacket->length) { + if (txPacket && txDescCache.packetAvailable() + && !txDescCache.packetMultiDesc() && txPacket->length) { bool success; DPRINTF(EthernetSM, "TXS: packet placed in TX FIFO\n"); success = txFifo.push(txPacket); - txFifoTick = true; + txFifoTick = true && !drainEvent; assert(success); txPacket = NULL; txDescCache.writeback((cacheBlockSize()-1)>>4); @@ -1194,21 +1226,22 @@ IGbE::txStateMachine() if (txDescCache.descLeft() == 0) { postInterrupt(IT_TXQE); txDescCache.writeback(0); + txDescCache.fetchDescriptors(); DPRINTF(EthernetSM, "TXS: No descriptors left in ring, forcing " "writeback stopping ticking and posting TXQE\n"); - txDescCache.fetchDescriptors(); txTick = false; return; } if (!(txDescCache.descUnused())) { + txDescCache.fetchDescriptors(); DPRINTF(EthernetSM, "TXS: No descriptors available in cache, fetching and stopping ticking\n"); txTick = false; - txDescCache.fetchDescriptors(); return; } + int size; size = txDescCache.getPacketSize(); if (size > 0 && txFifo.avail() > size) { @@ -1221,7 +1254,6 @@ IGbE::txStateMachine() DPRINTF(EthernetSM, "TXS: No packets to get, writing back used descriptors\n"); txDescCache.writeback(0); } else { - txDescCache.writeback((cacheBlockSize()-1)>>4); DPRINTF(EthernetSM, "TXS: FIFO full, stopping ticking until space " "available in FIFO\n"); txTick = false; @@ -1237,6 +1269,9 @@ IGbE::txStateMachine() bool IGbE::ethRxPkt(EthPacketPtr pkt) { + rxBytes += pkt->length; + rxPackets++; + DPRINTF(Ethernet, "RxFIFO: Receiving pcakte from wire\n"); if (!regs.rctl.en()) { @@ -1245,7 +1280,7 @@ IGbE::ethRxPkt(EthPacketPtr pkt) } // restart the state machines if they are stopped - rxTick = true; + rxTick = true && !drainEvent; if ((rxTick || txTick) && !tickEvent.scheduled()) { DPRINTF(EthernetSM, "RXS: received packet into fifo, starting ticking\n"); restartClock(); @@ -1256,6 +1291,7 @@ IGbE::ethRxPkt(EthPacketPtr pkt) postInterrupt(IT_RXO, true); return false; } + return true; } @@ -1285,6 +1321,8 @@ IGbE::rxStateMachine() if (descLeft == 0) { rxDescCache.writeback(0); + DPRINTF(EthernetSM, "RXS: No descriptors left in ring, forcing" + " writeback and stopping ticking\n"); rxTick = false; } @@ -1306,10 +1344,10 @@ IGbE::rxStateMachine() } if (rxDescCache.descUnused() == 0) { + rxDescCache.fetchDescriptors(); DPRINTF(EthernetSM, "RXS: No descriptors available in cache, " "fetching descriptors and stopping ticking\n"); rxTick = false; - rxDescCache.fetchDescriptors(); } return; } @@ -1321,10 +1359,10 @@ IGbE::rxStateMachine() } if (!rxDescCache.descUnused()) { + rxDescCache.fetchDescriptors(); DPRINTF(EthernetSM, "RXS: No descriptors available in cache, stopping ticking\n"); rxTick = false; DPRINTF(EthernetSM, "RXS: No descriptors available, fetching\n"); - rxDescCache.fetchDescriptors(); return; } @@ -1337,11 +1375,9 @@ IGbE::rxStateMachine() EthPacketPtr pkt; pkt = rxFifo.front(); - DPRINTF(EthernetSM, "RXS: Writing packet into memory\n"); - if (!rxDescCache.writePacket(pkt)) { - return; - } + rxDescCache.writePacket(pkt); + DPRINTF(EthernetSM, "RXS: Writing packet into memory\n"); DPRINTF(EthernetSM, "RXS: Removing packet from FIFO\n"); rxFifo.pop(); DPRINTF(EthernetSM, "RXS: stopping ticking until packet DMA completes\n"); @@ -1357,10 +1393,8 @@ IGbE::txWire() return; } - if (etherInt->askBusy()) { - // We'll get woken up when the packet ethTxDone() gets called - txFifoTick = false; - } else { + + if (etherInt->sendPacket(txFifo.front())) { if (DTRACE(EthernetSM)) { IpPtr ip(txFifo.front()); if (ip) @@ -1369,13 +1403,17 @@ IGbE::txWire() else DPRINTF(EthernetSM, "Transmitting Non-Ip packet\n"); } - - bool r = etherInt->sendPacket(txFifo.front()); - assert(r); - r += 1; DPRINTF(EthernetSM, "TxFIFO: Successful transmit, bytes available in fifo: %d\n", txFifo.avail()); + + txBytes += txFifo.front()->length; + txPackets++; + txFifoTick = false; + txFifo.pop(); + } else { + // We'll get woken up when the packet ethTxDone() gets called + txFifoTick = false; } } @@ -1395,7 +1433,7 @@ IGbE::tick() if (rxTick || txTick || txFifoTick) - tickEvent.schedule(curTick + cycles(1)); + schedule(tickEvent, curTick + ticks(1)); } void @@ -1404,11 +1442,12 @@ IGbE::ethTxDone() // 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; - if (txDescCache.descLeft() != 0) + txFifoTick = true && !drainEvent; + if (txDescCache.descLeft() != 0 && !drainEvent) txTick = true; restartClock(); + txWire(); DPRINTF(EthernetSM, "TxFIFO: Transmission complete\n"); } @@ -1423,6 +1462,7 @@ IGbE::serialize(std::ostream &os) SERIALIZE_SCALAR(eeDataBits); SERIALIZE_SCALAR(eeOpcode); SERIALIZE_SCALAR(eeAddr); + SERIALIZE_SCALAR(lastInterrupt); SERIALIZE_ARRAY(flash,iGbReg::EEPROM_SIZE); rxFifo.serialize("rxfifo", os); @@ -1474,6 +1514,7 @@ IGbE::unserialize(Checkpoint *cp, const std::string §ion) UNSERIALIZE_SCALAR(eeDataBits); UNSERIALIZE_SCALAR(eeOpcode); UNSERIALIZE_SCALAR(eeAddr); + UNSERIALIZE_SCALAR(lastInterrupt); UNSERIALIZE_ARRAY(flash,iGbReg::EEPROM_SIZE); rxFifo.unserialize("rxfifo", cp, section); @@ -1498,19 +1539,19 @@ IGbE::unserialize(Checkpoint *cp, const std::string §ion) UNSERIALIZE_SCALAR(inter_time); if (rdtr_time) - rdtrEvent.schedule(rdtr_time); + schedule(rdtrEvent, rdtr_time); if (radv_time) - radvEvent.schedule(radv_time); + schedule(radvEvent, radv_time); if (tidv_time) - tidvEvent.schedule(tidv_time); + schedule(tidvEvent, tidv_time); if (tadv_time) - tadvEvent.schedule(tadv_time); + schedule(tadvEvent, tadv_time); if (inter_time) - interEvent.schedule(inter_time); + schedule(interEvent, inter_time); txDescCache.unserialize(cp, csprintf("%s.TxDescCache", section));