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 &section){    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 + -
显示快捷键?