📄 ns_gige.cc
字号:
assert(rxDmaState == dmaReading); rxDmaState = dmaIdle; DPRINTF(EthernetDMA, "rx dma read paddr=%#x len=%d\n", rxDmaAddr, rxDmaLen); DDUMP(EthernetDMA, rxDmaData, rxDmaLen); // If the transmit state machine has a pending DMA, let it go first if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting) txKick(); rxKick();}boolNSGigE::doRxDmaWrite(){ assert(rxDmaState == dmaIdle || rxDmaState == dmaWriteWaiting); rxDmaState = dmaWriting; if (dmaPending() || getState() != Running) rxDmaState = dmaWriteWaiting; else dmaWrite(rxDmaAddr, rxDmaLen, &rxDmaWriteEvent, (uint8_t*)rxDmaData); return true;}voidNSGigE::rxDmaWriteDone(){ assert(rxDmaState == dmaWriting); rxDmaState = dmaIdle; DPRINTF(EthernetDMA, "rx dma write paddr=%#x len=%d\n", rxDmaAddr, rxDmaLen); DDUMP(EthernetDMA, rxDmaData, rxDmaLen); // If the transmit state machine has a pending DMA, let it go first if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting) txKick(); rxKick();}voidNSGigE::rxKick(){ bool is64bit = (bool)(regs.config & CFGR_M64ADDR); DPRINTF(EthernetSM, "receive kick rxState=%s (rxBuf.size=%d) %d-bit\n", NsRxStateStrings[rxState], rxFifo.size(), is64bit ? 64 : 32); Addr link, bufptr; uint32_t &cmdsts = is64bit ? rxDesc64.cmdsts : rxDesc32.cmdsts; uint32_t &extsts = is64bit ? rxDesc64.extsts : rxDesc32.extsts; next: if (clock) { if (rxKickTick > curTick) { DPRINTF(EthernetSM, "receive kick exiting, can't run till %d\n", rxKickTick); goto exit; } // Go to the next state machine clock tick. rxKickTick = curTick + ticks(1); } switch(rxDmaState) { case dmaReadWaiting: if (doRxDmaRead()) goto exit; break; case dmaWriteWaiting: if (doRxDmaWrite()) goto exit; break; default: break; } link = is64bit ? (Addr)rxDesc64.link : (Addr)rxDesc32.link; bufptr = is64bit ? (Addr)rxDesc64.bufptr : (Addr)rxDesc32.bufptr; // see state machine from spec for details // the way this works is, if you finish work on one state and can // go directly to another, you do that through jumping to the // label "next". however, if you have intermediate work, like DMA // so that you can't go to the next state yet, you go to exit and // exit the loop. however, when the DMA is done it will trigger // an event and come back to this loop. switch (rxState) { case rxIdle: if (!rxEnable) { DPRINTF(EthernetSM, "Receive Disabled! Nothing to do.\n"); goto exit; } if (CRDD) { rxState = rxDescRefr; rxDmaAddr = regs.rxdp & 0x3fffffff; rxDmaData = is64bit ? (void *)&rxDesc64.link : (void *)&rxDesc32.link; rxDmaLen = is64bit ? sizeof(rxDesc64.link) : sizeof(rxDesc32.link); rxDmaFree = dmaDescFree; descDmaReads++; descDmaRdBytes += rxDmaLen; if (doRxDmaRead()) goto exit; } else { rxState = rxDescRead; rxDmaAddr = regs.rxdp & 0x3fffffff; rxDmaData = is64bit ? (void *)&rxDesc64 : (void *)&rxDesc32; rxDmaLen = is64bit ? sizeof(rxDesc64) : sizeof(rxDesc32); rxDmaFree = dmaDescFree; descDmaReads++; descDmaRdBytes += rxDmaLen; if (doRxDmaRead()) goto exit; } break; case rxDescRefr: if (rxDmaState != dmaIdle) goto exit; rxState = rxAdvance; break; case rxDescRead: if (rxDmaState != dmaIdle) goto exit; DPRINTF(EthernetDesc, "rxDesc: addr=%08x read descriptor\n", regs.rxdp & 0x3fffffff); DPRINTF(EthernetDesc, "rxDesc: link=%#x bufptr=%#x cmdsts=%08x extsts=%08x\n", link, bufptr, cmdsts, extsts); if (cmdsts & CMDSTS_OWN) { devIntrPost(ISR_RXIDLE); rxState = rxIdle; goto exit; } else { rxState = rxFifoBlock; rxFragPtr = bufptr; rxDescCnt = cmdsts & CMDSTS_LEN_MASK; } break; case rxFifoBlock: if (!rxPacket) { /** * @todo in reality, we should be able to start processing * the packet as it arrives, and not have to wait for the * full packet ot be in the receive fifo. */ if (rxFifo.empty()) goto exit; DPRINTF(EthernetSM, "****processing receive of new packet****\n"); // If we don't have a packet, grab a new one from the fifo. rxPacket = rxFifo.front(); rxPktBytes = rxPacket->length; rxPacketBufPtr = rxPacket->data;#if TRACING_ON if (DTRACE(Ethernet)) { IpPtr ip(rxPacket); if (ip) { DPRINTF(Ethernet, "ID is %d\n", ip->id()); TcpPtr tcp(ip); if (tcp) { DPRINTF(Ethernet, "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n", tcp->sport(), tcp->dport(), tcp->seq(), tcp->ack()); } } }#endif // sanity check - i think the driver behaves like this assert(rxDescCnt >= rxPktBytes); rxFifo.pop(); } // dont' need the && rxDescCnt > 0 if driver sanity check // above holds if (rxPktBytes > 0) { rxState = rxFragWrite; // don't need min<>(rxPktBytes,rxDescCnt) if above sanity // check holds rxXferLen = rxPktBytes; rxDmaAddr = rxFragPtr & 0x3fffffff; rxDmaData = rxPacketBufPtr; rxDmaLen = rxXferLen; rxDmaFree = dmaDataFree; if (doRxDmaWrite()) goto exit; } else { rxState = rxDescWrite; //if (rxPktBytes == 0) { /* packet is done */ assert(rxPktBytes == 0); DPRINTF(EthernetSM, "done with receiving packet\n"); cmdsts |= CMDSTS_OWN; cmdsts &= ~CMDSTS_MORE; cmdsts |= CMDSTS_OK; cmdsts &= 0xffff0000; cmdsts += rxPacket->length; //i.e. set CMDSTS_SIZE#if 0 /* * all the driver uses these are for its own stats keeping * which we don't care about, aren't necessary for * functionality and doing this would just slow us down. * if they end up using this in a later version for * functional purposes, just undef */ if (rxFilterEnable) { cmdsts &= ~CMDSTS_DEST_MASK; const EthAddr &dst = rxFifoFront()->dst(); if (dst->unicast()) cmdsts |= CMDSTS_DEST_SELF; if (dst->multicast()) cmdsts |= CMDSTS_DEST_MULTI; if (dst->broadcast()) cmdsts |= CMDSTS_DEST_MASK; }#endif IpPtr ip(rxPacket); if (extstsEnable && ip) { extsts |= EXTSTS_IPPKT; rxIpChecksums++; if (cksum(ip) != 0) { DPRINTF(EthernetCksum, "Rx IP Checksum Error\n"); extsts |= EXTSTS_IPERR; } TcpPtr tcp(ip); UdpPtr udp(ip); if (tcp) { extsts |= EXTSTS_TCPPKT; rxTcpChecksums++; if (cksum(tcp) != 0) { DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n"); extsts |= EXTSTS_TCPERR; } } else if (udp) { extsts |= EXTSTS_UDPPKT; rxUdpChecksums++; if (cksum(udp) != 0) { DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n"); extsts |= EXTSTS_UDPERR; } } } rxPacket = 0; /* * the driver seems to always receive into desc buffers * of size 1514, so you never have a pkt that is split * into multiple descriptors on the receive side, so * i don't implement that case, hence the assert above. */ DPRINTF(EthernetDesc, "rxDesc: addr=%08x writeback cmdsts extsts\n", regs.rxdp & 0x3fffffff); DPRINTF(EthernetDesc, "rxDesc: link=%#x bufptr=%#x cmdsts=%08x extsts=%08x\n", link, bufptr, cmdsts, extsts); rxDmaAddr = regs.rxdp & 0x3fffffff; rxDmaData = &cmdsts; if (is64bit) { rxDmaAddr += offsetof(ns_desc64, cmdsts); rxDmaLen = sizeof(rxDesc64.cmdsts) + sizeof(rxDesc64.extsts); } else { rxDmaAddr += offsetof(ns_desc32, cmdsts); rxDmaLen = sizeof(rxDesc32.cmdsts) + sizeof(rxDesc32.extsts); } rxDmaFree = dmaDescFree; descDmaWrites++; descDmaWrBytes += rxDmaLen; if (doRxDmaWrite()) goto exit; } break; case rxFragWrite: if (rxDmaState != dmaIdle) goto exit; rxPacketBufPtr += rxXferLen; rxFragPtr += rxXferLen; rxPktBytes -= rxXferLen; rxState = rxFifoBlock; break; case rxDescWrite: if (rxDmaState != dmaIdle) goto exit; assert(cmdsts & CMDSTS_OWN); assert(rxPacket == 0); devIntrPost(ISR_RXOK); if (cmdsts & CMDSTS_INTR) devIntrPost(ISR_RXDESC); if (!rxEnable) { DPRINTF(EthernetSM, "Halting the RX state machine\n"); rxState = rxIdle; goto exit; } else rxState = rxAdvance; break; case rxAdvance: if (link == 0) { devIntrPost(ISR_RXIDLE); rxState = rxIdle; CRDD = true; goto exit; } else { if (rxDmaState != dmaIdle) goto exit; rxState = rxDescRead; regs.rxdp = link; CRDD = false; rxDmaAddr = regs.rxdp & 0x3fffffff; rxDmaData = is64bit ? (void *)&rxDesc64 : (void *)&rxDesc32; rxDmaLen = is64bit ? sizeof(rxDesc64) : sizeof(rxDesc32); rxDmaFree = dmaDescFree; if (doRxDmaRead()) goto exit; } break; default: panic("Invalid rxState!"); } DPRINTF(EthernetSM, "entering next rxState=%s\n", NsRxStateStrings[rxState]); goto next; exit: /** * @todo do we want to schedule a future kick? */ DPRINTF(EthernetSM, "rx state machine exited rxState=%s\n", NsRxStateStrings[rxState]); if (clock && !rxKickEvent.scheduled()) rxKickEvent.schedule(rxKickTick);}voidNSGigE::transmit(){ if (txFifo.empty()) { DPRINTF(Ethernet, "nothing to transmit\n"); return; } DPRINTF(Ethernet, "Attempt Pkt Transmit: txFifo length=%d\n", txFifo.size()); if (interface->sendPacket(txFifo.front())) {#if TRACING_ON if (DTRACE(Ethernet)) { IpPtr ip(txFifo.front()); if (ip) { DPRINTF(Ethernet, "ID is %d\n", ip->id()); TcpPtr tcp(ip); if (tcp) { DPRINTF(Ethernet, "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n", tcp->sport(), tcp->dport(), tcp->seq(), tcp->ack()); } } }#endif DDUMP(EthernetData, txFifo.front()->data, txFifo.front()->length); txBytes += txFifo.front()->length; txPackets++; DPRINTF(Ethernet, "Successful Xmit! now txFifoAvail is %d\n", txFifo.avail()); txFifo.pop(); /* * normally do a writeback of the descriptor here, and ONLY * after that is done, send this interrupt. but since our * stuff never actually fails, just do this interrupt here, * otherwise the code has to stray from this nice format. * besides, it's functionally the same. */ devIntrPost(ISR_TXOK); } if (!txFifo.empty() && !txEvent.scheduled()) { DPRINTF(Ethernet, "reschedule transmit\n"); txEvent.schedule(curTick + retryTime); }}boolNSGigE::doTxDmaRead(){ assert(txDmaState == dmaIdle || txDmaState == dmaReadWaiting); txDmaState = dmaReading; if (dmaPending() || getState() != Running) txDmaState = dmaReadWaiting; else dmaRead(txDmaAddr, txDmaLen, &txDmaReadEvent, (uint8_t*)txDmaData); return true;}voidNSGigE::txDmaReadDone(){ assert(txDmaState == dmaReading); txDmaState = dmaIdle; DPRINTF(EthernetDMA, "tx dma read paddr=%#x len=%d\n", txDmaAddr, txDmaLen); DDUMP(EthernetDMA, txDmaData, txDmaLen); // If the receive state machine has a pending DMA, let it go first if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting) rxKick(); txKick();}boolNSGigE::doTxDmaWrite(){ assert(txDmaState == dmaIdle || txDmaState == dmaWriteWaiting); txDmaState = dmaWriting;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -