first bit of life from the intel gigabit model
authorAli Saidi <saidi@eecs.umich.edu>
Mon, 26 Mar 2007 22:40:18 +0000 (18:40 -0400)
committerAli Saidi <saidi@eecs.umich.edu>
Mon, 26 Mar 2007 22:40:18 +0000 (18:40 -0400)
--HG--
extra : convert_revision : d8944a53f6b585df21651c4e624518d5c49a7837

src/dev/i8254xGBe.cc
src/dev/i8254xGBe.hh
src/dev/i8254xGBe_defs.hh
src/python/m5/objects/Ethernet.py

index d6449f6c51e7d9ea11b5e254fae227fe50b97c1b..c38a9e873d2374c78138b014515f50fe57d5dd9e 100644 (file)
@@ -59,8 +59,8 @@ IGbE::IGbE(Params *p)
       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),
-      rxDescCache(this, name()+".TxDesc", p->rx_desc_cache_size),
-      txDescCache(this, name()+".RxDesc", p->tx_desc_cache_size), clock(p->clock)
+      rxDescCache(this, name()+".RxDesc", p->rx_desc_cache_size),
+      txDescCache(this, name()+".TxDesc", p->tx_desc_cache_size), clock(p->clock)
 {
     // Initialized internal registers per Intel documentation
     // All registers intialized to 0 by per register constructor
@@ -70,6 +70,7 @@ IGbE::IGbE(Params *p)
     regs.ctrl.frcspd(1);
     regs.sts.speed(3); // Say we're 1000Mbps
     regs.sts.fd(1); // full duplex
+    regs.sts.lu(1); // link up
     regs.eecd.fwe(1);
     regs.eecd.ee_type(1);
     regs.imr = 0;
@@ -89,14 +90,15 @@ IGbE::IGbE(Params *p)
     // clear all 64 16 bit words of the eeprom
     memset(&flash, 0, EEPROM_SIZE*2);
 
-    //We'll need to instert the MAC address into the flash
-    flash[0] = 0xA4A4;
-    flash[1] = 0xB6B6;
-    flash[2] = 0xC8C8;
+    // Set the MAC address
+    memcpy(flash, p->hardware_address.bytes(), ETH_ADDR_LEN);
+    for (int x = 0; x < ETH_ADDR_LEN/2; x++)
+        flash[x] = htobe(flash[x]);
 
     uint16_t csum = 0;
     for (int x = 0; x < EEPROM_SIZE; x++)
-        csum += flash[x];
+        csum += htobe(flash[x]);
+
 
     // Magic happy checksum value
     flash[EEPROM_SIZE-1] = htobe((uint16_t)(EEPROM_CSUM - csum));
@@ -137,7 +139,7 @@ IGbE::read(PacketPtr pkt)
     // Only 32bit accesses allowed
     assert(pkt->getSize() == 4);
 
-    //DPRINTF(Ethernet, "Read device register %#X\n", daddr);
+    DPRINTF(Ethernet, "Read device register %#X\n", daddr);
 
     pkt->allocate();
 
@@ -166,13 +168,16 @@ IGbE::read(PacketPtr pkt)
         pkt->set<uint32_t>(regs.mdic());
         break;
       case REG_ICR:
+        DPRINTF(Ethernet, "Reading ICR. ICR=%#x IMR=%#x IAM=%#x IAME=%d\n", regs.icr(),
+                regs.imr, regs.iam, regs.ctrl_ext.iame());
         pkt->set<uint32_t>(regs.icr());
-        if (regs.icr.int_assert())
-            regs.imr &= regs.iam;
-        if (regs.imr == 0 || (regs.icr.int_assert() && regs.ctrl_ext.iame())) {
-            regs.icr(0);
-            cpuClearInt();
+        if (regs.icr.int_assert() || regs.imr == 0) {
+            regs.icr = regs.icr() & ~mask(30);
+            DPRINTF(Ethernet, "Cleared ICR. ICR=%#x\n", regs.icr());
         }
+        if (regs.ctrl_ext.iame() && regs.icr.int_assert())
+            regs.imr &= ~regs.iam;
+        chkInterrupt();
         break;
       case REG_ITR:
         pkt->set<uint32_t>(regs.itr());
@@ -221,13 +226,6 @@ IGbE::read(PacketPtr pkt)
             postInterrupt(IT_RXT);
             regs.rdtr.fpd(0);
         }
-        if (regs.rdtr.delay()) {
-            Tick t = regs.rdtr.delay() * Clock::Int::ns * 1024;
-            if (rdtrEvent.scheduled())
-                rdtrEvent.reschedule(curTick + t);
-            else
-                rdtrEvent.schedule(curTick + t);
-        }
         break;
       case REG_RADV:
         pkt->set<uint32_t>(regs.radv());
@@ -292,7 +290,7 @@ IGbE::write(PacketPtr pkt)
     // Only 32bit accesses allowed
     assert(pkt->getSize() == sizeof(uint32_t));
 
-    //DPRINTF(Ethernet, "Wrote device register %#X value %#X\n", daddr, pkt->get<uint32_t>());
+    DPRINTF(Ethernet, "Wrote device register %#X value %#X\n", daddr, pkt->get<uint32_t>());
 
     ///
     /// Handle write of register here
@@ -398,19 +396,16 @@ IGbE::write(PacketPtr pkt)
                 break;
             default:
                 regs.mdic.data(0);
-                warn("Accessing unknown phy register %d\n", regs.mdic.regadd());
         }
         regs.mdic.r(1);
         break;
       case REG_ICR:
-        if (regs.icr.int_assert())
-            regs.imr &= regs.iam;
-
+        DPRINTF(Ethernet, "Writing ICR. ICR=%#x IMR=%#x IAM=%#x IAME=%d\n", regs.icr(),
+                regs.imr, regs.iam, regs.ctrl_ext.iame());
+        if (regs.ctrl_ext.iame())
+            regs.imr &= ~regs.iam;
         regs.icr = ~bits(val,30,0) & regs.icr();
-        // if no more bits are set clear the int_asserted bit
-        if (!bits(regs.icr(),31,31))
-            cpuClearInt();
-
+        chkInterrupt();
         break;
       case REG_ITR:
         regs.itr = val;
@@ -439,8 +434,7 @@ IGbE::write(PacketPtr pkt)
         }
         if (regs.rctl.en())
             rxTick = true;
-        if ((rxTick || txTick) && !tickEvent.scheduled())
-            tickEvent.schedule(curTick + cycles(1));
+        restartClock();
         break;
       case REG_FCTTV:
         regs.fcttv = val;
@@ -451,8 +445,7 @@ IGbE::write(PacketPtr pkt)
         regs.tctl = val;
         if (regs.tctl.en())
            txTick = true;
-       if ((rxTick || txTick) && !tickEvent.scheduled())
-            tickEvent.schedule(curTick + cycles(1));
+        restartClock();
         if (regs.tctl.en() && !oldtctl.en()) {
             txDescCache.reset();
         }
@@ -496,8 +489,7 @@ IGbE::write(PacketPtr pkt)
       case REG_RDT:
         regs.rdt = val;
         rxTick = true;
-       if ((rxTick || txTick) && !tickEvent.scheduled())
-            tickEvent.schedule(curTick + cycles(1));
+        restartClock();
         break;
       case REG_RDTR:
         regs.rdtr = val;
@@ -524,8 +516,7 @@ IGbE::write(PacketPtr pkt)
       case REG_TDT:
         regs.tdt = val;
         txTick = true;
-        if ((rxTick || txTick) && !tickEvent.scheduled())
-            tickEvent.schedule(curTick + cycles(1));
+        restartClock();
         break;
       case REG_TIDV:
         regs.tidv = val;
@@ -556,21 +547,23 @@ IGbE::write(PacketPtr pkt)
 void
 IGbE::postInterrupt(IntTypes t, bool now)
 {
+    assert(t);
+
     // Interrupt is already pending
     if (t & regs.icr())
         return;
 
     if (regs.icr() & regs.imr)
     {
-        // already in an interrupt state, set new int and done
         regs.icr = regs.icr() | t;
+        if (!interEvent.scheduled())
+            interEvent.schedule(curTick + Clock::Int::ns * 256 *
+                    regs.itr.interval());
     } else {
         regs.icr = regs.icr() | t;
         if (regs.itr.interval() == 0 || now) {
-            if (now) {
-                if (interEvent.scheduled())
-                    interEvent.deschedule();
-            }
+            if (interEvent.scheduled())
+                interEvent.deschedule();
             cpuPostInt();
         } else {
            DPRINTF(EthernetIntr, "EINT: Scheduling timer interrupt for %d ticks\n",
@@ -610,21 +603,35 @@ IGbE::cpuPostInt()
 void
 IGbE::cpuClearInt()
 {
-    regs.icr.int_assert(0);
-    DPRINTF(EthernetIntr, "EINT: Clearing interrupt to CPU now. Vector %#x\n",
-            regs.icr());
-    intrClear();
+    if (regs.icr.int_assert()) {
+        regs.icr.int_assert(0);
+        DPRINTF(EthernetIntr, "EINT: Clearing interrupt to CPU now. Vector %#x\n",
+                regs.icr());
+        intrClear();
+    }
 }
 
 void
 IGbE::chkInterrupt()
 {
     // Check if we need to clear the cpu interrupt
-    if (!(regs.icr() & regs.imr))
-        cpuClearInt();
+    if (!(regs.icr() & regs.imr)) {
+        if (interEvent.scheduled())
+           interEvent.deschedule();
+        if (regs.icr.int_assert())
+            cpuClearInt();
+    }
+
+    if (regs.icr() & regs.imr) {
+        if (regs.itr.interval() == 0)  {
+            cpuPostInt();
+        } else {
+            if (!interEvent.scheduled())
+               interEvent.schedule(curTick + Clock::Int::ns * 256 * regs.itr.interval());
+        }
+    }
+
 
-    // Check if we need to set the cpu interupt
-    postInterrupt(IT_NONE);
 }
 
 
@@ -638,6 +645,8 @@ bool
 IGbE::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());
 
     if (!unusedCache.size())
@@ -645,7 +654,8 @@ IGbE::RxDescCache::writePacket(EthPacketPtr packet)
 
     pktPtr = packet;
 
-    igbe->dmaWrite(unusedCache.front()->buf, packet->length, &pktEvent, packet->data);
+    igbe->dmaWrite(igbe->platform->pciToDma(unusedCache.front()->buf),
+            packet->length, &pktEvent, packet->data);
     return true;
 }
 
@@ -656,7 +666,13 @@ IGbE::RxDescCache::pktComplete()
     RxDesc *desc;
     desc = unusedCache.front();
 
-    desc->len = pktPtr->length;
+    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);
 
@@ -669,7 +685,7 @@ IGbE::RxDescCache::pktComplete()
         if (igbe->regs.rxcsum.ipofld()) {
             DPRINTF(EthernetDesc, "RxDesc: Checking IP checksum\n");
             status |= RXDS_IPCS;
-            desc->csum = cksum(ip);
+            desc->csum = htole(cksum(ip));
             if (cksum(ip) != 0) {
                 err |= RXDE_IPE;
                 DPRINTF(EthernetDesc, "RxDesc: Checksum is bad!!\n");
@@ -679,7 +695,7 @@ IGbE::RxDescCache::pktComplete()
         if (tcp && igbe->regs.rxcsum.tuofld()) {
             DPRINTF(EthernetDesc, "RxDesc: Checking TCP checksum\n");
             status |= RXDS_TCPCS;
-            desc->csum = cksum(tcp);
+            desc->csum = htole(cksum(tcp));
             if (cksum(tcp) != 0) {
                 DPRINTF(EthernetDesc, "RxDesc: Checksum is bad!!\n");
                 err |= RXDE_TCPE;
@@ -690,7 +706,7 @@ IGbE::RxDescCache::pktComplete()
         if (udp && igbe->regs.rxcsum.tuofld()) {
             DPRINTF(EthernetDesc, "RxDesc: Checking UDP checksum\n");
             status |= RXDS_UDPCS;
-            desc->csum = cksum(udp);
+            desc->csum = htole(cksum(udp));
             if (cksum(tcp) != 0) {
                 DPRINTF(EthernetDesc, "RxDesc: Checksum is bad!!\n");
                 err |= RXDE_TCPE;
@@ -698,8 +714,8 @@ IGbE::RxDescCache::pktComplete()
         }
     } // if ip
 
-    desc->status = status;
-    desc->errors = err;
+    desc->status = htole(status);
+    desc->errors = htole(err);
 
     // No vlan support at this point... just set it to 0
     desc->vlan = 0;
@@ -724,7 +740,14 @@ IGbE::RxDescCache::pktComplete()
                     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())
         igbe->postInterrupt(IT_SRPD);
 
@@ -740,9 +763,7 @@ void
 IGbE::RxDescCache::enableSm()
 {
     igbe->rxTick = true;
-    if ((igbe->rxTick || igbe->txTick) && !igbe->tickEvent.scheduled())
-        igbe->tickEvent.schedule((curTick/igbe->cycles(1)) * igbe->cycles(1) +
-                igbe->cycles(1));
+    igbe->restartClock();
 }
 
 bool
@@ -759,7 +780,7 @@ IGbE::RxDescCache::packetDone()
 
 IGbE::TxDescCache::TxDescCache(IGbE *i, const std::string n, int s)
     : DescCache<TxDesc>(i,n, s), pktDone(false), isTcp(false), pktWaiting(false),
-      pktEvent(this)
+      hLen(0), pktEvent(this)
 
 {
 }
@@ -813,7 +834,8 @@ IGbE::TxDescCache::getPacketData(EthPacketPtr p)
     pktWaiting = true;
 
     DPRINTF(EthernetDesc, "TxDesc: Starting DMA of packet\n");
-    igbe->dmaRead(TxdOp::getBuf(desc), TxdOp::getLen(desc), &pktEvent, p->data);
+    igbe->dmaRead(igbe->platform->pciToDma(TxdOp::getBuf(desc)),
+            TxdOp::getLen(desc), &pktEvent, p->data + hLen);
 
 
 }
@@ -828,9 +850,28 @@ IGbE::TxDescCache::pktComplete()
 
     DPRINTF(EthernetDesc, "TxDesc: 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)) {
+        assert(hLen == 0);
+        hLen = TxdOp::getLen(desc);
+        unusedCache.pop_front();
+        usedCache.push_back(desc);
+        pktDone = true;
+        pktWaiting = false;
+        pktPtr = NULL;
+
+        DPRINTF(EthernetDesc, "TxDesc: Partial Packet Descriptor Done\n");
+        return;
+    }
+
+    // Set the length of the data in the EtherPacket
+    pktPtr->length = TxdOp::getLen(desc) + hLen;
+
     // no support for vlans
     assert(!TxdOp::vle(desc));
 
@@ -843,6 +884,8 @@ IGbE::TxDescCache::pktComplete()
     // set that this packet is done
     TxdOp::setDd(desc);
 
+    DPRINTF(EthernetDesc, "TxDescriptor data d1: %#llx d2: %#llx\n", desc->d1, desc->d2);
+
     // 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");
@@ -888,13 +931,25 @@ IGbE::TxDescCache::pktComplete()
         }
     }
 
+
+
     unusedCache.pop_front();
     usedCache.push_back(desc);
     pktDone = true;
     pktWaiting = false;
     pktPtr = NULL;
 
+    hLen = 0;
     DPRINTF(EthernetDesc, "TxDesc: Descriptor Done\n");
+
+    if (igbe->regs.txdctl.wthresh() == 0) {
+        DPRINTF(EthernetDesc, "TxDesc: 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");
+        writeback((igbe->cacheBlockSize()-1)>>4);
+    }
+
 }
 
 bool
@@ -911,9 +966,7 @@ void
 IGbE::TxDescCache::enableSm()
 {
     igbe->txTick = true;
-    if ((igbe->rxTick || igbe->txTick) && !igbe->tickEvent.scheduled())
-        igbe->tickEvent.schedule((curTick/igbe->cycles(1)) * igbe->cycles(1) +
-                igbe->cycles(1));
+    igbe->restartClock();
 }
 
 
@@ -921,16 +974,27 @@ IGbE::TxDescCache::enableSm()
 
 ///////////////////////////////////// IGbE /////////////////////////////////
 
+void
+IGbE::restartClock()
+{
+    if (!tickEvent.scheduled() && (rxTick || txTick))
+        tickEvent.schedule((curTick/cycles(1)) * cycles(1) + cycles(1));
+}
+
+
 void
 IGbE::txStateMachine()
 {
     if (!regs.tctl.en()) {
         txTick = false;
-        DPRINTF(EthernetSM, "TXS: RX disabled, stopping ticking\n");
+        DPRINTF(EthernetSM, "TXS: TX disabled, stopping ticking\n");
         return;
     }
 
-    if (txPacket && txDescCache.packetAvailable()) {
+    // If we have a packet available and it's length is not 0 (meaning it's not
+    // a multidescriptor packet) put it in the fifo, otherwise an the next
+    // iteration we'll get the rest of the data
+    if (txPacket && txDescCache.packetAvailable() && txPacket->length) {
         bool success;
         DPRINTF(EthernetSM, "TXS: packet placed in TX FIFO\n");
         success = txFifo.push(txPacket);
@@ -952,25 +1016,27 @@ IGbE::txStateMachine()
 
     if (!txDescCache.packetWaiting()) {
         if (txDescCache.descLeft() == 0) {
-            DPRINTF(EthernetSM, "TXS: No descriptors left in ring, forcing writeback\n");
+            DPRINTF(EthernetSM, "TXS: No descriptors left in ring, forcing "
+                    "writeback stopping ticking and posting TXQE\n");
             txDescCache.writeback(0);
-            DPRINTF(EthernetSM, "TXS: No descriptors left, stopping ticking\n");
             txTick = false;
+            postInterrupt(IT_TXQE, true);
         }
 
+
         if (!(txDescCache.descUnused())) {
-            DPRINTF(EthernetSM, "TXS: No descriptors available in cache, stopping ticking\n");
+            DPRINTF(EthernetSM, "TXS: No descriptors available in cache, fetching and stopping ticking\n");
             txTick = false;
-            DPRINTF(EthernetSM, "TXS: No descriptors left, fetching\n");
             txDescCache.fetchDescriptors();
             return;
         }
 
         int size;
         size = txDescCache.getPacketSize();
-        if (size > 0 && rxFifo.avail() > size) {
-            DPRINTF(EthernetSM, "TXS: Reserving %d bytes in FIFO and begining DMA of next packet\n");
-            rxFifo.reserve(size);
+        if (size > 0 && txFifo.avail() > size) {
+            DPRINTF(EthernetSM, "TXS: Reserving %d bytes in FIFO and begining "
+                    "DMA of next packet\n", size);
+            txFifo.reserve(size);
             txDescCache.getPacketData(txPacket);
         } else {
             DPRINTF(EthernetSM, "TXS: No packets to get, writing back used descriptors\n");
@@ -994,7 +1060,7 @@ IGbE::ethRxPkt(EthPacketPtr pkt)
     rxTick = true;
     if ((rxTick || txTick) && !tickEvent.scheduled()) {
         DPRINTF(EthernetSM, "RXS: received packet into fifo, starting ticking\n");
-        tickEvent.schedule(curTick/cycles(1) + cycles(1));
+        restartClock();
     }
 
     if (!rxFifo.push(pkt)) {
@@ -1040,7 +1106,10 @@ IGbE::rxStateMachine()
 
         if (regs.rxdctl.wthresh() >= rxDescCache.descUsed()) {
             DPRINTF(EthernetSM, "RXS: Writing back because WTHRESH >= descUsed\n");
-            rxDescCache.writeback(cacheBlockSize()-1);
+            if (regs.rxdctl.wthresh() < (cacheBlockSize()>>4))
+                rxDescCache.writeback(regs.rxdctl.wthresh()-1);
+            else
+                rxDescCache.writeback((cacheBlockSize()-1)>>4);
         }
 
         if ((rxDescCache.descUnused() < regs.rxdctl.pthresh()) &&
@@ -1101,16 +1170,12 @@ IGbE::txWire()
         txFifo.pop();
     }
 
-    if (txFifo.empty()) {
-        postInterrupt(IT_TXQE);
-        DPRINTF(Ethernet, "TxFIFO: Empty, posting interruppt\n");
-    }
 }
 
 void
 IGbE::tick()
 {
-    DPRINTF(EthernetSM, "IGbE: -------------- Cycle -------------- ");
+    DPRINTF(EthernetSM, "IGbE: -------------- Cycle --------------\n");
 
     if (rxTick)
         rxStateMachine();
@@ -1129,8 +1194,7 @@ IGbE::ethTxDone()
 {
     // restart the state machines if they are stopped
     txTick = true;
-    if ((rxTick || txTick) && !tickEvent.scheduled())
-        tickEvent.schedule(curTick/cycles(1) + cycles(1));
+    restartClock();
     DPRINTF(Ethernet, "TxFIFO: Transmission complete\n");
 }
 
@@ -1187,6 +1251,14 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(IGbE)
     Param<uint32_t> pci_func;
     Param<Tick> pio_latency;
     Param<Tick> config_latency;
+    Param<std::string> hardware_address;
+    Param<bool> use_flow_control;
+    Param<int> rx_fifo_size;
+    Param<int> tx_fifo_size;
+    Param<int> rx_desc_cache_size;
+    Param<int> tx_desc_cache_size;
+    Param<Tick> clock;
+
 
 END_DECLARE_SIM_OBJECT_PARAMS(IGbE)
 
@@ -1199,7 +1271,14 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(IGbE)
     INIT_PARAM(pci_dev, "PCI device number"),
     INIT_PARAM(pci_func, "PCI function code"),
     INIT_PARAM_DFLT(pio_latency, "Programmed IO latency in bus cycles", 1),
-    INIT_PARAM(config_latency, "Number of cycles for a config read or write")
+    INIT_PARAM(config_latency, "Number of cycles for a config read or write"),
+    INIT_PARAM(hardware_address, "Ethernet Hardware Address"),
+    INIT_PARAM(use_flow_control,"Should the device use xon/off packets"),
+    INIT_PARAM(rx_fifo_size,"Size of the RX FIFO"),
+    INIT_PARAM(tx_fifo_size,"Size of the TX FIFO"),
+    INIT_PARAM(rx_desc_cache_size,"Size of the RX descriptor cache"),
+    INIT_PARAM(tx_desc_cache_size,"Size of the TX descriptor cache"),
+    INIT_PARAM(clock,"Clock rate for the device to tick at")
 
 END_INIT_SIM_OBJECT_PARAMS(IGbE)
 
@@ -1217,6 +1296,14 @@ CREATE_SIM_OBJECT(IGbE)
     params->functionNum = pci_func;
     params->pio_delay = pio_latency;
     params->config_delay = config_latency;
+    params->hardware_address = hardware_address;
+    params->use_flow_control = use_flow_control;
+    params->rx_fifo_size = rx_fifo_size;
+    params->tx_fifo_size = tx_fifo_size;
+    params->rx_desc_cache_size = rx_desc_cache_size;
+    params->tx_desc_cache_size = tx_desc_cache_size;
+    params->clock = clock;
+
 
     return new IGbE(params);
 }
index d7d20ae50852b7939d41dc3a387041544e4c23a4..a2b9f38d58cf2c0e740d4e99947042be7e9b0eeb 100644 (file)
@@ -78,12 +78,12 @@ class IGbE : public PciDev
     bool txTick;
 
     // Event and function to deal with RDTR timer expiring
-    void rdtrProcess() { postInterrupt(iGbReg::IT_RXDMT, true); }
+    void rdtrProcess() { rxDescCache.writeback(0); 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() { postInterrupt(iGbReg::IT_RXDMT, true); }
+    void radvProcess() { rxDescCache.writeback(0); postInterrupt(iGbReg::IT_RXT, true); }
     //friend class EventWrapper<IGbE, &IGbE::radvProcess>;
     EventWrapper<IGbE, &IGbE::radvProcess> radvEvent;
 
@@ -131,6 +131,8 @@ class IGbE : public PciDev
 
     Tick intClock() { return Clock::Int::ns * 1024; }
 
+    void restartClock();
+
     template<class T>
     class DescCache
     {
@@ -141,6 +143,7 @@ class IGbE : public PciDev
         virtual long descLen() const = 0;
         virtual void updateHead(long h) = 0;
         virtual void enableSm() = 0;
+        virtual void intAfterWb() const {}
 
         std::deque<T*> usedCache;
         std::deque<T*> unusedCache;
@@ -206,7 +209,7 @@ class IGbE : public PciDev
         void writeback(Addr aMask)
         {
             int curHead = descHead();
-            int max_to_wb = usedCache.size() + curHead;
+            int max_to_wb = usedCache.size();
 
             DPRINTF(EthernetDesc, "Writing back descriptors head: %d tail: "
                     "%d len: %d cachePnt: %d max_to_wb: %d descleft: %d\n",
@@ -226,13 +229,13 @@ class IGbE : public PciDev
             moreToWb = false;
             wbAlignment = aMask;
 
-            if (max_to_wb > descLen()) {
+            if (max_to_wb + curHead > descLen()) {
                 max_to_wb = descLen() - curHead;
                 moreToWb = true;
                 // this is by definition aligned correctly
             } else if (aMask != 0) {
                 // align the wb point to the mask
-                max_to_wb = max_to_wb & ~(aMask>>4);
+                max_to_wb = max_to_wb & ~aMask;
             }
 
             DPRINTF(EthernetDesc, "Writing back %d descriptors\n", max_to_wb);
@@ -240,7 +243,7 @@ class IGbE : public PciDev
             if (max_to_wb <= 0 || wbOut)
                 return;
 
-            wbOut = max_to_wb - curHead;
+            wbOut = max_to_wb;
 
             for (int x = 0; x < wbOut; x++)
                 memcpy(&wbBuf[x], usedCache[x], sizeof(T));
@@ -251,8 +254,10 @@ class IGbE : public PciDev
                 usedCache.pop_front();
             };
 
-            igbe->dmaWrite(descBase() + curHead * sizeof(T), wbOut * sizeof(T),
-                    &wbEvent, (uint8_t*)wbBuf);
+
+            assert(wbOut);
+            igbe->dmaWrite(igbe->platform->pciToDma(descBase() + curHead * sizeof(T)),
+                    wbOut * sizeof(T), &wbEvent, (uint8_t*)wbBuf);
         }
 
         /** Fetch a chunk of descriptors into the descriptor cache.
@@ -260,7 +265,7 @@ class IGbE : public PciDev
          */
         void fetchDescriptors()
         {
-            size_t max_to_fetch = cachePnt - descTail();
+            size_t max_to_fetch = descTail() - cachePnt;
             if (max_to_fetch < 0)
                 max_to_fetch = descLen() - cachePnt;
 
@@ -268,7 +273,7 @@ class IGbE : public PciDev
                         unusedCache.size()));
 
             DPRINTF(EthernetDesc, "Fetching descriptors head: %d tail: "
-                    "%d len: %d cachePnt: %d max_to_wb: %d descleft: %d\n",
+                    "%d len: %d cachePnt: %d max_to_fetch: %d descleft: %d\n",
                     descHead(), descTail(), descLen(), cachePnt,
                     max_to_fetch, descLeft());
 
@@ -279,7 +284,13 @@ class IGbE : public PciDev
             // So we don't have two descriptor fetches going on at once
             curFetching = max_to_fetch;
 
-            igbe->dmaRead(descBase() + cachePnt * sizeof(T),
+            DPRINTF(EthernetDesc, "Fetching descriptors at %#x (%#x), size: %#x\n",
+                    descBase() + cachePnt * sizeof(T),
+                    igbe->platform->pciToDma(descBase() + cachePnt * sizeof(T)),
+                    curFetching * sizeof(T));
+
+            assert(curFetching);
+            igbe->dmaRead(igbe->platform->pciToDma(descBase() + cachePnt * sizeof(T)),
                     curFetching * sizeof(T), &fetchEvent, (uint8_t*)fetchBuf);
         }
 
@@ -303,6 +314,8 @@ class IGbE : public PciDev
             if (cachePnt > descLen())
                 cachePnt -= descLen();
 
+            curFetching = 0;
+
             DPRINTF(EthernetDesc, "Fetching complete cachePnt %d -> %d\n",
                     oldCp, cachePnt);
 
@@ -330,7 +343,7 @@ class IGbE : public PciDev
             // Update the head
             updateHead(curHead);
 
-            DPRINTF(EthernetDesc, "Writeback complete cachePnt %d -> %d\n",
+            DPRINTF(EthernetDesc, "Writeback complete curHead %d -> %d\n",
                     oldHead, curHead);
 
             // If we still have more to wb, call wb now
@@ -338,6 +351,7 @@ class IGbE : public PciDev
                 DPRINTF(EthernetDesc, "Writeback has more todo\n");
                 writeback(wbAlignment);
             }
+            intAfterWb();
         }
 
 
@@ -352,7 +366,7 @@ class IGbE : public PciDev
             if (cachePnt - descTail() >= 0)
                 left += (cachePnt - descTail());
             else
-                left += (descLen() - cachePnt);
+                left += (descTail() - cachePnt);
 
             return left;
         }
@@ -428,10 +442,12 @@ class IGbE : public PciDev
         virtual long descLen() const { return igbe->regs.tdlen() >> 4; }
         virtual void updateHead(long h) { igbe->regs.tdh(h); }
         virtual void enableSm();
+        virtual void intAfterWb() const { igbe->postInterrupt(iGbReg::IT_TXDW);}
 
         bool pktDone;
         bool isTcp;
         bool pktWaiting;
+        int hLen;
 
       public:
         TxDescCache(IGbE *i, std::string n, int s);
@@ -467,6 +483,7 @@ class IGbE : public PciDev
   public:
     struct Params : public PciDev::Params
     {
+        Net::EthAddr hardware_address;
         bool use_flow_control;
         int rx_fifo_size;
         int tx_fifo_size;
index d9648a7c210067bf1533f78a612b467148d8ef78..8538c155b531c83102aab8ffec4f13a1ea5a1f6a 100644 (file)
@@ -173,18 +173,18 @@ Addr getBuf(TxDesc *d) { assert(isLegacy(d) || isData(d)); return d->d1; }
 Addr getLen(TxDesc *d) { if (isLegacy(d)) return bits(d->d2,15,0); else return bits(d->d2, 19,0); }
 void setDd(TxDesc *d)
 {
-    replaceBits(d->d1, 35, 32, 1);
+    replaceBits(d->d2, 35, 32, ULL(1));
 }
 
 bool ide(TxDesc *d)  { return bits(d->d2, 31,31); }
 bool vle(TxDesc *d)  { assert(isLegacy(d) || isData(d)); return bits(d->d2, 30,30); }
-bool rs(TxDesc *d)   { return bits(d->d2, 28,28); }
-bool ic(TxDesc *d)   { assert(isLegacy(d) || isData(d)); return isLegacy(d) && bits(d->d2, 27,27); }
-bool tse(TxDesc *d)  { return (isData(d) || isContext(d)) && bits(d->d2, 27,27); }
-bool ifcs(TxDesc *d) { assert(isLegacy(d) || isData(d)); return bits(d->d2, 26,26); }
-bool eop(TxDesc *d)  { assert(isLegacy(d) || isData(d)); return bits(d->d2, 25,25); }
-bool ip(TxDesc *d)   { assert(isContext(d)); return bits(d->d2, 26,26); }
-bool tcp(TxDesc *d)  { assert(isContext(d)); return bits(d->d2, 25,25); }
+bool rs(TxDesc *d)   { return bits(d->d2, 27,27); }
+bool ic(TxDesc *d)   { assert(isLegacy(d) || isData(d)); return isLegacy(d) && bits(d->d2, 26,26); }
+bool tse(TxDesc *d)  { return (isData(d) || isContext(d)) && bits(d->d2, 26,26); }
+bool ifcs(TxDesc *d) { assert(isLegacy(d) || isData(d)); return bits(d->d2, 25,25); }
+bool eop(TxDesc *d)  { assert(isLegacy(d) || isData(d)); return bits(d->d2, 24,24); }
+bool ip(TxDesc *d)   { assert(isContext(d)); return bits(d->d2, 25,25); }
+bool tcp(TxDesc *d)  { assert(isContext(d)); return bits(d->d2, 24,24); }
 
 uint8_t getCso(TxDesc *d) { assert(isLegacy(d)); return bits(d->d2, 23,16); }
 uint8_t getCss(TxDesc *d) { assert(isLegacy(d)); return bits(d->d2, 47,40); }
@@ -351,7 +351,7 @@ struct Regs {
         ADD_FIELD32(txdlow,15,1) // transmit desc low thresh
         ADD_FIELD32(srpd,16,1)   // small receive packet detected
         ADD_FIELD32(ack,17,1);    // receive ack frame
-        ADD_FIELD32(int_assert, 31,0); // interrupt caused a system interrupt
+        ADD_FIELD32(int_assert, 31,1); // interrupt caused a system interrupt
     };
     ICR icr;
 
@@ -393,10 +393,10 @@ struct Regs {
         int descSize()
         {
             switch(bsize()) {
-                case 0: return bsex() ? 2048 : -1;
-                case 1: return bsex() ? 1024 : 16384;
-                case 2: return bsex() ? 512 : 8192;
-                case 3: return bsex() ? 256 : 4096;
+                case 0: return bsex() == 0 ? 2048 : -1;
+                case 1: return bsex() == 0 ? 1024 : 16384;
+                case 2: return bsex() == 0 ? 512 : 8192;
+                case 3: return bsex() == 0 ? 256 : 4096;
                 default:
                         return -1;
             }
@@ -451,7 +451,7 @@ struct Regs {
 
     struct RDBA : public Reg<uint64_t> { // 0x2800 RDBA Register
         using Reg<uint64_t>::operator=;
-        ADD_FIELD64(rdbal,4,28); // base address of rx descriptor ring
+        ADD_FIELD64(rdbal,0,32); // base address of rx descriptor ring
         ADD_FIELD64(rdbah,32,32); // base address of rx descriptor ring
     };
     RDBA rdba;
@@ -506,7 +506,7 @@ struct Regs {
 
     struct TDBA : public Reg<uint64_t> { // 0x3800 TDBAL Register
         using Reg<uint64_t>::operator=;
-        ADD_FIELD64(tdbal,4,28); // base address of transmit descriptor ring
+        ADD_FIELD64(tdbal,0,32); // base address of transmit descriptor ring
         ADD_FIELD64(tdbah,32,32); // base address of transmit descriptor ring
     };
     TDBA tdba;
index a52e35511ea475968daffe1791fff16279db7204..bfe30950c9d9f430d4f725e23821d409f9913754 100644 (file)
@@ -67,7 +67,14 @@ if build_env['ALPHA_TLASER']:
 
 class IGbE(PciDevice):
     type = 'IGbE'
-    hardware_address = Param.EthernetAddr(NextEthernetAddr, "Ethernet Hardware Address")
+    hardware_address = Param.String("Ethernet Hardware Address")
+    use_flow_control = Param.Bool(False, "Should we use xon/xoff flow contorl (UNIMPLMENTD)")
+    rx_fifo_size = Param.MemorySize('384kB', "Size of the rx FIFO")
+    tx_fifo_size = Param.MemorySize('384kB', "Size of the tx FIFO")
+    rx_desc_cache_size = Param.Int(64, "Number of enteries in the rx descriptor cache")
+    tx_desc_cache_size = Param.Int(64, "Number of enteries in the rx descriptor cache")
+    clock = Param.Clock('500MHz', "Clock speed of the device")
+
 
 class IGbEPciData(PciConfigData):
     VendorID = 0x8086