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)
{
pkt->set<uint32_t>(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);
}
regs.itr = val;
break;
case REG_ICS:
+ DPRINTF(EthernetIntr, "Posting interrupt because of ICS write\n");
postInterrupt((IntTypes)val);
break;
case REG_IMS:
regs.rctl = val;
if (regs.rctl.rst()) {
rxDescCache.reset();
+ DPRINTF(EthernetSM, "RXS: Got RESET!\n");
rxFifo.clear();
regs.rctl.rst(0);
}
} 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());
}
}
}
// 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;
}
}
// 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;
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();
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());
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);
assert(unusedCache.size());
assert(pktPtr);
- DPRINTF(EthernetDesc, "TxDesc: DMA of packet complete\n");
+ DPRINTF(EthernetDesc, "DMA of packet complete\n");
desc = unusedCache.front();
pktWaiting = false;
pktPtr = NULL;
- DPRINTF(EthernetDesc, "TxDesc: Partial Packet Descriptor Done\n");
+ DPRINTF(EthernetDesc, "Partial Packet Descriptor Done\n");
return;
}
// 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());
}
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());
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);
}
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;
}
txDescCache.writeback(0);
txTick = false;
postInterrupt(IT_TXQE, true);
+ return;
}
"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;
}
}
}
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;
}
}
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;
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;
}
}
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");
}
// 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<IGbE, &IGbE::rdtrProcess>;
EventWrapper<IGbE, &IGbE::rdtrProcess> 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<IGbE, &IGbE::radvProcess>;
EventWrapper<IGbE, &IGbE::radvProcess> 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<IGbE, &IGbE::tadvProcess>;
EventWrapper<IGbE, &IGbE::tadvProcess> 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<IGbE, &IGbE::tidvProcess>;
EventWrapper<IGbE, &IGbE::tidvProcess> tidvEvent;
*/
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)
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
*/
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()));
#endif
cachePnt += curFetching;
- if (cachePnt > descLen())
- cachePnt -= descLen();
+ assert(cachePnt <= descLen());
+ if (cachePnt == descLen())
+ cachePnt = 0;
curFetching = 0;
curHead += wbOut;
wbOut = 0;
- if (curHead > descLen())
- curHead = 0;
+ if (curHead >= descLen())
+ curHead -= descLen();
// Update the head
updateHead(curHead);
usedCache.clear();
unusedCache.clear();
+
+ cachePnt = 0;
+
}
};