sinic.cc revision 8851
12SN/A/*
22188SN/A * Copyright (c) 2004-2005 The Regents of The University of Michigan
32SN/A * All rights reserved.
42SN/A *
52SN/A * Redistribution and use in source and binary forms, with or without
62SN/A * modification, are permitted provided that the following conditions are
72SN/A * met: redistributions of source code must retain the above copyright
82SN/A * notice, this list of conditions and the following disclaimer;
92SN/A * redistributions in binary form must reproduce the above copyright
102SN/A * notice, this list of conditions and the following disclaimer in the
112SN/A * documentation and/or other materials provided with the distribution;
122SN/A * neither the name of the copyright holders nor the names of its
132SN/A * contributors may be used to endorse or promote products derived from
142SN/A * this software without specific prior written permission.
152SN/A *
162SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
172SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
182SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
192SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
202SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
212SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
222SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
232SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
242SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
252SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
262SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
272665SN/A *
282665SN/A * Authors: Nathan Binkert
292665SN/A */
302665SN/A
312665SN/A#include <deque>
322SN/A#include <limits>
332SN/A#include <string>
342SN/A
352SN/A#include "arch/vtophys.hh"
362465SN/A#include "base/compiler.hh"
373565Sgblack@eecs.umich.edu#include "base/debug.hh"
385529Snate@binkert.org#include "base/inet.hh"
398777Sgblack@eecs.umich.edu#include "base/types.hh"
401917SN/A#include "config/the_isa.hh"
411070SN/A#include "cpu/intr_control.hh"
421917SN/A#include "cpu/thread_context.hh"
432188SN/A#include "debug/EthernetAll.hh"
448777Sgblack@eecs.umich.edu#include "dev/etherlink.hh"
458777Sgblack@eecs.umich.edu#include "dev/sinic.hh"
461917SN/A#include "mem/packet.hh"
472290SN/A#include "mem/packet_access.hh"
488777Sgblack@eecs.umich.edu#include "sim/eventq.hh"
498777Sgblack@eecs.umich.edu#include "sim/stats.hh"
508706Sandreas.hansson@arm.com
518799Sgblack@eecs.umich.eduusing namespace std;
528809Sgblack@eecs.umich.eduusing namespace Net;
5310319SAndreas.Sandberg@ARM.comusing namespace TheISA;
548793Sgblack@eecs.umich.edu
558777Sgblack@eecs.umich.edunamespace Sinic {
561070SN/A
571917SN/Aconst char *RxStateStrings[] =
582519SN/A{
592SN/A    "rxIdle",
602SN/A    "rxFifoBlock",
612SN/A    "rxBeginCopy",
622SN/A    "rxCopy",
638820Sgblack@eecs.umich.edu    "rxCopyDone"
648820Sgblack@eecs.umich.edu};
659384SAndreas.Sandberg@arm.com
6610537Sandreas.hansson@arm.comconst char *TxStateStrings[] =
6710537Sandreas.hansson@arm.com{
689384SAndreas.Sandberg@arm.com    "txIdle",
698766Sgblack@eecs.umich.edu    "txFifoBlock",
708766Sgblack@eecs.umich.edu    "txBeginCopy",
718766Sgblack@eecs.umich.edu    "txCopy",
728766Sgblack@eecs.umich.edu    "txCopyDone"
739377Sgblack@eecs.umich.edu};
742683Sktlim@umich.edu
756022Sgblack@eecs.umich.edu
769384SAndreas.Sandberg@arm.com///////////////////////////////////////////////////////////////////////
779384SAndreas.Sandberg@arm.com//
789384SAndreas.Sandberg@arm.com// Sinic PCI Device
792SN/A//
802683Sktlim@umich.eduBase::Base(const Params *p)
812190SN/A    : PciDev(p), rxEnable(false), txEnable(false), clock(p->clock),
822680SN/A      intrDelay(p->intr_delay), intrTick(0), cpuIntrEnable(false),
832290SN/A      cpuPendingIntr(false), intrEvent(0), interface(NULL)
846316Sgblack@eecs.umich.edu{
851917SN/A}
868735Sandreas.hanson@arm.com
871982SN/ADevice::Device(const Params *p)
881917SN/A    : Base(p), rxUnique(0), txUnique(0),
892683Sktlim@umich.edu      virtualRegs(p->virtual_count < 1 ? 1 : p->virtual_count),
902683Sktlim@umich.edu      rxFifo(p->rx_fifo_size), txFifo(p->tx_fifo_size),
911917SN/A      rxKickTick(0), txKickTick(0),
921917SN/A      txEvent(this), rxDmaEvent(this), txDmaEvent(this),
931917SN/A      dmaReadDelay(p->dma_read_delay), dmaReadFactor(p->dma_read_factor),
941917SN/A      dmaWriteDelay(p->dma_write_delay), dmaWriteFactor(p->dma_write_factor)
951917SN/A{
961917SN/A    interface = new Interface(name() + ".int0", this);
971917SN/A    reset();
981917SN/A
992521SN/A}
1005482Snate@binkert.org
1013548Sgblack@eecs.umich.eduDevice::~Device()
1022SN/A{}
1032862Sktlim@umich.edu
1042683Sktlim@umich.eduvoid
1051070SN/ADevice::regStats()
1062680SN/A{
1071070SN/A    rxBytes
1081070SN/A        .name(name() + ".rxBytes")
1091917SN/A        .desc("Bytes Received")
1102683Sktlim@umich.edu        .prereq(rxBytes)
111180SN/A        ;
1129441SAndreas.Sandberg@ARM.com
1139478Snilay@cs.wisc.edu    rxBandwidth
114180SN/A        .name(name() + ".rxBandwidth")
1159441SAndreas.Sandberg@ARM.com        .desc("Receive Bandwidth (bits/s)")
1169441SAndreas.Sandberg@ARM.com        .precision(0)
117180SN/A        .prereq(rxBytes)
1182864Sktlim@umich.edu        ;
1192864Sktlim@umich.edu
1202864Sktlim@umich.edu    rxPackets
1212862Sktlim@umich.edu        .name(name() + ".rxPackets")
1222862Sktlim@umich.edu        .desc("Number of Packets Received")
1232862Sktlim@umich.edu        .prereq(rxBytes)
1242862Sktlim@umich.edu        ;
1252862Sktlim@umich.edu
1268793Sgblack@eecs.umich.edu    rxPacketRate
1278793Sgblack@eecs.umich.edu        .name(name() + ".rxPPS")
1285714Shsul@eecs.umich.edu        .desc("Packet Reception Rate (packets/s)")
1295715Shsul@eecs.umich.edu        .precision(0)
1305714Shsul@eecs.umich.edu        .prereq(rxBytes)
1312862Sktlim@umich.edu        ;
1322862Sktlim@umich.edu
1332862Sktlim@umich.edu    rxIpPackets
1342683Sktlim@umich.edu        .name(name() + ".rxIpPackets")
135217SN/A        .desc("Number of IP Packets Received")
1362862Sktlim@umich.edu        .prereq(rxBytes)
1379428SAndreas.Sandberg@ARM.com        ;
138217SN/A
139217SN/A    rxTcpPackets
140217SN/A        .name(name() + ".rxTcpPackets")
141217SN/A        .desc("Number of Packets Received")
1422683Sktlim@umich.edu        .prereq(rxBytes)
143217SN/A        ;
1442862Sktlim@umich.edu
1459428SAndreas.Sandberg@ARM.com    rxUdpPackets
146217SN/A        .name(name() + ".rxUdpPackets")
147217SN/A        .desc("Number of UDP Packets Received")
1482683Sktlim@umich.edu        .prereq(rxBytes)
1499461Snilay@cs.wisc.edu        ;
1509461Snilay@cs.wisc.edu
1519461Snilay@cs.wisc.edu    rxIpChecksums
1529461Snilay@cs.wisc.edu        .name(name() + ".rxIpChecksums")
1539461Snilay@cs.wisc.edu        .desc("Number of rx IP Checksums done by device")
1549461Snilay@cs.wisc.edu        .precision(0)
1552683Sktlim@umich.edu        .prereq(rxBytes)
1562683Sktlim@umich.edu        ;
1578735Sandreas.hanson@arm.com
1588735Sandreas.hanson@arm.com    rxTcpChecksums
1592683Sktlim@umich.edu        .name(name() + ".rxTcpChecksums")
1602683Sktlim@umich.edu        .desc("Number of rx TCP Checksums done by device")
161217SN/A        .precision(0)
162217SN/A        .prereq(rxBytes)
16310407Smitch.hayenga@arm.com        ;
1642SN/A
1652680SN/A    rxUdpChecksums
1662SN/A        .name(name() + ".rxUdpChecksums")
1672SN/A        .desc("Number of rx UDP Checksums done by device")
1687823Ssteve.reinhardt@amd.com        .precision(0)
1692680SN/A        .prereq(rxBytes)
17010407Smitch.hayenga@arm.com        ;
171393SN/A
172393SN/A    totBandwidth
173393SN/A        .name(name() + ".totBandwidth")
1742683Sktlim@umich.edu        .desc("Total Bandwidth (bits/s)")
175393SN/A        .precision(0)
1762680SN/A        .prereq(totBytes)
177393SN/A        ;
178393SN/A
1797823Ssteve.reinhardt@amd.com    totPackets
1807823Ssteve.reinhardt@amd.com        .name(name() + ".totPackets")
1812680SN/A        .desc("Total Packets")
1828735Sandreas.hanson@arm.com        .precision(0)
1832SN/A        .prereq(totBytes)
1842SN/A        ;
185393SN/A
186393SN/A    totBytes
1872683Sktlim@umich.edu        .name(name() + ".totBytes")
188393SN/A        .desc("Total Bytes")
1892680SN/A        .precision(0)
190393SN/A        .prereq(totBytes)
191393SN/A        ;
1922680SN/A
1938735Sandreas.hanson@arm.com    totPacketRate
194393SN/A        .name(name() + ".totPPS")
195393SN/A        .desc("Total Tranmission Rate (packets/s)")
196393SN/A        .precision(0)
197393SN/A        .prereq(totBytes)
1982683Sktlim@umich.edu        ;
1992SN/A
2008793Sgblack@eecs.umich.edu    txBytes
2012341SN/A        .name(name() + ".txBytes")
2022SN/A        .desc("Bytes Transmitted")
203716SN/A        .prereq(txBytes)
204716SN/A        ;
2052683Sktlim@umich.edu
2062190SN/A    txBandwidth
2072680SN/A        .name(name() + ".txBandwidth")
2082190SN/A        .desc("Transmit Bandwidth (bits/s)")
2092190SN/A        .precision(0)
21010319SAndreas.Sandberg@ARM.com        .prereq(txBytes)
21110319SAndreas.Sandberg@ARM.com        ;
21210319SAndreas.Sandberg@ARM.com
21310319SAndreas.Sandberg@ARM.com    txPackets
21410319SAndreas.Sandberg@ARM.com        .name(name() + ".txPackets")
21510319SAndreas.Sandberg@ARM.com        .desc("Number of Packets Transmitted")
21610319SAndreas.Sandberg@ARM.com        .prereq(txBytes)
21710319SAndreas.Sandberg@ARM.com        ;
21810319SAndreas.Sandberg@ARM.com
21910319SAndreas.Sandberg@ARM.com    txPacketRate
22010319SAndreas.Sandberg@ARM.com        .name(name() + ".txPPS")
22110319SAndreas.Sandberg@ARM.com        .desc("Packet Tranmission Rate (packets/s)")
22210319SAndreas.Sandberg@ARM.com        .precision(0)
22310319SAndreas.Sandberg@ARM.com        .prereq(txBytes)
22410319SAndreas.Sandberg@ARM.com        ;
225
226    txIpPackets
227        .name(name() + ".txIpPackets")
228        .desc("Number of IP Packets Transmitted")
229        .prereq(txBytes)
230        ;
231
232    txTcpPackets
233        .name(name() + ".txTcpPackets")
234        .desc("Number of TCP Packets Transmitted")
235        .prereq(txBytes)
236        ;
237
238    txUdpPackets
239        .name(name() + ".txUdpPackets")
240        .desc("Number of Packets Transmitted")
241        .prereq(txBytes)
242        ;
243
244    txIpChecksums
245        .name(name() + ".txIpChecksums")
246        .desc("Number of tx IP Checksums done by device")
247        .precision(0)
248        .prereq(txBytes)
249        ;
250
251    txTcpChecksums
252        .name(name() + ".txTcpChecksums")
253        .desc("Number of tx TCP Checksums done by device")
254        .precision(0)
255        .prereq(txBytes)
256        ;
257
258    txUdpChecksums
259        .name(name() + ".txUdpChecksums")
260        .desc("Number of tx UDP Checksums done by device")
261        .precision(0)
262        .prereq(txBytes)
263        ;
264
265    txBandwidth = txBytes * Stats::constant(8) / simSeconds;
266    rxBandwidth = rxBytes * Stats::constant(8) / simSeconds;
267    totBandwidth = txBandwidth + rxBandwidth;
268    totBytes = txBytes + rxBytes;
269    totPackets = txPackets + rxPackets;
270    txPacketRate = txPackets / simSeconds;
271    rxPacketRate = rxPackets / simSeconds;
272
273    _maxVnicDistance = 0;
274
275    maxVnicDistance
276        .name(name() + ".maxVnicDistance")
277        .desc("maximum vnic distance")
278        ;
279
280    totalVnicDistance
281        .name(name() + ".totalVnicDistance")
282        .desc("total vnic distance")
283        ;
284    numVnicDistance
285        .name(name() + ".numVnicDistance")
286        .desc("number of vnic distance measurements")
287        ;
288
289    avgVnicDistance
290        .name(name() + ".avgVnicDistance")
291        .desc("average vnic distance")
292        ;
293
294    avgVnicDistance = totalVnicDistance / numVnicDistance;
295}
296
297void
298Device::resetStats()
299{
300    _maxVnicDistance = 0;
301}
302
303EtherInt*
304Device::getEthPort(const std::string &if_name, int idx)
305{
306    if (if_name == "interface") {
307        if (interface->getPeer())
308            panic("interface already connected to\n");
309
310        return interface;
311    }
312    return NULL;
313}
314
315
316void
317Device::prepareIO(int cpu, int index)
318{
319    int size = virtualRegs.size();
320    if (index > size)
321        panic("Trying to access a vnic that doesn't exist %d > %d\n",
322              index, size);
323}
324
325//add stats for head of line blocking
326//add stats for average fifo length
327//add stats for average number of vnics busy
328
329void
330Device::prepareRead(int cpu, int index)
331{
332    using namespace Regs;
333    prepareIO(cpu, index);
334
335    VirtualReg &vnic = virtualRegs[index];
336
337    // update rx registers
338    uint64_t rxdone = vnic.RxDone;
339    rxdone = set_RxDone_Packets(rxdone, rxFifo.countPacketsAfter(rxFifoPtr));
340    rxdone = set_RxDone_Empty(rxdone, rxFifo.empty());
341    rxdone = set_RxDone_High(rxdone, rxFifo.size() > regs.RxFifoHigh);
342    rxdone = set_RxDone_NotHigh(rxdone, rxLow);
343    regs.RxData = vnic.RxData;
344    regs.RxDone = rxdone;
345    regs.RxWait = rxdone;
346
347    // update tx regsiters
348    uint64_t txdone = vnic.TxDone;
349    txdone = set_TxDone_Packets(txdone, txFifo.packets());
350    txdone = set_TxDone_Full(txdone, txFifo.avail() < regs.TxMaxCopy);
351    txdone = set_TxDone_Low(txdone, txFifo.size() < regs.TxFifoLow);
352    regs.TxData = vnic.TxData;
353    regs.TxDone = txdone;
354    regs.TxWait = txdone;
355
356    int head = 0xffff;
357
358    if (!rxFifo.empty()) {
359        int vnic = rxFifo.begin()->priv;
360        if (vnic != -1 && virtualRegs[vnic].rxPacketOffset > 0)
361            head = vnic;
362    }
363
364    regs.RxStatus = set_RxStatus_Head(regs.RxStatus, head);
365    regs.RxStatus = set_RxStatus_Busy(regs.RxStatus, rxBusyCount);
366    regs.RxStatus = set_RxStatus_Mapped(regs.RxStatus, rxMappedCount);
367    regs.RxStatus = set_RxStatus_Dirty(regs.RxStatus, rxDirtyCount);
368}
369
370void
371Device::prepareWrite(int cpu, int index)
372{
373    prepareIO(cpu, index);
374}
375
376/**
377 * I/O read of device register
378 */
379Tick
380Device::read(PacketPtr pkt)
381{
382    assert(config.command & PCI_CMD_MSE);
383    assert(pkt->getAddr() >= BARAddrs[0] && pkt->getSize() < BARSize[0]);
384
385    int cpu = pkt->req->contextId();
386    Addr daddr = pkt->getAddr() - BARAddrs[0];
387    Addr index = daddr >> Regs::VirtualShift;
388    Addr raddr = daddr & Regs::VirtualMask;
389
390    pkt->allocate();
391
392    if (!regValid(raddr))
393        panic("invalid register: cpu=%d vnic=%d da=%#x pa=%#x size=%d",
394              cpu, index, daddr, pkt->getAddr(), pkt->getSize());
395
396    const Regs::Info &info = regInfo(raddr);
397    if (!info.read)
398        panic("read %s (write only): "
399              "cpu=%d vnic=%d da=%#x pa=%#x size=%d",
400              info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize());
401
402        panic("read %s (invalid size): "
403              "cpu=%d vnic=%d da=%#x pa=%#x size=%d",
404              info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize());
405
406    prepareRead(cpu, index);
407
408    uint64_t value M5_VAR_USED = 0;
409    if (pkt->getSize() == 4) {
410        uint32_t reg = regData32(raddr);
411        pkt->set(reg);
412        value = reg;
413    }
414
415    if (pkt->getSize() == 8) {
416        uint64_t reg = regData64(raddr);
417        pkt->set(reg);
418        value = reg;
419    }
420
421    DPRINTF(EthernetPIO,
422            "read %s: cpu=%d vnic=%d da=%#x pa=%#x size=%d val=%#x\n",
423            info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize(), value);
424
425    // reading the interrupt status register has the side effect of
426    // clearing it
427    if (raddr == Regs::IntrStatus)
428        devIntrClear();
429
430    return pioDelay;
431}
432
433/**
434 * IPR read of device register
435
436    Fault
437Device::iprRead(Addr daddr, int cpu, uint64_t &result)
438{
439    if (!regValid(daddr))
440        panic("invalid address: da=%#x", daddr);
441
442    const Regs::Info &info = regInfo(daddr);
443    if (!info.read)
444        panic("reading %s (write only): cpu=%d da=%#x", info.name, cpu, daddr);
445
446    DPRINTF(EthernetPIO, "IPR read %s: cpu=%d da=%#x\n",
447            info.name, cpu, daddr);
448
449    prepareRead(cpu, 0);
450
451    if (info.size == 4)
452        result = regData32(daddr);
453
454    if (info.size == 8)
455        result = regData64(daddr);
456
457    DPRINTF(EthernetPIO, "IPR read %s: cpu=%s da=%#x val=%#x\n",
458            info.name, cpu, result);
459
460    return NoFault;
461}
462*/
463/**
464 * I/O write of device register
465 */
466Tick
467Device::write(PacketPtr pkt)
468{
469    assert(config.command & PCI_CMD_MSE);
470    assert(pkt->getAddr() >= BARAddrs[0] && pkt->getSize() < BARSize[0]);
471
472    int cpu = pkt->req->contextId();
473    Addr daddr = pkt->getAddr() - BARAddrs[0];
474    Addr index = daddr >> Regs::VirtualShift;
475    Addr raddr = daddr & Regs::VirtualMask;
476
477    if (!regValid(raddr))
478        panic("invalid register: cpu=%d, da=%#x pa=%#x size=%d",
479                cpu, daddr, pkt->getAddr(), pkt->getSize());
480
481    const Regs::Info &info = regInfo(raddr);
482    if (!info.write)
483        panic("write %s (read only): "
484              "cpu=%d vnic=%d da=%#x pa=%#x size=%d",
485              info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize());
486
487    if (pkt->getSize() != info.size)
488        panic("write %s (invalid size): "
489              "cpu=%d vnic=%d da=%#x pa=%#x size=%d",
490              info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize());
491
492    VirtualReg &vnic = virtualRegs[index];
493
494    DPRINTF(EthernetPIO,
495            "write %s vnic %d: cpu=%d val=%#x da=%#x pa=%#x size=%d\n",
496            info.name, index, cpu, info.size == 4 ? pkt->get<uint32_t>() :
497            pkt->get<uint64_t>(), daddr, pkt->getAddr(), pkt->getSize());
498
499    prepareWrite(cpu, index);
500
501    switch (raddr) {
502      case Regs::Config:
503        changeConfig(pkt->get<uint32_t>());
504        break;
505
506      case Regs::Command:
507        command(pkt->get<uint32_t>());
508        break;
509
510      case Regs::IntrStatus:
511        devIntrClear(regs.IntrStatus & pkt->get<uint32_t>());
512        break;
513
514      case Regs::IntrMask:
515        devIntrChangeMask(pkt->get<uint32_t>());
516        break;
517
518      case Regs::RxData:
519        if (Regs::get_RxDone_Busy(vnic.RxDone))
520            panic("receive machine busy with another request! rxState=%s",
521                  RxStateStrings[rxState]);
522
523        vnic.rxUnique = rxUnique++;
524        vnic.RxDone = Regs::RxDone_Busy;
525        vnic.RxData = pkt->get<uint64_t>();
526        rxBusyCount++;
527
528        if (Regs::get_RxData_Vaddr(pkt->get<uint64_t>())) {
529            panic("vtophys not implemented in newmem");
530#ifdef SINIC_VTOPHYS
531            Addr vaddr = Regs::get_RxData_Addr(reg64);
532            Addr paddr = vtophys(req->xc, vaddr);
533            DPRINTF(EthernetPIO, "write RxData vnic %d (rxunique %d): "
534                    "vaddr=%#x, paddr=%#x\n",
535                    index, vnic.rxUnique, vaddr, paddr);
536
537            vnic.RxData = Regs::set_RxData_Addr(vnic.RxData, paddr);
538#endif
539        } else {
540            DPRINTF(EthernetPIO, "write RxData vnic %d (rxunique %d)\n",
541                    index, vnic.rxUnique);
542        }
543
544        if (vnic.rxIndex == rxFifo.end()) {
545            DPRINTF(EthernetPIO, "request new packet...appending to rxList\n");
546            rxList.push_back(index);
547        } else {
548            DPRINTF(EthernetPIO, "packet exists...appending to rxBusy\n");
549            rxBusy.push_back(index);
550        }
551
552        if (rxEnable && (rxState == rxIdle || rxState == rxFifoBlock)) {
553            rxState = rxFifoBlock;
554            rxKick();
555        }
556        break;
557
558      case Regs::TxData:
559        if (Regs::get_TxDone_Busy(vnic.TxDone))
560            panic("transmit machine busy with another request! txState=%s",
561                  TxStateStrings[txState]);
562
563        vnic.txUnique = txUnique++;
564        vnic.TxDone = Regs::TxDone_Busy;
565
566        if (Regs::get_TxData_Vaddr(pkt->get<uint64_t>())) {
567            panic("vtophys won't work here in newmem.\n");
568#ifdef SINIC_VTOPHYS
569            Addr vaddr = Regs::get_TxData_Addr(reg64);
570            Addr paddr = vtophys(req->xc, vaddr);
571            DPRINTF(EthernetPIO, "write TxData vnic %d (txunique %d): "
572                    "vaddr=%#x, paddr=%#x\n",
573                    index, vnic.txUnique, vaddr, paddr);
574
575            vnic.TxData = Regs::set_TxData_Addr(vnic.TxData, paddr);
576#endif
577        } else {
578            DPRINTF(EthernetPIO, "write TxData vnic %d (txunique %d)\n",
579                    index, vnic.txUnique);
580        }
581
582        if (txList.empty() || txList.front() != index)
583            txList.push_back(index);
584        if (txEnable && txState == txIdle && txList.front() == index) {
585            txState = txFifoBlock;
586            txKick();
587        }
588        break;
589    }
590
591    return pioDelay;
592}
593
594void
595Device::devIntrPost(uint32_t interrupts)
596{
597    if ((interrupts & Regs::Intr_Res))
598        panic("Cannot set a reserved interrupt");
599
600    regs.IntrStatus |= interrupts;
601
602    DPRINTF(EthernetIntr,
603            "interrupt written to intStatus: intr=%#x status=%#x mask=%#x\n",
604            interrupts, regs.IntrStatus, regs.IntrMask);
605
606    interrupts = regs.IntrStatus & regs.IntrMask;
607
608    // Intr_RxHigh is special, we only signal it if we've emptied the fifo
609    // and then filled it above the high watermark
610    if (rxEmpty)
611        rxEmpty = false;
612    else
613        interrupts &= ~Regs::Intr_RxHigh;
614
615    // Intr_TxLow is special, we only signal it if we've filled up the fifo
616    // and then dropped below the low watermark
617    if (txFull)
618        txFull = false;
619    else
620        interrupts &= ~Regs::Intr_TxLow;
621
622    if (interrupts) {
623        Tick when = curTick();
624        if ((interrupts & Regs::Intr_NoDelay) == 0)
625            when += intrDelay;
626        cpuIntrPost(when);
627    }
628}
629
630void
631Device::devIntrClear(uint32_t interrupts)
632{
633    if ((interrupts & Regs::Intr_Res))
634        panic("Cannot clear a reserved interrupt");
635
636    regs.IntrStatus &= ~interrupts;
637
638    DPRINTF(EthernetIntr,
639            "interrupt cleared from intStatus: intr=%x status=%x mask=%x\n",
640            interrupts, regs.IntrStatus, regs.IntrMask);
641
642    if (!(regs.IntrStatus & regs.IntrMask))
643        cpuIntrClear();
644}
645
646void
647Device::devIntrChangeMask(uint32_t newmask)
648{
649    if (regs.IntrMask == newmask)
650        return;
651
652    regs.IntrMask = newmask;
653
654    DPRINTF(EthernetIntr,
655            "interrupt mask changed: intStatus=%x intMask=%x masked=%x\n",
656            regs.IntrStatus, regs.IntrMask, regs.IntrStatus & regs.IntrMask);
657
658    if (regs.IntrStatus & regs.IntrMask)
659        cpuIntrPost(curTick());
660    else
661        cpuIntrClear();
662}
663
664void
665Base::cpuIntrPost(Tick when)
666{
667    // If the interrupt you want to post is later than an interrupt
668    // already scheduled, just let it post in the coming one and don't
669    // schedule another.
670    // HOWEVER, must be sure that the scheduled intrTick is in the
671    // future (this was formerly the source of a bug)
672    /**
673     * @todo this warning should be removed and the intrTick code should
674     * be fixed.
675     */
676    assert(when >= curTick());
677    assert(intrTick >= curTick() || intrTick == 0);
678    if (!cpuIntrEnable) {
679        DPRINTF(EthernetIntr, "interrupts not enabled.\n",
680                intrTick);
681        return;
682    }
683
684    if (when > intrTick && intrTick != 0) {
685        DPRINTF(EthernetIntr, "don't need to schedule event...intrTick=%d\n",
686                intrTick);
687        return;
688    }
689
690    intrTick = when;
691    if (intrTick < curTick()) {
692        Debug::breakpoint();
693        intrTick = curTick();
694    }
695
696    DPRINTF(EthernetIntr, "going to schedule an interrupt for intrTick=%d\n",
697            intrTick);
698
699    if (intrEvent)
700        intrEvent->squash();
701    intrEvent = new IntrEvent(this, true);
702    schedule(intrEvent, intrTick);
703}
704
705void
706Base::cpuInterrupt()
707{
708    assert(intrTick == curTick());
709
710    // Whether or not there's a pending interrupt, we don't care about
711    // it anymore
712    intrEvent = 0;
713    intrTick = 0;
714
715    // Don't send an interrupt if there's already one
716    if (cpuPendingIntr) {
717        DPRINTF(EthernetIntr,
718                "would send an interrupt now, but there's already pending\n");
719    } else {
720        // Send interrupt
721        cpuPendingIntr = true;
722
723        DPRINTF(EthernetIntr, "posting interrupt\n");
724        intrPost();
725    }
726}
727
728void
729Base::cpuIntrClear()
730{
731    if (!cpuPendingIntr)
732        return;
733
734    if (intrEvent) {
735        intrEvent->squash();
736        intrEvent = 0;
737    }
738
739    intrTick = 0;
740
741    cpuPendingIntr = false;
742
743    DPRINTF(EthernetIntr, "clearing cchip interrupt\n");
744    intrClear();
745}
746
747bool
748Base::cpuIntrPending() const
749{ return cpuPendingIntr; }
750
751void
752Device::changeConfig(uint32_t newconf)
753{
754    uint32_t changed = regs.Config ^ newconf;
755    if (!changed)
756        return;
757
758    regs.Config = newconf;
759
760    if ((changed & Regs::Config_IntEn)) {
761        cpuIntrEnable = regs.Config & Regs::Config_IntEn;
762        if (cpuIntrEnable) {
763            if (regs.IntrStatus & regs.IntrMask)
764                cpuIntrPost(curTick());
765        } else {
766            cpuIntrClear();
767        }
768    }
769
770    if ((changed & Regs::Config_TxEn)) {
771        txEnable = regs.Config & Regs::Config_TxEn;
772        if (txEnable)
773            txKick();
774    }
775
776    if ((changed & Regs::Config_RxEn)) {
777        rxEnable = regs.Config & Regs::Config_RxEn;
778        if (rxEnable)
779            rxKick();
780    }
781}
782
783void
784Device::command(uint32_t command)
785{
786    if (command & Regs::Command_Intr)
787        devIntrPost(Regs::Intr_Soft);
788
789    if (command & Regs::Command_Reset)
790        reset();
791}
792
793void
794Device::reset()
795{
796    using namespace Regs;
797
798    memset(&regs, 0, sizeof(regs));
799
800    regs.Config = 0;
801    if (params()->rx_thread)
802        regs.Config |= Config_RxThread;
803    if (params()->tx_thread)
804        regs.Config |= Config_TxThread;
805    if (params()->rss)
806        regs.Config |= Config_RSS;
807    if (params()->zero_copy)
808        regs.Config |= Config_ZeroCopy;
809    if (params()->delay_copy)
810        regs.Config |= Config_DelayCopy;
811    if (params()->virtual_addr)
812        regs.Config |= Config_Vaddr;
813
814    if (params()->delay_copy && params()->zero_copy)
815        panic("Can't delay copy and zero copy");
816
817    regs.IntrMask = Intr_Soft | Intr_RxHigh | Intr_RxPacket | Intr_TxLow;
818    regs.RxMaxCopy = params()->rx_max_copy;
819    regs.TxMaxCopy = params()->tx_max_copy;
820    regs.ZeroCopySize = params()->zero_copy_size;
821    regs.ZeroCopyMark = params()->zero_copy_threshold;
822    regs.VirtualCount = params()->virtual_count;
823    regs.RxMaxIntr = params()->rx_max_intr;
824    regs.RxFifoSize = params()->rx_fifo_size;
825    regs.TxFifoSize = params()->tx_fifo_size;
826    regs.RxFifoLow = params()->rx_fifo_low_mark;
827    regs.TxFifoLow = params()->tx_fifo_threshold;
828    regs.RxFifoHigh = params()->rx_fifo_threshold;
829    regs.TxFifoHigh = params()->tx_fifo_high_mark;
830    regs.HwAddr = params()->hardware_address;
831
832    if (regs.RxMaxCopy < regs.ZeroCopyMark)
833        panic("Must be able to copy at least as many bytes as the threshold");
834
835    if (regs.ZeroCopySize >= regs.ZeroCopyMark)
836        panic("The number of bytes to copy must be less than the threshold");
837
838    rxList.clear();
839    rxBusy.clear();
840    rxActive = -1;
841    txList.clear();
842    rxBusyCount = 0;
843    rxDirtyCount = 0;
844    rxMappedCount = 0;
845
846    rxState = rxIdle;
847    txState = txIdle;
848
849    rxFifo.clear();
850    rxFifoPtr = rxFifo.end();
851    txFifo.clear();
852    rxEmpty = false;
853    rxLow = true;
854    txFull = false;
855
856    int size = virtualRegs.size();
857    virtualRegs.clear();
858    virtualRegs.resize(size);
859    for (int i = 0; i < size; ++i)
860        virtualRegs[i].rxIndex = rxFifo.end();
861}
862
863void
864Device::rxDmaDone()
865{
866    assert(rxState == rxCopy);
867    rxState = rxCopyDone;
868    DPRINTF(EthernetDMA, "end rx dma write paddr=%#x len=%d\n",
869            rxDmaAddr, rxDmaLen);
870    DDUMP(EthernetData, rxDmaData, rxDmaLen);
871
872    // If the transmit state machine  has a pending DMA, let it go first
873    if (txState == txBeginCopy)
874        txKick();
875
876    rxKick();
877}
878
879void
880Device::rxKick()
881{
882    VirtualReg *vnic = NULL;
883
884    DPRINTF(EthernetSM, "rxKick: rxState=%s (rxFifo.size=%d)\n",
885            RxStateStrings[rxState], rxFifo.size());
886
887    if (rxKickTick > curTick()) {
888        DPRINTF(EthernetSM, "rxKick: exiting, can't run till %d\n",
889                rxKickTick);
890        return;
891    }
892
893  next:
894    rxFifo.check();
895    if (rxState == rxIdle)
896        goto exit;
897
898    if (rxActive == -1) {
899        if (rxState != rxFifoBlock)
900            panic("no active vnic while in state %s", RxStateStrings[rxState]);
901
902        DPRINTF(EthernetSM, "processing rxState=%s\n",
903                RxStateStrings[rxState]);
904    } else {
905        vnic = &virtualRegs[rxActive];
906        DPRINTF(EthernetSM,
907                "processing rxState=%s for vnic %d (rxunique %d)\n",
908                RxStateStrings[rxState], rxActive, vnic->rxUnique);
909    }
910
911    switch (rxState) {
912      case rxFifoBlock:
913        if (DTRACE(EthernetSM)) {
914            PacketFifo::iterator end = rxFifo.end();
915            int size = virtualRegs.size();
916            for (int i = 0; i < size; ++i) {
917                VirtualReg *vn = &virtualRegs[i];
918                bool busy = Regs::get_RxDone_Busy(vn->RxDone);
919                if (vn->rxIndex != end) {
920#ifndef NDEBUG
921                    bool dirty = vn->rxPacketOffset > 0;
922                    const char *status;
923
924                    if (busy && dirty)
925                        status = "busy,dirty";
926                    else if (busy)
927                        status = "busy";
928                    else if (dirty)
929                        status = "dirty";
930                    else
931                        status = "mapped";
932
933                    DPRINTF(EthernetSM,
934                            "vnic %d %s (rxunique %d), packet %d, slack %d\n",
935                            i, status, vn->rxUnique,
936                            rxFifo.countPacketsBefore(vn->rxIndex),
937                            vn->rxIndex->slack);
938#endif
939                } else if (busy) {
940                    DPRINTF(EthernetSM, "vnic %d unmapped (rxunique %d)\n",
941                            i, vn->rxUnique);
942                }
943            }
944        }
945
946        if (!rxBusy.empty()) {
947            rxActive = rxBusy.front();
948            rxBusy.pop_front();
949            vnic = &virtualRegs[rxActive];
950
951            if (vnic->rxIndex == rxFifo.end())
952                panic("continuing vnic without packet\n");
953
954            DPRINTF(EthernetSM,
955                    "continue processing for vnic %d (rxunique %d)\n",
956                    rxActive, vnic->rxUnique);
957
958            rxState = rxBeginCopy;
959
960            int vnic_distance = rxFifo.countPacketsBefore(vnic->rxIndex);
961            totalVnicDistance += vnic_distance;
962            numVnicDistance += 1;
963            if (vnic_distance > _maxVnicDistance) {
964                maxVnicDistance = vnic_distance;
965                _maxVnicDistance = vnic_distance;
966            }
967
968            break;
969        }
970
971        if (rxFifoPtr == rxFifo.end()) {
972            DPRINTF(EthernetSM, "receive waiting for data.  Nothing to do.\n");
973            goto exit;
974        }
975
976        if (rxList.empty())
977            panic("Not idle, but nothing to do!");
978
979        assert(!rxFifo.empty());
980
981        rxActive = rxList.front();
982        rxList.pop_front();
983        vnic = &virtualRegs[rxActive];
984
985        DPRINTF(EthernetSM,
986                "processing new packet for vnic %d (rxunique %d)\n",
987                rxActive, vnic->rxUnique);
988
989        // Grab a new packet from the fifo.
990        vnic->rxIndex = rxFifoPtr++;
991        vnic->rxIndex->priv = rxActive;
992        vnic->rxPacketOffset = 0;
993        vnic->rxPacketBytes = vnic->rxIndex->packet->length;
994        assert(vnic->rxPacketBytes);
995        rxMappedCount++;
996
997        vnic->rxDoneData = 0;
998        /* scope for variables */ {
999            IpPtr ip(vnic->rxIndex->packet);
1000            if (ip) {
1001                DPRINTF(Ethernet, "ID is %d\n", ip->id());
1002                vnic->rxDoneData |= Regs::RxDone_IpPacket;
1003                rxIpChecksums++;
1004                if (cksum(ip) != 0) {
1005                    DPRINTF(EthernetCksum, "Rx IP Checksum Error\n");
1006                    vnic->rxDoneData |= Regs::RxDone_IpError;
1007                }
1008                TcpPtr tcp(ip);
1009                UdpPtr udp(ip);
1010                if (tcp) {
1011                    DPRINTF(Ethernet,
1012                            "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n",
1013                            tcp->sport(), tcp->dport(), tcp->seq(),
1014                            tcp->ack());
1015                    vnic->rxDoneData |= Regs::RxDone_TcpPacket;
1016                    rxTcpChecksums++;
1017                    if (cksum(tcp) != 0) {
1018                        DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n");
1019                        vnic->rxDoneData |= Regs::RxDone_TcpError;
1020                    }
1021                } else if (udp) {
1022                    vnic->rxDoneData |= Regs::RxDone_UdpPacket;
1023                    rxUdpChecksums++;
1024                    if (cksum(udp) != 0) {
1025                        DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n");
1026                        vnic->rxDoneData |= Regs::RxDone_UdpError;
1027                    }
1028                }
1029            }
1030        }
1031        rxState = rxBeginCopy;
1032        break;
1033
1034      case rxBeginCopy:
1035        if (dmaPending() || getState() != Running)
1036            goto exit;
1037
1038        rxDmaAddr = params()->platform->pciToDma(
1039                Regs::get_RxData_Addr(vnic->RxData));
1040        rxDmaLen = min<unsigned>(Regs::get_RxData_Len(vnic->RxData),
1041                                 vnic->rxPacketBytes);
1042
1043        /*
1044         * if we're doing zero/delay copy and we're below the fifo
1045         * threshold, see if we should try to do the zero/defer copy
1046         */
1047        if ((Regs::get_Config_ZeroCopy(regs.Config) ||
1048             Regs::get_Config_DelayCopy(regs.Config)) &&
1049            !Regs::get_RxData_NoDelay(vnic->RxData) && rxLow) {
1050            if (rxDmaLen > regs.ZeroCopyMark)
1051                rxDmaLen = regs.ZeroCopySize;
1052        }
1053        rxDmaData = vnic->rxIndex->packet->data + vnic->rxPacketOffset;
1054        rxState = rxCopy;
1055        if (rxDmaAddr == 1LL) {
1056            rxState = rxCopyDone;
1057            break;
1058        }
1059
1060        dmaWrite(rxDmaAddr, rxDmaLen, &rxDmaEvent, rxDmaData);
1061        break;
1062
1063      case rxCopy:
1064        DPRINTF(EthernetSM, "receive machine still copying\n");
1065        goto exit;
1066
1067      case rxCopyDone:
1068        vnic->RxDone = vnic->rxDoneData;
1069        vnic->RxDone |= Regs::RxDone_Complete;
1070        rxBusyCount--;
1071
1072        if (vnic->rxPacketBytes == rxDmaLen) {
1073            if (vnic->rxPacketOffset)
1074                rxDirtyCount--;
1075
1076            // Packet is complete.  Indicate how many bytes were copied
1077            vnic->RxDone = Regs::set_RxDone_CopyLen(vnic->RxDone, rxDmaLen);
1078
1079            DPRINTF(EthernetSM,
1080                    "rxKick: packet complete on vnic %d (rxunique %d)\n",
1081                    rxActive, vnic->rxUnique);
1082            rxFifo.remove(vnic->rxIndex);
1083            vnic->rxIndex = rxFifo.end();
1084            rxMappedCount--;
1085        } else {
1086            if (!vnic->rxPacketOffset)
1087                rxDirtyCount++;
1088
1089            vnic->rxPacketBytes -= rxDmaLen;
1090            vnic->rxPacketOffset += rxDmaLen;
1091            vnic->RxDone |= Regs::RxDone_More;
1092            vnic->RxDone = Regs::set_RxDone_CopyLen(vnic->RxDone,
1093                                                    vnic->rxPacketBytes);
1094            DPRINTF(EthernetSM,
1095                    "rxKick: packet not complete on vnic %d (rxunique %d): "
1096                    "%d bytes left\n",
1097                    rxActive, vnic->rxUnique, vnic->rxPacketBytes);
1098        }
1099
1100        rxActive = -1;
1101        rxState = rxBusy.empty() && rxList.empty() ? rxIdle : rxFifoBlock;
1102
1103        if (rxFifo.empty()) {
1104            devIntrPost(Regs::Intr_RxEmpty);
1105            rxEmpty = true;
1106        }
1107
1108        if (rxFifo.size() < regs.RxFifoLow)
1109            rxLow = true;
1110
1111        if (rxFifo.size() > regs.RxFifoHigh)
1112            rxLow = false;
1113
1114        devIntrPost(Regs::Intr_RxDMA);
1115        break;
1116
1117      default:
1118        panic("Invalid rxState!");
1119    }
1120
1121    DPRINTF(EthernetSM, "entering next rxState=%s\n",
1122            RxStateStrings[rxState]);
1123
1124    goto next;
1125
1126  exit:
1127    /**
1128     * @todo do we want to schedule a future kick?
1129     */
1130    DPRINTF(EthernetSM, "rx state machine exited rxState=%s\n",
1131            RxStateStrings[rxState]);
1132}
1133
1134void
1135Device::txDmaDone()
1136{
1137    assert(txState == txCopy);
1138    txState = txCopyDone;
1139    DPRINTF(EthernetDMA, "tx dma read paddr=%#x len=%d\n",
1140            txDmaAddr, txDmaLen);
1141    DDUMP(EthernetData, txDmaData, txDmaLen);
1142
1143    // If the receive state machine  has a pending DMA, let it go first
1144    if (rxState == rxBeginCopy)
1145        rxKick();
1146
1147    txKick();
1148}
1149
1150void
1151Device::transmit()
1152{
1153    if (txFifo.empty()) {
1154        DPRINTF(Ethernet, "nothing to transmit\n");
1155        return;
1156    }
1157
1158    uint32_t interrupts;
1159    EthPacketPtr packet = txFifo.front();
1160    if (!interface->sendPacket(packet)) {
1161        DPRINTF(Ethernet, "Packet Transmit: failed txFifo available %d\n",
1162                txFifo.avail());
1163        return;
1164    }
1165
1166    txFifo.pop();
1167#if TRACING_ON
1168    if (DTRACE(Ethernet)) {
1169        IpPtr ip(packet);
1170        if (ip) {
1171            DPRINTF(Ethernet, "ID is %d\n", ip->id());
1172            TcpPtr tcp(ip);
1173            if (tcp) {
1174                DPRINTF(Ethernet,
1175                        "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n",
1176                        tcp->sport(), tcp->dport(), tcp->seq(),
1177                        tcp->ack());
1178            }
1179        }
1180    }
1181#endif
1182
1183    DDUMP(EthernetData, packet->data, packet->length);
1184    txBytes += packet->length;
1185    txPackets++;
1186
1187    DPRINTF(Ethernet, "Packet Transmit: successful txFifo Available %d\n",
1188            txFifo.avail());
1189
1190    interrupts = Regs::Intr_TxPacket;
1191    if (txFifo.size() < regs.TxFifoLow)
1192        interrupts |= Regs::Intr_TxLow;
1193    devIntrPost(interrupts);
1194}
1195
1196void
1197Device::txKick()
1198{
1199    VirtualReg *vnic;
1200    DPRINTF(EthernetSM, "txKick: txState=%s (txFifo.size=%d)\n",
1201            TxStateStrings[txState], txFifo.size());
1202
1203    if (txKickTick > curTick()) {
1204        DPRINTF(EthernetSM, "txKick: exiting, can't run till %d\n",
1205                txKickTick);
1206        return;
1207    }
1208
1209  next:
1210    if (txState == txIdle)
1211        goto exit;
1212
1213    assert(!txList.empty());
1214    vnic = &virtualRegs[txList.front()];
1215
1216    switch (txState) {
1217      case txFifoBlock:
1218        assert(Regs::get_TxDone_Busy(vnic->TxDone));
1219        if (!txPacket) {
1220            // Grab a new packet from the fifo.
1221            txPacket = new EthPacketData(16384);
1222            txPacketOffset = 0;
1223        }
1224
1225        if (txFifo.avail() - txPacket->length <
1226            Regs::get_TxData_Len(vnic->TxData)) {
1227            DPRINTF(EthernetSM, "transmit fifo full.  Nothing to do.\n");
1228            goto exit;
1229        }
1230
1231        txState = txBeginCopy;
1232        break;
1233
1234      case txBeginCopy:
1235        if (dmaPending() || getState() != Running)
1236            goto exit;
1237
1238        txDmaAddr = params()->platform->pciToDma(
1239                Regs::get_TxData_Addr(vnic->TxData));
1240        txDmaLen = Regs::get_TxData_Len(vnic->TxData);
1241        txDmaData = txPacket->data + txPacketOffset;
1242        txState = txCopy;
1243
1244        dmaRead(txDmaAddr, txDmaLen, &txDmaEvent, txDmaData);
1245        break;
1246
1247      case txCopy:
1248        DPRINTF(EthernetSM, "transmit machine still copying\n");
1249        goto exit;
1250
1251      case txCopyDone:
1252        vnic->TxDone = txDmaLen | Regs::TxDone_Complete;
1253        txPacket->length += txDmaLen;
1254        if ((vnic->TxData & Regs::TxData_More)) {
1255            txPacketOffset += txDmaLen;
1256            txState = txIdle;
1257            devIntrPost(Regs::Intr_TxDMA);
1258            break;
1259        }
1260
1261        assert(txPacket->length <= txFifo.avail());
1262        if ((vnic->TxData & Regs::TxData_Checksum)) {
1263            IpPtr ip(txPacket);
1264            if (ip) {
1265                TcpPtr tcp(ip);
1266                if (tcp) {
1267                    tcp->sum(0);
1268                    tcp->sum(cksum(tcp));
1269                    txTcpChecksums++;
1270                }
1271
1272                UdpPtr udp(ip);
1273                if (udp) {
1274                    udp->sum(0);
1275                    udp->sum(cksum(udp));
1276                    txUdpChecksums++;
1277                }
1278
1279                ip->sum(0);
1280                ip->sum(cksum(ip));
1281                txIpChecksums++;
1282            }
1283        }
1284
1285        txFifo.push(txPacket);
1286        if (txFifo.avail() < regs.TxMaxCopy) {
1287            devIntrPost(Regs::Intr_TxFull);
1288            txFull = true;
1289        }
1290        txPacket = 0;
1291        transmit();
1292        txList.pop_front();
1293        txState = txList.empty() ? txIdle : txFifoBlock;
1294        devIntrPost(Regs::Intr_TxDMA);
1295        break;
1296
1297      default:
1298        panic("Invalid txState!");
1299    }
1300
1301    DPRINTF(EthernetSM, "entering next txState=%s\n",
1302            TxStateStrings[txState]);
1303
1304    goto next;
1305
1306  exit:
1307    /**
1308     * @todo do we want to schedule a future kick?
1309     */
1310    DPRINTF(EthernetSM, "tx state machine exited txState=%s\n",
1311            TxStateStrings[txState]);
1312}
1313
1314void
1315Device::transferDone()
1316{
1317    if (txFifo.empty()) {
1318        DPRINTF(Ethernet, "transfer complete: txFifo empty...nothing to do\n");
1319        return;
1320    }
1321
1322    DPRINTF(Ethernet, "transfer complete: data in txFifo...schedule xmit\n");
1323
1324    reschedule(txEvent, curTick() + ticks(1), true);
1325}
1326
1327bool
1328Device::rxFilter(const EthPacketPtr &packet)
1329{
1330    if (!Regs::get_Config_Filter(regs.Config))
1331        return false;
1332
1333    panic("receive filter not implemented\n");
1334    bool drop = true;
1335
1336#if 0
1337    string type;
1338
1339    EthHdr *eth = packet->eth();
1340    if (eth->unicast()) {
1341        // If we're accepting all unicast addresses
1342        if (acceptUnicast)
1343            drop = false;
1344
1345        // If we make a perfect match
1346        if (acceptPerfect && params->eaddr == eth.dst())
1347            drop = false;
1348
1349        if (acceptArp && eth->type() == ETH_TYPE_ARP)
1350            drop = false;
1351
1352    } else if (eth->broadcast()) {
1353        // if we're accepting broadcasts
1354        if (acceptBroadcast)
1355            drop = false;
1356
1357    } else if (eth->multicast()) {
1358        // if we're accepting all multicasts
1359        if (acceptMulticast)
1360            drop = false;
1361
1362    }
1363
1364    if (drop) {
1365        DPRINTF(Ethernet, "rxFilter drop\n");
1366        DDUMP(EthernetData, packet->data, packet->length);
1367    }
1368#endif
1369    return drop;
1370}
1371
1372bool
1373Device::recvPacket(EthPacketPtr packet)
1374{
1375    rxBytes += packet->length;
1376    rxPackets++;
1377
1378    DPRINTF(Ethernet, "Receiving packet from wire, rxFifo Available is %d\n",
1379            rxFifo.avail());
1380
1381    if (!rxEnable) {
1382        DPRINTF(Ethernet, "receive disabled...packet dropped\n");
1383        return true;
1384    }
1385
1386    if (rxFilter(packet)) {
1387        DPRINTF(Ethernet, "packet filtered...dropped\n");
1388        return true;
1389    }
1390
1391    if (rxFifo.size() >= regs.RxFifoHigh)
1392        devIntrPost(Regs::Intr_RxHigh);
1393
1394    if (!rxFifo.push(packet)) {
1395        DPRINTF(Ethernet,
1396                "packet will not fit in receive buffer...packet dropped\n");
1397        return false;
1398    }
1399
1400    // If we were at the last element, back up one ot go to the new
1401    // last element of the list.
1402    if (rxFifoPtr == rxFifo.end())
1403        --rxFifoPtr;
1404
1405    devIntrPost(Regs::Intr_RxPacket);
1406    rxKick();
1407    return true;
1408}
1409
1410void
1411Device::resume()
1412{
1413    SimObject::resume();
1414
1415    // During drain we could have left the state machines in a waiting state and
1416    // they wouldn't get out until some other event occured to kick them.
1417    // This way they'll get out immediately
1418    txKick();
1419    rxKick();
1420}
1421
1422//=====================================================================
1423//
1424//
1425void
1426Base::serialize(std::ostream &os)
1427{
1428    // Serialize the PciDev base class
1429    PciDev::serialize(os);
1430
1431    SERIALIZE_SCALAR(rxEnable);
1432    SERIALIZE_SCALAR(txEnable);
1433    SERIALIZE_SCALAR(cpuIntrEnable);
1434
1435    /*
1436     * Keep track of pending interrupt status.
1437     */
1438    SERIALIZE_SCALAR(intrTick);
1439    SERIALIZE_SCALAR(cpuPendingIntr);
1440    Tick intrEventTick = 0;
1441    if (intrEvent)
1442        intrEventTick = intrEvent->when();
1443    SERIALIZE_SCALAR(intrEventTick);
1444}
1445
1446void
1447Base::unserialize(Checkpoint *cp, const std::string &section)
1448{
1449    // Unserialize the PciDev base class
1450    PciDev::unserialize(cp, section);
1451
1452    UNSERIALIZE_SCALAR(rxEnable);
1453    UNSERIALIZE_SCALAR(txEnable);
1454    UNSERIALIZE_SCALAR(cpuIntrEnable);
1455
1456    /*
1457     * Keep track of pending interrupt status.
1458     */
1459    UNSERIALIZE_SCALAR(intrTick);
1460    UNSERIALIZE_SCALAR(cpuPendingIntr);
1461    Tick intrEventTick;
1462    UNSERIALIZE_SCALAR(intrEventTick);
1463    if (intrEventTick) {
1464        intrEvent = new IntrEvent(this, true);
1465        schedule(intrEvent, intrEventTick);
1466    }
1467}
1468
1469void
1470Device::serialize(std::ostream &os)
1471{
1472    int count;
1473
1474    // Serialize the PciDev base class
1475    Base::serialize(os);
1476
1477    if (rxState == rxCopy)
1478        panic("can't serialize with an in flight dma request rxState=%s",
1479              RxStateStrings[rxState]);
1480
1481    if (txState == txCopy)
1482        panic("can't serialize with an in flight dma request txState=%s",
1483              TxStateStrings[txState]);
1484
1485    /*
1486     * Serialize the device registers that could be modified by the OS.
1487     */
1488    SERIALIZE_SCALAR(regs.Config);
1489    SERIALIZE_SCALAR(regs.IntrStatus);
1490    SERIALIZE_SCALAR(regs.IntrMask);
1491    SERIALIZE_SCALAR(regs.RxData);
1492    SERIALIZE_SCALAR(regs.TxData);
1493
1494    /*
1495     * Serialize the virtual nic state
1496     */
1497    int virtualRegsSize = virtualRegs.size();
1498    SERIALIZE_SCALAR(virtualRegsSize);
1499    for (int i = 0; i < virtualRegsSize; ++i) {
1500        VirtualReg *vnic = &virtualRegs[i];
1501
1502        std::string reg = csprintf("vnic%d", i);
1503        paramOut(os, reg + ".RxData", vnic->RxData);
1504        paramOut(os, reg + ".RxDone", vnic->RxDone);
1505        paramOut(os, reg + ".TxData", vnic->TxData);
1506        paramOut(os, reg + ".TxDone", vnic->TxDone);
1507
1508        bool rxPacketExists = vnic->rxIndex != rxFifo.end();
1509        paramOut(os, reg + ".rxPacketExists", rxPacketExists);
1510        if (rxPacketExists) {
1511            int rxPacket = 0;
1512            PacketFifo::iterator i = rxFifo.begin();
1513            while (i != vnic->rxIndex) {
1514                assert(i != rxFifo.end());
1515                ++i;
1516                ++rxPacket;
1517            }
1518
1519            paramOut(os, reg + ".rxPacket", rxPacket);
1520            paramOut(os, reg + ".rxPacketOffset", vnic->rxPacketOffset);
1521            paramOut(os, reg + ".rxPacketBytes", vnic->rxPacketBytes);
1522        }
1523        paramOut(os, reg + ".rxDoneData", vnic->rxDoneData);
1524    }
1525
1526    int rxFifoPtr = -1;
1527    if (this->rxFifoPtr != rxFifo.end())
1528        rxFifoPtr = rxFifo.countPacketsBefore(this->rxFifoPtr);
1529    SERIALIZE_SCALAR(rxFifoPtr);
1530
1531    SERIALIZE_SCALAR(rxActive);
1532    SERIALIZE_SCALAR(rxBusyCount);
1533    SERIALIZE_SCALAR(rxDirtyCount);
1534    SERIALIZE_SCALAR(rxMappedCount);
1535
1536    VirtualList::iterator i, end;
1537    for (count = 0, i = rxList.begin(), end = rxList.end(); i != end; ++i)
1538        paramOut(os, csprintf("rxList%d", count++), *i);
1539    int rxListSize = count;
1540    SERIALIZE_SCALAR(rxListSize);
1541
1542    for (count = 0, i = rxBusy.begin(), end = rxBusy.end(); i != end; ++i)
1543        paramOut(os, csprintf("rxBusy%d", count++), *i);
1544    int rxBusySize = count;
1545    SERIALIZE_SCALAR(rxBusySize);
1546
1547    for (count = 0, i = txList.begin(), end = txList.end(); i != end; ++i)
1548        paramOut(os, csprintf("txList%d", count++), *i);
1549    int txListSize = count;
1550    SERIALIZE_SCALAR(txListSize);
1551
1552    /*
1553     * Serialize rx state machine
1554     */
1555    int rxState = this->rxState;
1556    SERIALIZE_SCALAR(rxState);
1557    SERIALIZE_SCALAR(rxEmpty);
1558    SERIALIZE_SCALAR(rxLow);
1559    rxFifo.serialize("rxFifo", os);
1560
1561    /*
1562     * Serialize tx state machine
1563     */
1564    int txState = this->txState;
1565    SERIALIZE_SCALAR(txState);
1566    SERIALIZE_SCALAR(txFull);
1567    txFifo.serialize("txFifo", os);
1568    bool txPacketExists = txPacket;
1569    SERIALIZE_SCALAR(txPacketExists);
1570    if (txPacketExists) {
1571        txPacket->serialize("txPacket", os);
1572        SERIALIZE_SCALAR(txPacketOffset);
1573        SERIALIZE_SCALAR(txPacketBytes);
1574    }
1575
1576    /*
1577     * If there's a pending transmit, store the time so we can
1578     * reschedule it later
1579     */
1580    Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick() : 0;
1581    SERIALIZE_SCALAR(transmitTick);
1582}
1583
1584void
1585Device::unserialize(Checkpoint *cp, const std::string &section)
1586{
1587    // Unserialize the PciDev base class
1588    Base::unserialize(cp, section);
1589
1590    /*
1591     * Unserialize the device registers that may have been written by the OS.
1592     */
1593    UNSERIALIZE_SCALAR(regs.Config);
1594    UNSERIALIZE_SCALAR(regs.IntrStatus);
1595    UNSERIALIZE_SCALAR(regs.IntrMask);
1596    UNSERIALIZE_SCALAR(regs.RxData);
1597    UNSERIALIZE_SCALAR(regs.TxData);
1598
1599    UNSERIALIZE_SCALAR(rxActive);
1600    UNSERIALIZE_SCALAR(rxBusyCount);
1601    UNSERIALIZE_SCALAR(rxDirtyCount);
1602    UNSERIALIZE_SCALAR(rxMappedCount);
1603
1604    int rxListSize;
1605    UNSERIALIZE_SCALAR(rxListSize);
1606    rxList.clear();
1607    for (int i = 0; i < rxListSize; ++i) {
1608        int value;
1609        paramIn(cp, section, csprintf("rxList%d", i), value);
1610        rxList.push_back(value);
1611    }
1612
1613    int rxBusySize;
1614    UNSERIALIZE_SCALAR(rxBusySize);
1615    rxBusy.clear();
1616    for (int i = 0; i < rxBusySize; ++i) {
1617        int value;
1618        paramIn(cp, section, csprintf("rxBusy%d", i), value);
1619        rxBusy.push_back(value);
1620    }
1621
1622    int txListSize;
1623    UNSERIALIZE_SCALAR(txListSize);
1624    txList.clear();
1625    for (int i = 0; i < txListSize; ++i) {
1626        int value;
1627        paramIn(cp, section, csprintf("txList%d", i), value);
1628        txList.push_back(value);
1629    }
1630
1631    /*
1632     * Unserialize rx state machine
1633     */
1634    int rxState;
1635    UNSERIALIZE_SCALAR(rxState);
1636    UNSERIALIZE_SCALAR(rxEmpty);
1637    UNSERIALIZE_SCALAR(rxLow);
1638    this->rxState = (RxState) rxState;
1639    rxFifo.unserialize("rxFifo", cp, section);
1640
1641    int rxFifoPtr;
1642    UNSERIALIZE_SCALAR(rxFifoPtr);
1643    if (rxFifoPtr >= 0) {
1644        this->rxFifoPtr = rxFifo.begin();
1645        for (int i = 0; i < rxFifoPtr; ++i)
1646            ++this->rxFifoPtr;
1647    } else {
1648        this->rxFifoPtr = rxFifo.end();
1649    }
1650
1651    /*
1652     * Unserialize tx state machine
1653     */
1654    int txState;
1655    UNSERIALIZE_SCALAR(txState);
1656    UNSERIALIZE_SCALAR(txFull);
1657    this->txState = (TxState) txState;
1658    txFifo.unserialize("txFifo", cp, section);
1659    bool txPacketExists;
1660    UNSERIALIZE_SCALAR(txPacketExists);
1661    txPacket = 0;
1662    if (txPacketExists) {
1663        txPacket = new EthPacketData(16384);
1664        txPacket->unserialize("txPacket", cp, section);
1665        UNSERIALIZE_SCALAR(txPacketOffset);
1666        UNSERIALIZE_SCALAR(txPacketBytes);
1667    }
1668
1669    /*
1670     * unserialize the virtual nic registers/state
1671     *
1672     * this must be done after the unserialization of the rxFifo
1673     * because the packet iterators depend on the fifo being populated
1674     */
1675    int virtualRegsSize;
1676    UNSERIALIZE_SCALAR(virtualRegsSize);
1677    virtualRegs.clear();
1678    virtualRegs.resize(virtualRegsSize);
1679    for (int i = 0; i < virtualRegsSize; ++i) {
1680        VirtualReg *vnic = &virtualRegs[i];
1681        std::string reg = csprintf("vnic%d", i);
1682
1683        paramIn(cp, section, reg + ".RxData", vnic->RxData);
1684        paramIn(cp, section, reg + ".RxDone", vnic->RxDone);
1685        paramIn(cp, section, reg + ".TxData", vnic->TxData);
1686        paramIn(cp, section, reg + ".TxDone", vnic->TxDone);
1687
1688        vnic->rxUnique = rxUnique++;
1689        vnic->txUnique = txUnique++;
1690
1691        bool rxPacketExists;
1692        paramIn(cp, section, reg + ".rxPacketExists", rxPacketExists);
1693        if (rxPacketExists) {
1694            int rxPacket;
1695            paramIn(cp, section, reg + ".rxPacket", rxPacket);
1696            vnic->rxIndex = rxFifo.begin();
1697            while (rxPacket--)
1698                ++vnic->rxIndex;
1699
1700            paramIn(cp, section, reg + ".rxPacketOffset",
1701                    vnic->rxPacketOffset);
1702            paramIn(cp, section, reg + ".rxPacketBytes", vnic->rxPacketBytes);
1703        } else {
1704            vnic->rxIndex = rxFifo.end();
1705        }
1706        paramIn(cp, section, reg + ".rxDoneData", vnic->rxDoneData);
1707    }
1708
1709    /*
1710     * If there's a pending transmit, reschedule it now
1711     */
1712    Tick transmitTick;
1713    UNSERIALIZE_SCALAR(transmitTick);
1714    if (transmitTick)
1715        schedule(txEvent, curTick() + transmitTick);
1716
1717    pioPort.sendRangeChange();
1718
1719}
1720
1721} // namespace Sinic
1722
1723Sinic::Device *
1724SinicParams::create()
1725{
1726    return new Sinic::Device(this);
1727}
1728