i8254xgbe.cc
来自「M5,一个功能强大的多处理器系统模拟器.很多针对处理器架构,性能的研究都使用它作」· CC 代码 · 共 1,528 行 · 第 1/3 页
CC
1,528 行
} else { DPRINTF(EthernetSM, "RXS: RDT NOT Fetching Desc b/c draining!\n"); } break; case REG_RDTR: regs.rdtr = val; break; case REG_RADV: regs.radv = val; break; case REG_TDBAL: regs.tdba.tdbal( val & ~mask(4)); txDescCache.areaChanged(); break; case REG_TDBAH: regs.tdba.tdbah(val); txDescCache.areaChanged(); break; case REG_TDLEN: regs.tdlen = val & ~mask(7); txDescCache.areaChanged(); break; case REG_TDH: regs.tdh = val; txDescCache.areaChanged(); break; case REG_TDT: regs.tdt = val; DPRINTF(EthernetSM, "TXS: TX Tail pointer updated\n"); if (getState() == SimObject::Running) { DPRINTF(EthernetSM, "TXS: TDT Fetching Descriptors!\n"); txDescCache.fetchDescriptors(); } else { DPRINTF(EthernetSM, "TXS: TDT NOT Fetching Desc b/c draining!\n"); } break; case REG_TIDV: regs.tidv = val; break; case REG_TXDCTL: regs.txdctl = val; break; case REG_TADV: regs.tadv = val; break; case REG_RXCSUM: regs.rxcsum = val; break; case REG_MANC: regs.manc = val; break; default: if (!(daddr >= REG_VFTA && daddr < (REG_VFTA + VLAN_FILTER_TABLE_SIZE*4)) && !(daddr >= REG_RAL && daddr < (REG_RAL + RCV_ADDRESS_TABLE_SIZE*8)) && !(daddr >= REG_MTA && daddr < (REG_MTA + MULTICAST_TABLE_SIZE*4))) panic("Write request to unknown register number: %#x\n", daddr); }; pkt->makeAtomicResponse(); return pioDelay;}voidIGbE::postInterrupt(IntTypes t, bool now){ assert(t); // Interrupt is already pending if (t & regs.icr() && !now) return; regs.icr = regs.icr() | t; if (regs.itr.interval() == 0 || now) { if (interEvent.scheduled()) { interEvent.deschedule(); } cpuPostInt(); } else { DPRINTF(EthernetIntr, "EINT: Scheduling timer interrupt for %d ticks\n", Clock::Int::ns * 256 * regs.itr.interval()); if (!interEvent.scheduled()) { interEvent.schedule(curTick + Clock::Int::ns * 256 * regs.itr.interval()); } }}voidIGbE::delayIntEvent(){ cpuPostInt();}voidIGbE::cpuPostInt(){ if (!(regs.icr() & regs.imr)) { DPRINTF(Ethernet, "Interrupt Masked. Not Posting\n"); return; } DPRINTF(Ethernet, "Posting Interrupt\n"); if (interEvent.scheduled()) { interEvent.deschedule(); } if (rdtrEvent.scheduled()) { regs.icr.rxt0(1); rdtrEvent.deschedule(); } if (radvEvent.scheduled()) { regs.icr.rxt0(1); radvEvent.deschedule(); } if (tadvEvent.scheduled()) { regs.icr.txdw(1); tadvEvent.deschedule(); } if (tidvEvent.scheduled()) { regs.icr.txdw(1); tidvEvent.deschedule(); } regs.icr.int_assert(1); DPRINTF(EthernetIntr, "EINT: Posting interrupt to CPU now. Vector %#x\n", regs.icr()); intrPost();}voidIGbE::cpuClearInt(){ if (regs.icr.int_assert()) { regs.icr.int_assert(0); DPRINTF(EthernetIntr, "EINT: Clearing interrupt to CPU now. Vector %#x\n", regs.icr()); intrClear(); }}voidIGbE::chkInterrupt(){ DPRINTF(Ethernet, "Checking interrupts icr: %#x imr: %#x\n", regs.icr(), regs.imr); // Check if we need to clear the cpu interrupt if (!(regs.icr() & regs.imr)) { DPRINTF(Ethernet, "Mask cleaned all interrupts\n"); if (interEvent.scheduled()) interEvent.deschedule(); if (regs.icr.int_assert()) cpuClearInt(); } DPRINTF(Ethernet, "ITR = %#X itr.interval = %#X\n", regs.itr(), regs.itr.interval()); if (regs.icr() & regs.imr) { if (regs.itr.interval() == 0) { cpuPostInt(); } else { DPRINTF(Ethernet, "Possibly scheduling interrupt because of imr write\n"); 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()); } } }}IGbE::RxDescCache::RxDescCache(IGbE *i, const std::string n, int s) : DescCache<RxDesc>(i, n, s), pktDone(false), pktEvent(this){}voidIGbE::RxDescCache::writePacket(EthPacketPtr packet){ // We shouldn't have to deal with any of these yet DPRINTF(EthernetDesc, "Packet Length: %d Desc Size: %d\n", packet->length, igbe->regs.rctl.descSize()); assert(packet->length < igbe->regs.rctl.descSize()); 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);}voidIGbE::RxDescCache::pktComplete(){ assert(unusedCache.size()); 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", pktPtr->length, crcfixup, htole((uint16_t)(pktPtr->length + crcfixup)), (uint16_t)(pktPtr->length + crcfixup)); // no support for anything but starting at 0 assert(igbe->regs.rxcsum.pcss() == 0); 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) { DPRINTF(EthernetDesc, "Proccesing Ip packet with Id=%d\n", ip->id()); if (igbe->regs.rxcsum.ipofld()) { DPRINTF(EthernetDesc, "Checking IP checksum\n"); status |= RXDS_IPCS; desc->csum = htole(cksum(ip)); if (cksum(ip) != 0) { err |= RXDE_IPE; DPRINTF(EthernetDesc, "Checksum is bad!!\n"); } } TcpPtr tcp(ip); if (tcp && igbe->regs.rxcsum.tuofld()) { DPRINTF(EthernetDesc, "Checking TCP checksum\n"); status |= RXDS_TCPCS; desc->csum = htole(cksum(tcp)); if (cksum(tcp) != 0) { DPRINTF(EthernetDesc, "Checksum is bad!!\n"); err |= RXDE_TCPE; } } UdpPtr udp(ip); if (udp && igbe->regs.rxcsum.tuofld()) { DPRINTF(EthernetDesc, "Checking UDP checksum\n"); status |= RXDS_UDPCS; desc->csum = htole(cksum(udp)); if (cksum(udp) != 0) { DPRINTF(EthernetDesc, "Checksum is bad!!\n"); err |= RXDE_TCPE; } } } else { // if ip DPRINTF(EthernetSM, "Proccesing Non-Ip packet\n"); } desc->status = htole(status); desc->errors = htole(err); // No vlan support at this point... just set it to 0 desc->vlan = 0; // Deal with the rx timer interrupts 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); } if (igbe->regs.radv.idv() && igbe->regs.rdtr.delay()) { 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()); } } // if neither radv or rdtr, maybe itr is set... if (!igbe->regs.rdtr.delay()) { DPRINTF(EthernetSM, "RXS: Receive interrupt delay disabled, posting IT_RXT\n"); igbe->postInterrupt(IT_RXT); } // If the packet is small enough, interrupt appropriately // I wonder if this is delayed or not?! if (pktPtr->length <= igbe->regs.rsrpd.idv()) { DPRINTF(EthernetSM, "RXS: Posting IT_SRPD beacuse small packet received\n"); igbe->postInterrupt(IT_SRPD); } DPRINTF(EthernetDesc, "Processing of this descriptor complete\n"); unusedCache.pop_front(); usedCache.push_back(desc); pktPtr = NULL; enableSm(); pktDone = true; igbe->checkDrain();}voidIGbE::RxDescCache::enableSm(){ if (!igbe->drainEvent) { igbe->rxTick = true; igbe->restartClock(); }}boolIGbE::RxDescCache::packetDone(){ if (pktDone) { pktDone = false; return true; } return false;}boolIGbE::RxDescCache::hasOutstandingEvents(){ return pktEvent.scheduled() || wbEvent.scheduled() || fetchEvent.scheduled();}voidIGbE::RxDescCache::serialize(std::ostream &os){ DescCache<RxDesc>::serialize(os); SERIALIZE_SCALAR(pktDone);}voidIGbE::RxDescCache::unserialize(Checkpoint *cp, const std::string §ion){ DescCache<RxDesc>::unserialize(cp, section); UNSERIALIZE_SCALAR(pktDone);}///////////////////////////////////// IGbE::TxDesc /////////////////////////////////IGbE::TxDescCache::TxDescCache(IGbE *i, const std::string n, int s) : DescCache<TxDesc>(i,n, s), pktDone(false), isTcp(false), pktWaiting(false), pktEvent(this){}intIGbE::TxDescCache::getPacketSize(){ assert(unusedCache.size()); TxDesc *desc; DPRINTF(EthernetDesc, "Starting processing of descriptor\n"); while (unusedCache.size() && TxdOp::isContext(unusedCache.front())) { DPRINTF(EthernetDesc, "Got context descriptor type... skipping\n"); // I think we can just ignore these for now? desc = unusedCache.front(); DPRINTF(EthernetDesc, "Descriptor upper: %#x lower: %#X\n", desc->d1, desc->d2); // is this going to be a tcp or udp packet? isTcp = TxdOp::tcp(desc) ? true : false; // make sure it's ipv4 //assert(TxdOp::ip(desc)); TxdOp::setDd(desc); unusedCache.pop_front(); usedCache.push_back(desc); } if (!unusedCache.size()) return -1; DPRINTF(EthernetDesc, "Next TX packet is %d bytes\n", TxdOp::getLen(unusedCache.front())); return TxdOp::getLen(unusedCache.front());}voidIGbE::TxDescCache::getPacketData(EthPacketPtr p){ assert(unusedCache.size()); TxDesc *desc; desc = unusedCache.front(); assert((TxdOp::isLegacy(desc) || TxdOp::isData(desc)) && TxdOp::getLen(desc)); pktPtr = p; pktWaiting = true; DPRINTF(EthernetDesc, "Starting DMA of packet\n"); igbe->dmaRead(igbe->platform->pciToDma(TxdOp::getBuf(desc)), TxdOp::getLen(desc), &pktEvent, p->data + p->length);}voidIGbE::TxDescCache::pktComplete(){ TxDesc *desc; assert(unusedCache.size()); assert(pktPtr); 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); unusedCache.pop_front(); usedCache.push_back(desc); pktDone = true; pktWaiting = false; pktPtr = NULL; DPRINTF(EthernetDesc, "Partial Packet Descriptor Done\n"); enableSm(); igbe->checkDrain(); return; } // Set the length of the data in the EtherPacket pktPtr->length += TxdOp::getLen(desc); // no support for vlans assert(!TxdOp::vle(desc)); // we alway report status assert(TxdOp::rs(desc)); // we only support single packet descriptors at this point assert(TxdOp::eop(desc)); // set that this packet is done TxdOp::setDd(desc); DPRINTF(EthernetDesc, "TxDescriptor data d1: %#llx d2: %#llx\n", desc->d1, desc->d2); if (DTRACE(EthernetDesc)) { IpPtr ip(pktPtr); if (ip) DPRINTF(EthernetDesc, "Proccesing Ip packet with Id=%d\n", ip->id()); else DPRINTF(EthernetSM, "Proccesing Non-Ip packet\n"); } // Checksums are only ofloaded for new descriptor types if (TxdOp::isData(desc) && ( TxdOp::ixsm(desc) || TxdOp::txsm(desc)) ) { DPRINTF(EthernetDesc, "Calculating checksums for packet\n"); IpPtr ip(pktPtr); if (TxdOp::ixsm(desc)) { ip->sum(0); ip->sum(cksum(ip)); DPRINTF(EthernetDesc, "Calculated IP checksum\n"); } if (TxdOp::txsm(desc)) { TcpPtr tcp(ip); UdpPtr udp(ip); if (tcp) { tcp->sum(0); tcp->sum(cksum(tcp)); DPRINTF(EthernetDesc, "Calculated TCP checksum\n"); } else if (udp) { assert(udp); udp->sum(0); udp->sum(cksum(udp)); DPRINTF(EthernetDesc, "Calculated UDP checksum\n"); } else { panic("Told to checksum, but don't know how\n"); } } } if (TxdOp::ide(desc)) { // Deal with the rx timer interrupts 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() *
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?