📄 ns_gige.cc
字号:
if (dmaPending() || getState() != Running) txDmaState = dmaWriteWaiting; else dmaWrite(txDmaAddr, txDmaLen, &txDmaWriteEvent, (uint8_t*)txDmaData); return true;}voidNSGigE::txDmaWriteDone(){ assert(txDmaState == dmaWriting); txDmaState = dmaIdle; DPRINTF(EthernetDMA, "tx dma write 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();}voidNSGigE::txKick(){ bool is64bit = (bool)(regs.config & CFGR_M64ADDR); DPRINTF(EthernetSM, "transmit kick txState=%s %d-bit\n", NsTxStateStrings[txState], is64bit ? 64 : 32); Addr link, bufptr; uint32_t &cmdsts = is64bit ? txDesc64.cmdsts : txDesc32.cmdsts; uint32_t &extsts = is64bit ? txDesc64.extsts : txDesc32.extsts; next: if (clock) { if (txKickTick > curTick) { DPRINTF(EthernetSM, "transmit kick exiting, can't run till %d\n", txKickTick); goto exit; } // Go to the next state machine clock tick. txKickTick = curTick + ticks(1); } switch(txDmaState) { case dmaReadWaiting: if (doTxDmaRead()) goto exit; break; case dmaWriteWaiting: if (doTxDmaWrite()) goto exit; break; default: break; } link = is64bit ? (Addr)txDesc64.link : (Addr)txDesc32.link; bufptr = is64bit ? (Addr)txDesc64.bufptr : (Addr)txDesc32.bufptr; switch (txState) { case txIdle: if (!txEnable) { DPRINTF(EthernetSM, "Transmit disabled. Nothing to do.\n"); goto exit; } if (CTDD) { txState = txDescRefr; txDmaAddr = regs.txdp & 0x3fffffff; txDmaData = is64bit ? (void *)&txDesc64.link : (void *)&txDesc32.link; txDmaLen = is64bit ? sizeof(txDesc64.link) : sizeof(txDesc32.link); txDmaFree = dmaDescFree; descDmaReads++; descDmaRdBytes += txDmaLen; if (doTxDmaRead()) goto exit; } else { txState = txDescRead; txDmaAddr = regs.txdp & 0x3fffffff; txDmaData = is64bit ? (void *)&txDesc64 : (void *)&txDesc32; txDmaLen = is64bit ? sizeof(txDesc64) : sizeof(txDesc32); txDmaFree = dmaDescFree; descDmaReads++; descDmaRdBytes += txDmaLen; if (doTxDmaRead()) goto exit; } break; case txDescRefr: if (txDmaState != dmaIdle) goto exit; txState = txAdvance; break; case txDescRead: if (txDmaState != dmaIdle) goto exit; DPRINTF(EthernetDesc, "txDesc: addr=%08x read descriptor\n", regs.txdp & 0x3fffffff); DPRINTF(EthernetDesc, "txDesc: link=%#x bufptr=%#x cmdsts=%#08x extsts=%#08x\n", link, bufptr, cmdsts, extsts); if (cmdsts & CMDSTS_OWN) { txState = txFifoBlock; txFragPtr = bufptr; txDescCnt = cmdsts & CMDSTS_LEN_MASK; } else { devIntrPost(ISR_TXIDLE); txState = txIdle; goto exit; } break; case txFifoBlock: if (!txPacket) { DPRINTF(EthernetSM, "****starting the tx of a new packet****\n"); txPacket = new EthPacketData(16384); txPacketBufPtr = txPacket->data; } if (txDescCnt == 0) { DPRINTF(EthernetSM, "the txDescCnt == 0, done with descriptor\n"); if (cmdsts & CMDSTS_MORE) { DPRINTF(EthernetSM, "there are more descriptors to come\n"); txState = txDescWrite; cmdsts &= ~CMDSTS_OWN; txDmaAddr = regs.txdp & 0x3fffffff; txDmaData = &cmdsts; if (is64bit) { txDmaAddr += offsetof(ns_desc64, cmdsts); txDmaLen = sizeof(txDesc64.cmdsts); } else { txDmaAddr += offsetof(ns_desc32, cmdsts); txDmaLen = sizeof(txDesc32.cmdsts); } txDmaFree = dmaDescFree; if (doTxDmaWrite()) goto exit; } else { /* this packet is totally done */ DPRINTF(EthernetSM, "This packet is done, let's wrap it up\n"); /* deal with the the packet that just finished */ if ((regs.vtcr & VTCR_PPCHK) && extstsEnable) { IpPtr ip(txPacket); if (extsts & EXTSTS_UDPPKT) { UdpPtr udp(ip); udp->sum(0); udp->sum(cksum(udp)); txUdpChecksums++; } else if (extsts & EXTSTS_TCPPKT) { TcpPtr tcp(ip); tcp->sum(0); tcp->sum(cksum(tcp)); txTcpChecksums++; } if (extsts & EXTSTS_IPPKT) { ip->sum(0); ip->sum(cksum(ip)); txIpChecksums++; } } txPacket->length = txPacketBufPtr - txPacket->data; // this is just because the receive can't handle a // packet bigger want to make sure if (txPacket->length > 1514) panic("transmit packet too large, %s > 1514\n", txPacket->length);#ifndef NDEBUG bool success =#endif txFifo.push(txPacket); assert(success); /* * this following section is not tqo spec, but * functionally shouldn't be any different. normally, * the chip will wait til the transmit has occurred * before writing back the descriptor because it has * to wait to see that it was successfully transmitted * to decide whether to set CMDSTS_OK or not. * however, in the simulator since it is always * successfully transmitted, and writing it exactly to * spec would complicate the code, we just do it here */ cmdsts &= ~CMDSTS_OWN; cmdsts |= CMDSTS_OK; DPRINTF(EthernetDesc, "txDesc writeback: cmdsts=%08x extsts=%08x\n", cmdsts, extsts); txDmaFree = dmaDescFree; txDmaAddr = regs.txdp & 0x3fffffff; txDmaData = &cmdsts; if (is64bit) { txDmaAddr += offsetof(ns_desc64, cmdsts); txDmaLen = sizeof(txDesc64.cmdsts) + sizeof(txDesc64.extsts); } else { txDmaAddr += offsetof(ns_desc32, cmdsts); txDmaLen = sizeof(txDesc32.cmdsts) + sizeof(txDesc32.extsts); } descDmaWrites++; descDmaWrBytes += txDmaLen; transmit(); txPacket = 0; if (!txEnable) { DPRINTF(EthernetSM, "halting TX state machine\n"); txState = txIdle; goto exit; } else txState = txAdvance; if (doTxDmaWrite()) goto exit; } } else { DPRINTF(EthernetSM, "this descriptor isn't done yet\n"); if (!txFifo.full()) { txState = txFragRead; /* * The number of bytes transferred is either whatever * is left in the descriptor (txDescCnt), or if there * is not enough room in the fifo, just whatever room * is left in the fifo */ txXferLen = min<uint32_t>(txDescCnt, txFifo.avail()); txDmaAddr = txFragPtr & 0x3fffffff; txDmaData = txPacketBufPtr; txDmaLen = txXferLen; txDmaFree = dmaDataFree; if (doTxDmaRead()) goto exit; } else { txState = txFifoBlock; transmit(); goto exit; } } break; case txFragRead: if (txDmaState != dmaIdle) goto exit; txPacketBufPtr += txXferLen; txFragPtr += txXferLen; txDescCnt -= txXferLen; txFifo.reserve(txXferLen); txState = txFifoBlock; break; case txDescWrite: if (txDmaState != dmaIdle) goto exit; if (cmdsts & CMDSTS_INTR) devIntrPost(ISR_TXDESC); if (!txEnable) { DPRINTF(EthernetSM, "halting TX state machine\n"); txState = txIdle; goto exit; } else txState = txAdvance; break; case txAdvance: if (link == 0) { devIntrPost(ISR_TXIDLE); txState = txIdle; goto exit; } else { if (txDmaState != dmaIdle) goto exit; txState = txDescRead; regs.txdp = link; CTDD = false; txDmaAddr = link & 0x3fffffff; txDmaData = is64bit ? (void *)&txDesc64 : (void *)&txDesc32; txDmaLen = is64bit ? sizeof(txDesc64) : sizeof(txDesc32); txDmaFree = dmaDescFree; if (doTxDmaRead()) goto exit; } break; default: panic("invalid state"); } DPRINTF(EthernetSM, "entering next txState=%s\n", NsTxStateStrings[txState]); goto next; exit: /** * @todo do we want to schedule a future kick? */ DPRINTF(EthernetSM, "tx state machine exited txState=%s\n", NsTxStateStrings[txState]); if (clock && !txKickEvent.scheduled()) txKickEvent.schedule(txKickTick);}/** * Advance the EEPROM state machine * Called on rising edge of EEPROM clock bit in MEAR */voidNSGigE::eepromKick(){ switch (eepromState) { case eepromStart: // Wait for start bit if (regs.mear & MEAR_EEDI) { // Set up to get 2 opcode bits eepromState = eepromGetOpcode; eepromBitsToRx = 2; eepromOpcode = 0; } break; case eepromGetOpcode: eepromOpcode <<= 1; eepromOpcode += (regs.mear & MEAR_EEDI) ? 1 : 0; --eepromBitsToRx; // Done getting opcode if (eepromBitsToRx == 0) { if (eepromOpcode != EEPROM_READ) panic("only EEPROM reads are implemented!"); // Set up to get address eepromState = eepromGetAddress; eepromBitsToRx = 6; eepromAddress = 0; } break; case eepromGetAddress: eepromAddress <<= 1; eepromAddress += (regs.mear & MEAR_EEDI) ? 1 : 0; --eepromBitsToRx; // Done getting address if (eepromBitsToRx == 0) { if (eepromAddress >= EEPROM_SIZE) panic("EEPROM read access out of range!"); switch (eepromAddress) { case EEPROM_PMATCH2_ADDR: eepromData = rom.perfectMatch[5]; eepromData <<= 8; eepromData += rom.perfectMatch[4]; break; case EEPROM_PMATCH1_ADDR: eepromData = rom.perfectMatch[3]; eepromData <<= 8; eepromData += rom.perfectMatch[2]; break; case EEPROM_PMATCH0_ADDR: eepromData = rom.perfectMatch[1]; eepromData <<= 8; eepromData += rom.perfectMatch[0]; break; default: panic("FreeBSD driver only uses EEPROM to read PMATCH!"); } // Set up to read data eepromState = eepromRead; eepromBitsToRx = 16; // Clear data in bit regs.mear &= ~MEAR_EEDI; } break; case eepromRead: // Clear Data Out bit regs.mear &= ~MEAR_EEDO; // Set bit to value of current EEPROM bit regs.mear |= (eepromData & 0x8000) ? MEAR_EEDO : 0x0; eepromData <<= 1; --eepromBitsToRx; // All done if (eepromBitsToRx == 0) { eepromState = eepromStart; } break; default: panic("invalid EEPROM state"); }}voidNSGigE::transferDone(){ if (txFifo.empty()) { DPRINTF(Ethernet, "transfer complete: txFifo empty...nothing to do\n"); return; } DPRINTF(Ethernet, "transfer complete: data in txFifo...schedule xmit\n"); txEvent.reschedule(curTick + ticks(1), true);}boolNSGigE::rxFilter(const EthPacketPtr &packet){ EthPtr eth = packet; bool drop = true; string type; const EthAddr &dst = eth->dst(); if (dst.unicast()) { // If we're accepting all unicast addresses if (acce
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -