sinic.cc revision 2566
113606Sciro.santilli@arm.com/*
27586SAli.Saidi@arm.com * Copyright (c) 2004-2005 The Regents of The University of Michigan
37586SAli.Saidi@arm.com * All rights reserved.
47586SAli.Saidi@arm.com *
57586SAli.Saidi@arm.com * Redistribution and use in source and binary forms, with or without
67586SAli.Saidi@arm.com * modification, are permitted provided that the following conditions are
77586SAli.Saidi@arm.com * met: redistributions of source code must retain the above copyright
87586SAli.Saidi@arm.com * notice, this list of conditions and the following disclaimer;
97586SAli.Saidi@arm.com * redistributions in binary form must reproduce the above copyright
107586SAli.Saidi@arm.com * notice, this list of conditions and the following disclaimer in the
117586SAli.Saidi@arm.com * documentation and/or other materials provided with the distribution;
127586SAli.Saidi@arm.com * neither the name of the copyright holders nor the names of its
1310118Snilay@cs.wisc.edu * contributors may be used to endorse or promote products derived from
1410118Snilay@cs.wisc.edu * this software without specific prior written permission.
153970Sgblack@eecs.umich.edu *
163005Sstever@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
173005Sstever@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
183005Sstever@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
193005Sstever@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
203005Sstever@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
213005Sstever@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
223005Sstever@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
233005Sstever@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
243005Sstever@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
253005Sstever@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
263005Sstever@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
273005Sstever@eecs.umich.edu */
283005Sstever@eecs.umich.edu
293005Sstever@eecs.umich.edu#include <cstdio>
303005Sstever@eecs.umich.edu#include <deque>
313005Sstever@eecs.umich.edu#include <limits>
323005Sstever@eecs.umich.edu#include <string>
333005Sstever@eecs.umich.edu
343005Sstever@eecs.umich.edu#include "base/inet.hh"
353005Sstever@eecs.umich.edu#include "cpu/exec_context.hh"
363005Sstever@eecs.umich.edu#include "cpu/intr_control.hh"
373005Sstever@eecs.umich.edu#include "dev/etherlink.hh"
383005Sstever@eecs.umich.edu#include "dev/sinic.hh"
393005Sstever@eecs.umich.edu#include "dev/pciconfigall.hh"
403005Sstever@eecs.umich.edu#include "mem/packet.hh"
413005Sstever@eecs.umich.edu#include "sim/builder.hh"
4210118Snilay@cs.wisc.edu#include "sim/debug.hh"
433005Sstever@eecs.umich.edu#include "sim/eventq.hh"
4412564Sgabeblack@google.com#include "sim/host.hh"
4513774Sandreas.sandberg@arm.com#include "sim/stats.hh"
4612564Sgabeblack@google.com#include "arch/vtophys.hh"
476654Snate@binkert.org
486654Snate@binkert.orgusing namespace Net;
492889SN/Ausing namespace TheISA;
502710SN/A
516654Snate@binkert.orgnamespace Sinic {
526654Snate@binkert.org
5312395Sswapnilster@gmail.comconst char *RxStateStrings[] =
5412475Sglenn.bergmans@arm.com{
555457Ssaidi@eecs.umich.edu    "rxIdle",
5611670Sandreas.hansson@arm.com    "rxFifoBlock",
5710118Snilay@cs.wisc.edu    "rxBeginCopy",
5811670Sandreas.hansson@arm.com    "rxCopy",
596654Snate@binkert.org    "rxCopyDone"
6011682Sandreas.hansson@arm.com};
6111682Sandreas.hansson@arm.com
6211682Sandreas.hansson@arm.comconst char *TxStateStrings[] =
6311682Sandreas.hansson@arm.com{
6411682Sandreas.hansson@arm.com    "txIdle",
6511682Sandreas.hansson@arm.com    "txFifoBlock",
6611790Sjungma@eit.uni-kl.de    "txBeginCopy",
6713432Spau.cabre@metempsy.com    "txCopy",
6811682Sandreas.hansson@arm.com    "txCopyDone"
6911682Sandreas.hansson@arm.com};
703444Sktlim@umich.edu
7110594Sgabeblack@google.com
7210594Sgabeblack@google.com///////////////////////////////////////////////////////////////////////
7312564Sgabeblack@google.com//
7412564Sgabeblack@google.com// Sinic PCI Device
7510594Sgabeblack@google.com//
7610594Sgabeblack@google.comBase::Base(Params *p)
7710594Sgabeblack@google.com    : PciDev(p), rxEnable(false), txEnable(false), clock(p->clock),
7810594Sgabeblack@google.com      intrDelay(p->intr_delay), intrTick(0), cpuIntrEnable(false),
7910594Sgabeblack@google.com      cpuPendingIntr(false), intrEvent(0), interface(NULL)
8010594Sgabeblack@google.com{
8110594Sgabeblack@google.com}
8210119Snilay@cs.wisc.edu
8310594Sgabeblack@google.comDevice::Device(Params *p)
8410119Snilay@cs.wisc.edu    : Base(p), rxFifo(p->rx_fifo_size), txFifo(p->tx_fifo_size),
8510594Sgabeblack@google.com      rxKickTick(0), txKickTick(0),
8610594Sgabeblack@google.com      txEvent(this), rxDmaEvent(this), txDmaEvent(this),
8710119Snilay@cs.wisc.edu      dmaReadDelay(p->dma_read_delay), dmaReadFactor(p->dma_read_factor),
8810594Sgabeblack@google.com      dmaWriteDelay(p->dma_write_delay), dmaWriteFactor(p->dma_write_factor)
8910119Snilay@cs.wisc.edu{
9010594Sgabeblack@google.com    reset();
9110119Snilay@cs.wisc.edu
9213864Ssupohaosu@gmail.com}
9313864Ssupohaosu@gmail.com
9410119Snilay@cs.wisc.eduDevice::~Device()
9513864Ssupohaosu@gmail.com{}
9613864Ssupohaosu@gmail.com
9710594Sgabeblack@google.comvoid
9810780SCurtis.Dunham@arm.comDevice::regStats()
9912475Sglenn.bergmans@arm.com{
10012475Sglenn.bergmans@arm.com    rxBytes
10112079Sgedare@rtems.org        .name(name() + ".rxBytes")
10212079Sgedare@rtems.org        .desc("Bytes Received")
10310119Snilay@cs.wisc.edu        .prereq(rxBytes)
10410119Snilay@cs.wisc.edu        ;
10510119Snilay@cs.wisc.edu
10610119Snilay@cs.wisc.edu    rxBandwidth
1072566SN/A        .name(name() + ".rxBandwidth")
10810119Snilay@cs.wisc.edu        .desc("Receive Bandwidth (bits/s)")
10910119Snilay@cs.wisc.edu        .precision(0)
1109665Sandreas.hansson@arm.com        .prereq(rxBytes)
11110119Snilay@cs.wisc.edu        ;
11210119Snilay@cs.wisc.edu
11310119Snilay@cs.wisc.edu    rxPackets
11410119Snilay@cs.wisc.edu        .name(name() + ".rxPackets")
11510119Snilay@cs.wisc.edu        .desc("Number of Packets Received")
11610119Snilay@cs.wisc.edu        .prereq(rxBytes)
11710119Snilay@cs.wisc.edu        ;
11810119Snilay@cs.wisc.edu
11910119Snilay@cs.wisc.edu    rxPacketRate
12010119Snilay@cs.wisc.edu        .name(name() + ".rxPPS")
12110119Snilay@cs.wisc.edu        .desc("Packet Reception Rate (packets/s)")
12210119Snilay@cs.wisc.edu        .precision(0)
12310119Snilay@cs.wisc.edu        .prereq(rxBytes)
12410119Snilay@cs.wisc.edu        ;
12510119Snilay@cs.wisc.edu
12610119Snilay@cs.wisc.edu    rxIpPackets
12710119Snilay@cs.wisc.edu        .name(name() + ".rxIpPackets")
12813803Sodanrc@yahoo.com.br        .desc("Number of IP Packets Received")
12913803Sodanrc@yahoo.com.br        .prereq(rxBytes)
13013803Sodanrc@yahoo.com.br        ;
13110119Snilay@cs.wisc.edu
13210119Snilay@cs.wisc.edu    rxTcpPackets
13310119Snilay@cs.wisc.edu        .name(name() + ".rxTcpPackets")
13410119Snilay@cs.wisc.edu        .desc("Number of Packets Received")
13510119Snilay@cs.wisc.edu        .prereq(rxBytes)
13610119Snilay@cs.wisc.edu        ;
13710119Snilay@cs.wisc.edu
13810119Snilay@cs.wisc.edu    rxUdpPackets
13910119Snilay@cs.wisc.edu        .name(name() + ".rxUdpPackets")
14010119Snilay@cs.wisc.edu        .desc("Number of UDP Packets Received")
14110119Snilay@cs.wisc.edu        .prereq(rxBytes)
14210119Snilay@cs.wisc.edu        ;
14310119Snilay@cs.wisc.edu
14410119Snilay@cs.wisc.edu    rxIpChecksums
14513731Sandreas.sandberg@arm.com        .name(name() + ".rxIpChecksums")
14610119Snilay@cs.wisc.edu        .desc("Number of rx IP Checksums done by device")
14712941Sandreas.sandberg@arm.com        .precision(0)
14811839SCurtis.Dunham@arm.com        .prereq(rxBytes)
14910119Snilay@cs.wisc.edu        ;
15010119Snilay@cs.wisc.edu
15112598Snikos.nikoleris@arm.com    rxTcpChecksums
15210519Snilay@cs.wisc.edu        .name(name() + ".rxTcpChecksums")
15312598Snikos.nikoleris@arm.com        .desc("Number of rx TCP Checksums done by device")
15410119Snilay@cs.wisc.edu        .precision(0)
15510119Snilay@cs.wisc.edu        .prereq(rxBytes)
15610119Snilay@cs.wisc.edu        ;
15710119Snilay@cs.wisc.edu
15810119Snilay@cs.wisc.edu    rxUdpChecksums
15910547Snilay@cs.wisc.edu        .name(name() + ".rxUdpChecksums")
16010547Snilay@cs.wisc.edu        .desc("Number of rx UDP Checksums done by device")
16110547Snilay@cs.wisc.edu        .precision(0)
16210547Snilay@cs.wisc.edu        .prereq(rxBytes)
16310119Snilay@cs.wisc.edu        ;
16410119Snilay@cs.wisc.edu
16510119Snilay@cs.wisc.edu    totBandwidth
16610119Snilay@cs.wisc.edu        .name(name() + ".totBandwidth")
16710119Snilay@cs.wisc.edu        .desc("Total Bandwidth (bits/s)")
16810119Snilay@cs.wisc.edu        .precision(0)
16910119Snilay@cs.wisc.edu        .prereq(totBytes)
17010119Snilay@cs.wisc.edu        ;
17110120Snilay@cs.wisc.edu
17210120Snilay@cs.wisc.edu    totPackets
17310119Snilay@cs.wisc.edu        .name(name() + ".totPackets")
17411598Sandreas.sandberg@arm.com        .desc("Total Packets")
17510120Snilay@cs.wisc.edu        .precision(0)
17610120Snilay@cs.wisc.edu        .prereq(totBytes)
17710119Snilay@cs.wisc.edu        ;
17811598Sandreas.sandberg@arm.com
17911150Smitch.hayenga@arm.com    totBytes
18011150Smitch.hayenga@arm.com        .name(name() + ".totBytes")
18111150Smitch.hayenga@arm.com        .desc("Total Bytes")
18210119Snilay@cs.wisc.edu        .precision(0)
1832995SN/A        .prereq(totBytes)
18410119Snilay@cs.wisc.edu        ;
18510119Snilay@cs.wisc.edu
18610119Snilay@cs.wisc.edu    totPacketRate
18710119Snilay@cs.wisc.edu        .name(name() + ".totPPS")
18810119Snilay@cs.wisc.edu        .desc("Total Tranmission Rate (packets/s)")
18910780SCurtis.Dunham@arm.com        .precision(0)
19010119Snilay@cs.wisc.edu        .prereq(totBytes)
19110119Snilay@cs.wisc.edu        ;
19210119Snilay@cs.wisc.edu
1933304Sstever@eecs.umich.edu    txBytes
19410119Snilay@cs.wisc.edu        .name(name() + ".txBytes")
19510608Sdam.sunwoo@arm.com        .desc("Bytes Transmitted")
19613684Sgiacomo.travaglini@arm.com        .prereq(txBytes)
19713012Sandreas.sandberg@arm.com        ;
19810608Sdam.sunwoo@arm.com
19910608Sdam.sunwoo@arm.com    txBandwidth
20010608Sdam.sunwoo@arm.com        .name(name() + ".txBandwidth")
20113731Sandreas.sandberg@arm.com        .desc("Transmit Bandwidth (bits/s)")
20210608Sdam.sunwoo@arm.com        .precision(0)
20310608Sdam.sunwoo@arm.com        .prereq(txBytes)
20410119Snilay@cs.wisc.edu        ;
20510119Snilay@cs.wisc.edu
20613432Spau.cabre@metempsy.com    txPackets
20713432Spau.cabre@metempsy.com        .name(name() + ".txPackets")
20813432Spau.cabre@metempsy.com        .desc("Number of Packets Transmitted")
20913958Sjairo.balart@metempsy.com        .prereq(txBytes)
21013958Sjairo.balart@metempsy.com        ;
21113958Sjairo.balart@metempsy.com
21213958Sjairo.balart@metempsy.com    txPacketRate
21313958Sjairo.balart@metempsy.com        .name(name() + ".txPPS")
21410119Snilay@cs.wisc.edu        .desc("Packet Tranmission Rate (packets/s)")
2153819Shsul@eecs.umich.edu        .precision(0)
21611251Sradhika.jagtap@ARM.com        .prereq(txBytes)
21711251Sradhika.jagtap@ARM.com        ;
21811251Sradhika.jagtap@ARM.com
21911251Sradhika.jagtap@ARM.com    txIpPackets
22011251Sradhika.jagtap@ARM.com        .name(name() + ".txIpPackets")
22111251Sradhika.jagtap@ARM.com        .desc("Number of IP Packets Transmitted")
22211251Sradhika.jagtap@ARM.com        .prereq(txBytes)
22311251Sradhika.jagtap@ARM.com        ;
22411251Sradhika.jagtap@ARM.com
22511251Sradhika.jagtap@ARM.com    txTcpPackets
22611251Sradhika.jagtap@ARM.com        .name(name() + ".txTcpPackets")
22710119Snilay@cs.wisc.edu        .desc("Number of TCP Packets Transmitted")
22811183Serfan.azarkhish@unibo.it        .prereq(txBytes)
22910119Snilay@cs.wisc.edu        ;
23010118Snilay@cs.wisc.edu
23110119Snilay@cs.wisc.edu    txUdpPackets
2329827Sakash.bagdia@arm.com        .name(name() + ".txUdpPackets")
23310119Snilay@cs.wisc.edu        .desc("Number of Packets Transmitted")
23410119Snilay@cs.wisc.edu        .prereq(txBytes)
23510119Snilay@cs.wisc.edu        ;
23610119Snilay@cs.wisc.edu
23710119Snilay@cs.wisc.edu    txIpChecksums
23810119Snilay@cs.wisc.edu        .name(name() + ".txIpChecksums")
2399827Sakash.bagdia@arm.com        .desc("Number of tx IP Checksums done by device")
24010594Sgabeblack@google.com        .precision(0)
2416654Snate@binkert.org        .prereq(txBytes)
24213803Sodanrc@yahoo.com.br        ;
24313803Sodanrc@yahoo.com.br
2446654Snate@binkert.org    txTcpChecksums
24510594Sgabeblack@google.com        .name(name() + ".txTcpChecksums")
2466654Snate@binkert.org        .desc("Number of tx TCP Checksums done by device")
24710594Sgabeblack@google.com        .precision(0)
2486654Snate@binkert.org        .prereq(txBytes)
24910594Sgabeblack@google.com        ;
25010594Sgabeblack@google.com
2517586SAli.Saidi@arm.com    txUdpChecksums
25210635Satgutier@umich.edu        .name(name() + ".txUdpChecksums")
25313606Sciro.santilli@arm.com        .desc("Number of tx UDP Checksums done by device")
2548661SAli.Saidi@ARM.com        .precision(0)
2559827Sakash.bagdia@arm.com        .prereq(txBytes)
2569827Sakash.bagdia@arm.com        ;
2579827Sakash.bagdia@arm.com
2589793Sakash.bagdia@arm.com    txBandwidth = txBytes * Stats::constant(8) / simSeconds;
25910119Snilay@cs.wisc.edu    rxBandwidth = rxBytes * Stats::constant(8) / simSeconds;
26010119Snilay@cs.wisc.edu    totBandwidth = txBandwidth + rxBandwidth;
2619790Sakash.bagdia@arm.com    totBytes = txBytes + rxBytes;
2629827Sakash.bagdia@arm.com    totPackets = txPackets + rxPackets;
2639827Sakash.bagdia@arm.com    txPacketRate = txPackets / simSeconds;
2649827Sakash.bagdia@arm.com    rxPacketRate = rxPackets / simSeconds;
2659793Sakash.bagdia@arm.com}
2669827Sakash.bagdia@arm.com
2679827Sakash.bagdia@arm.comvoid
2689827Sakash.bagdia@arm.comDevice::prepareIO(int cpu, int index)
2699793Sakash.bagdia@arm.com{
2709793Sakash.bagdia@arm.com    int size = virtualRegs.size();
2719793Sakash.bagdia@arm.com    if (index < size)
2729384SAndreas.Sandberg@arm.com        return;
2738863Snilay@cs.wisc.edu
2747876Sgblack@eecs.umich.edu    virtualRegs.resize(index + 1);
2754837Ssaidi@eecs.umich.edu    for (int i = size; i <= index; ++i)
2764837Ssaidi@eecs.umich.edu        virtualRegs[i].rxPacket = rxFifo.end();
27713803Sodanrc@yahoo.com.br}
27813803Sodanrc@yahoo.com.br
27913803Sodanrc@yahoo.com.brvoid
2809408Sandreas.hansson@arm.comDevice::prepareRead(int cpu, int index)
28112941Sandreas.sandberg@arm.com{
28211839SCurtis.Dunham@arm.com    using namespace Regs;
2839653SAndreas.Sandberg@ARM.com    prepareIO(cpu, index);
2849164Sandreas.hansson@arm.com
2859408Sandreas.hansson@arm.com    VirtualReg &vnic = virtualRegs[index];
2868845Sandreas.hansson@arm.com
2878845Sandreas.hansson@arm.com    // update rx registers
2884837Ssaidi@eecs.umich.edu    uint64_t rxdone = vnic.RxDone;
2899826Sandreas.hansson@arm.com    rxdone = set_RxDone_Packets(rxdone, rxFifo.packets());
2909826Sandreas.hansson@arm.com    regs.RxData = vnic.RxData;
2919835Sandreas.hansson@arm.com    regs.RxDone = rxdone;
2929826Sandreas.hansson@arm.com    regs.RxWait = rxdone;
29313731Sandreas.sandberg@arm.com
2949826Sandreas.hansson@arm.com    // update tx regsiters
2959826Sandreas.hansson@arm.com    uint64_t txdone = vnic.TxDone;
2968659SAli.Saidi@ARM.com    txdone = set_TxDone_Packets(txdone, txFifo.packets());
29710119Snilay@cs.wisc.edu    txdone = set_TxDone_Full(txdone, txFifo.avail() < regs.TxMaxCopy);
29810119Snilay@cs.wisc.edu    txdone = set_TxDone_Low(txdone, txFifo.size() < regs.TxFifoMark);
29910119Snilay@cs.wisc.edu    regs.TxData = vnic.TxData;
30010119Snilay@cs.wisc.edu    regs.TxDone = txdone;
30110119Snilay@cs.wisc.edu    regs.TxWait = txdone;
30210119Snilay@cs.wisc.edu}
30310119Snilay@cs.wisc.edu
30410119Snilay@cs.wisc.eduvoid
30510119Snilay@cs.wisc.eduDevice::prepareWrite(int cpu, int index)
30610119Snilay@cs.wisc.edu{
30710119Snilay@cs.wisc.edu    prepareIO(cpu, index);
30810119Snilay@cs.wisc.edu}
30910119Snilay@cs.wisc.edu
31010119Snilay@cs.wisc.edu/**
31110119Snilay@cs.wisc.edu * I/O read of device register
31212564Sgabeblack@google.com */
31310119Snilay@cs.wisc.eduTick
31410119Snilay@cs.wisc.eduDevice::read(Packet &pkt)
31510119Snilay@cs.wisc.edu{
31610119Snilay@cs.wisc.edu    assert(config.command & PCI_CMD_MSE);
31710119Snilay@cs.wisc.edu    assert(pkt.addr >= BARAddrs[0] && pkt.size < BARSize[0]);
31810119Snilay@cs.wisc.edu
31910119Snilay@cs.wisc.edu    int cpu = pkt.req->getCpuNum();
32010119Snilay@cs.wisc.edu    Addr daddr = pkt.addr - BARAddrs[0];
32110119Snilay@cs.wisc.edu    Addr index = daddr >> Regs::VirtualShift;
32210119Snilay@cs.wisc.edu    Addr raddr = daddr & Regs::VirtualMask;
32310119Snilay@cs.wisc.edu
32410119Snilay@cs.wisc.edu    pkt.time = curTick + pioDelay;
32512564Sgabeblack@google.com    pkt.allocate();
32612564Sgabeblack@google.com
32710119Snilay@cs.wisc.edu    if (!regValid(raddr))
32810119Snilay@cs.wisc.edu        panic("invalid register: cpu=%d, da=%#x pa=%#x size=%d",
32910119Snilay@cs.wisc.edu                cpu, daddr, pkt.addr, pkt.size);
33010697SCurtis.Dunham@arm.com
33110747SChris.Emmons@arm.com    const Regs::Info &info = regInfo(raddr);
33210697SCurtis.Dunham@arm.com    if (!info.read)
33310747SChris.Emmons@arm.com        panic("reading %s (write only): cpu=%d da=%#x pa=%#x size=%d",
33410119Snilay@cs.wisc.edu                info.name, cpu, daddr, pkt.addr, pkt.size);
33510697SCurtis.Dunham@arm.com
33610747SChris.Emmons@arm.com    if (pkt.size != info.size)
33710119Snilay@cs.wisc.edu        panic("invalid size for reg %s: cpu=%d da=%#x pa=%#x size=%d",
33810119Snilay@cs.wisc.edu                info.name, cpu, daddr, pkt.addr, pkt.size);
33910119Snilay@cs.wisc.edu
34010119Snilay@cs.wisc.edu    prepareRead(cpu, index);
34110119Snilay@cs.wisc.edu
34210119Snilay@cs.wisc.edu    uint64_t value = 0;
3438801Sgblack@eecs.umich.edu    if (pkt.size == 4) {
34411291Sgabor.dozsa@arm.com        uint32_t reg = regData32(raddr);
34511291Sgabor.dozsa@arm.com        pkt.set(reg);
34611291Sgabor.dozsa@arm.com        value = reg;
34711291Sgabor.dozsa@arm.com    }
34811291Sgabor.dozsa@arm.com
34911291Sgabor.dozsa@arm.com    if (pkt.size == 8) {
35011291Sgabor.dozsa@arm.com        uint64_t reg = regData64(raddr);
35111291Sgabor.dozsa@arm.com        pkt.set(reg);
35211291Sgabor.dozsa@arm.com        value = reg;
35311291Sgabor.dozsa@arm.com    }
35411291Sgabor.dozsa@arm.com
35511291Sgabor.dozsa@arm.com    DPRINTF(EthernetPIO,
3563005Sstever@eecs.umich.edu            "read %s cpu=%d da=%#x pa=%#x size=%d val=%#x\n",
3578801Sgblack@eecs.umich.edu            info.name, cpu, daddr, pkt.addr, pkt.size, value);
3583005Sstever@eecs.umich.edu
35912564Sgabeblack@google.com    // reading the interrupt status register has the side effect of
3603005Sstever@eecs.umich.edu    // clearing it
3612566SN/A    if (raddr == Regs::IntrStatus)
3627861Sgblack@eecs.umich.edu        devIntrClear();
3637861Sgblack@eecs.umich.edu
3647861Sgblack@eecs.umich.edu    return pioDelay;
3658635Schris.emmons@arm.com}
3668635Schris.emmons@arm.com
3678635Schris.emmons@arm.com/**
36813606Sciro.santilli@arm.com * IPR read of device register
36913606Sciro.santilli@arm.com
37012475Sglenn.bergmans@arm.com    Fault
37112475Sglenn.bergmans@arm.comDevice::iprRead(Addr daddr, int cpu, uint64_t &result)
37212475Sglenn.bergmans@arm.com{
37312475Sglenn.bergmans@arm.com    if (!regValid(daddr))
37412475Sglenn.bergmans@arm.com        panic("invalid address: da=%#x", daddr);
37512475Sglenn.bergmans@arm.com
37612475Sglenn.bergmans@arm.com    const Regs::Info &info = regInfo(daddr);
37712475Sglenn.bergmans@arm.com    if (!info.read)
37812475Sglenn.bergmans@arm.com        panic("reading %s (write only): cpu=%d da=%#x", info.name, cpu, daddr);
37913608Sgiacomo.travaglini@arm.com
38012475Sglenn.bergmans@arm.com    DPRINTF(EthernetPIO, "IPR read %s: cpu=%d da=%#x\n",
3819061Snilay@cs.wisc.edu            info.name, cpu, daddr);
3823481Shsul@eecs.umich.edu
383    prepareRead(cpu, 0);
384
385    if (info.size == 4)
386        result = regData32(daddr);
387
388    if (info.size == 8)
389        result = regData64(daddr);
390
391    DPRINTF(EthernetPIO, "IPR read %s: cpu=%s da=%#x val=%#x\n",
392            info.name, cpu, result);
393
394    return NoFault;
395}
396*/
397/**
398 * I/O write of device register
399 */
400Tick
401Device::write(Packet &pkt)
402{
403    assert(config.command & PCI_CMD_MSE);
404    assert(pkt.addr >= BARAddrs[0] && pkt.size < BARSize[0]);
405
406    int cpu = pkt.req->getCpuNum();
407    Addr daddr = pkt.addr - BARAddrs[0];
408    Addr index = daddr >> Regs::VirtualShift;
409    Addr raddr = daddr & Regs::VirtualMask;
410
411    pkt.time = curTick + pioDelay;
412
413    if (!regValid(raddr))
414        panic("invalid register: cpu=%d, da=%#x pa=%#x size=%d",
415                cpu, daddr, pkt.addr, pkt.size);
416
417    const Regs::Info &info = regInfo(raddr);
418    if (!info.write)
419        panic("write %s (read only): cpu=%d da=%#x pa=%#x size=%d",
420                info.name, cpu, daddr, pkt.addr, pkt.size);
421
422    if (pkt.size != info.size)
423        panic("invalid size for reg %s: cpu=%d da=%#x pa=%#x size=%d",
424                info.name, cpu, daddr, pkt.addr, pkt.size);
425
426    VirtualReg &vnic = virtualRegs[index];
427
428    DPRINTF(EthernetPIO,
429            "write %s: cpu=%d val=%#x da=%#x pa=%#x size=%d\n",
430            info.name, cpu, info.size == 4 ? pkt.get<uint32_t>() :
431            pkt.get<uint64_t>(), daddr, pkt.addr, pkt.size);
432
433    prepareWrite(cpu, index);
434
435    switch (raddr) {
436      case Regs::Config:
437        changeConfig(pkt.get<uint32_t>());
438        break;
439
440      case Regs::Command:
441        command(pkt.get<uint32_t>());
442        break;
443
444      case Regs::IntrStatus:
445        devIntrClear(regs.IntrStatus & pkt.get<uint32_t>());
446        break;
447
448      case Regs::IntrMask:
449        devIntrChangeMask(pkt.get<uint32_t>());
450        break;
451
452      case Regs::RxData:
453        if (Regs::get_RxDone_Busy(vnic.RxDone))
454            panic("receive machine busy with another request! rxState=%s",
455                  RxStateStrings[rxState]);
456
457        vnic.RxDone = Regs::RxDone_Busy;
458        vnic.RxData = pkt.get<uint64_t>();
459        rxList.push_back(index);
460        if (rxEnable && rxState == rxIdle) {
461            rxState = rxFifoBlock;
462            rxKick();
463        }
464        break;
465
466      case Regs::TxData:
467        if (Regs::get_TxDone_Busy(vnic.TxDone))
468            panic("transmit machine busy with another request! txState=%s",
469                  TxStateStrings[txState]);
470
471        vnic.TxDone = Regs::TxDone_Busy;
472        vnic.TxData = pkt.get<uint64_t>();
473        if (txList.empty() || txList.front() != index)
474            txList.push_back(index);
475        if (txEnable && txState == txIdle && txList.front() == index) {
476            txState = txFifoBlock;
477            txKick();
478        }
479        break;
480    }
481
482    return pioDelay;
483}
484
485void
486Device::devIntrPost(uint32_t interrupts)
487{
488    if ((interrupts & Regs::Intr_Res))
489        panic("Cannot set a reserved interrupt");
490
491    regs.IntrStatus |= interrupts;
492
493    DPRINTF(EthernetIntr,
494            "interrupt written to intStatus: intr=%#x status=%#x mask=%#x\n",
495            interrupts, regs.IntrStatus, regs.IntrMask);
496
497    interrupts = regs.IntrStatus & regs.IntrMask;
498
499    // Intr_RxHigh is special, we only signal it if we've emptied the fifo
500    // and then filled it above the high watermark
501    if (rxEmpty)
502        rxEmpty = false;
503    else
504        interrupts &= ~Regs::Intr_RxHigh;
505
506    // Intr_TxLow is special, we only signal it if we've filled up the fifo
507    // and then dropped below the low watermark
508    if (txFull)
509        txFull = false;
510    else
511        interrupts &= ~Regs::Intr_TxLow;
512
513    if (interrupts) {
514        Tick when = curTick;
515        if ((interrupts & Regs::Intr_NoDelay) == 0)
516            when += intrDelay;
517        cpuIntrPost(when);
518    }
519}
520
521void
522Device::devIntrClear(uint32_t interrupts)
523{
524    if ((interrupts & Regs::Intr_Res))
525        panic("Cannot clear a reserved interrupt");
526
527    regs.IntrStatus &= ~interrupts;
528
529    DPRINTF(EthernetIntr,
530            "interrupt cleared from intStatus: intr=%x status=%x mask=%x\n",
531            interrupts, regs.IntrStatus, regs.IntrMask);
532
533    if (!(regs.IntrStatus & regs.IntrMask))
534        cpuIntrClear();
535}
536
537void
538Device::devIntrChangeMask(uint32_t newmask)
539{
540    if (regs.IntrMask == newmask)
541        return;
542
543    regs.IntrMask = newmask;
544
545    DPRINTF(EthernetIntr,
546            "interrupt mask changed: intStatus=%x intMask=%x masked=%x\n",
547            regs.IntrStatus, regs.IntrMask, regs.IntrStatus & regs.IntrMask);
548
549    if (regs.IntrStatus & regs.IntrMask)
550        cpuIntrPost(curTick);
551    else
552        cpuIntrClear();
553}
554
555void
556Base::cpuIntrPost(Tick when)
557{
558    // If the interrupt you want to post is later than an interrupt
559    // already scheduled, just let it post in the coming one and don't
560    // schedule another.
561    // HOWEVER, must be sure that the scheduled intrTick is in the
562    // future (this was formerly the source of a bug)
563    /**
564     * @todo this warning should be removed and the intrTick code should
565     * be fixed.
566     */
567    assert(when >= curTick);
568    assert(intrTick >= curTick || intrTick == 0);
569    if (!cpuIntrEnable) {
570        DPRINTF(EthernetIntr, "interrupts not enabled.\n",
571                intrTick);
572        return;
573    }
574
575    if (when > intrTick && intrTick != 0) {
576        DPRINTF(EthernetIntr, "don't need to schedule event...intrTick=%d\n",
577                intrTick);
578        return;
579    }
580
581    intrTick = when;
582    if (intrTick < curTick) {
583        debug_break();
584        intrTick = curTick;
585    }
586
587    DPRINTF(EthernetIntr, "going to schedule an interrupt for intrTick=%d\n",
588            intrTick);
589
590    if (intrEvent)
591        intrEvent->squash();
592    intrEvent = new IntrEvent(this, true);
593    intrEvent->schedule(intrTick);
594}
595
596void
597Base::cpuInterrupt()
598{
599    assert(intrTick == curTick);
600
601    // Whether or not there's a pending interrupt, we don't care about
602    // it anymore
603    intrEvent = 0;
604    intrTick = 0;
605
606    // Don't send an interrupt if there's already one
607    if (cpuPendingIntr) {
608        DPRINTF(EthernetIntr,
609                "would send an interrupt now, but there's already pending\n");
610    } else {
611        // Send interrupt
612        cpuPendingIntr = true;
613
614        DPRINTF(EthernetIntr, "posting interrupt\n");
615        intrPost();
616    }
617}
618
619void
620Base::cpuIntrClear()
621{
622    if (!cpuPendingIntr)
623        return;
624
625    if (intrEvent) {
626        intrEvent->squash();
627        intrEvent = 0;
628    }
629
630    intrTick = 0;
631
632    cpuPendingIntr = false;
633
634    DPRINTF(EthernetIntr, "clearing cchip interrupt\n");
635    intrClear();
636}
637
638bool
639Base::cpuIntrPending() const
640{ return cpuPendingIntr; }
641
642void
643Device::changeConfig(uint32_t newconf)
644{
645    uint32_t changed = regs.Config ^ newconf;
646    if (!changed)
647        return;
648
649    regs.Config = newconf;
650
651    if ((changed & Regs::Config_IntEn)) {
652        cpuIntrEnable = regs.Config & Regs::Config_IntEn;
653        if (cpuIntrEnable) {
654            if (regs.IntrStatus & regs.IntrMask)
655                cpuIntrPost(curTick);
656        } else {
657            cpuIntrClear();
658        }
659    }
660
661    if ((changed & Regs::Config_TxEn)) {
662        txEnable = regs.Config & Regs::Config_TxEn;
663        if (txEnable)
664            txKick();
665    }
666
667    if ((changed & Regs::Config_RxEn)) {
668        rxEnable = regs.Config & Regs::Config_RxEn;
669        if (rxEnable)
670            rxKick();
671    }
672}
673
674void
675Device::command(uint32_t command)
676{
677    if (command & Regs::Command_Intr)
678        devIntrPost(Regs::Intr_Soft);
679
680    if (command & Regs::Command_Reset)
681        reset();
682}
683
684void
685Device::reset()
686{
687    using namespace Regs;
688
689    memset(&regs, 0, sizeof(regs));
690
691    regs.Config = 0;
692    if (params()->rx_thread)
693        regs.Config |= Config_RxThread;
694    if (params()->tx_thread)
695        regs.Config |= Config_TxThread;
696    if (params()->rss)
697        regs.Config |= Config_RSS;
698    regs.IntrMask = Intr_Soft | Intr_RxHigh | Intr_RxPacket | Intr_TxLow;
699    regs.RxMaxCopy = params()->rx_max_copy;
700    regs.TxMaxCopy = params()->tx_max_copy;
701    regs.RxMaxIntr = params()->rx_max_intr;
702    regs.RxFifoSize = params()->rx_fifo_size;
703    regs.TxFifoSize = params()->tx_fifo_size;
704    regs.RxFifoMark = params()->rx_fifo_threshold;
705    regs.TxFifoMark = params()->tx_fifo_threshold;
706    regs.HwAddr = params()->eaddr;
707
708    rxList.clear();
709    txList.clear();
710
711    rxState = rxIdle;
712    txState = txIdle;
713
714    rxFifo.clear();
715    rxFifoPtr = rxFifo.end();
716    txFifo.clear();
717    rxEmpty = false;
718    txFull = false;
719
720    int size = virtualRegs.size();
721    virtualRegs.clear();
722    virtualRegs.resize(size);
723    for (int i = 0; i < size; ++i)
724        virtualRegs[i].rxPacket = rxFifo.end();
725}
726
727void
728Device::rxDmaDone()
729{
730    assert(rxState == rxCopy);
731    rxState = rxCopyDone;
732    DPRINTF(EthernetDMA, "rx dma write paddr=%#x len=%d\n",
733            rxDmaAddr, rxDmaLen);
734    DDUMP(EthernetData, rxDmaData, rxDmaLen);
735
736    // If the transmit state machine  has a pending DMA, let it go first
737    if (txState == txBeginCopy)
738        txKick();
739
740    rxKick();
741}
742
743void
744Device::rxKick()
745{
746    VirtualReg *vnic;
747
748    DPRINTF(EthernetSM, "receive kick rxState=%s (rxFifo.size=%d)\n",
749            RxStateStrings[rxState], rxFifo.size());
750
751    if (rxKickTick > curTick) {
752        DPRINTF(EthernetSM, "receive kick exiting, can't run till %d\n",
753                rxKickTick);
754        return;
755    }
756
757  next:
758    if (rxState == rxIdle)
759        goto exit;
760
761    assert(!rxList.empty());
762    vnic = &virtualRegs[rxList.front()];
763
764    DPRINTF(EthernetSM, "processing rxState=%s for virtual nic %d\n",
765            RxStateStrings[rxState], rxList.front());
766
767    switch (rxState) {
768      case rxFifoBlock:
769        if (vnic->rxPacket != rxFifo.end()) {
770            rxState = rxBeginCopy;
771            break;
772        }
773
774        if (rxFifoPtr == rxFifo.end()) {
775            DPRINTF(EthernetSM, "receive waiting for data.  Nothing to do.\n");
776            goto exit;
777        }
778
779        assert(!rxFifo.empty());
780
781        // Grab a new packet from the fifo.
782        vnic->rxPacket = rxFifoPtr++;
783        vnic->rxPacketOffset = 0;
784        vnic->rxPacketBytes = (*vnic->rxPacket)->length;
785        assert(vnic->rxPacketBytes);
786
787        vnic->rxDoneData = 0;
788        /* scope for variables */ {
789            IpPtr ip(*vnic->rxPacket);
790            if (ip) {
791                vnic->rxDoneData |= Regs::RxDone_IpPacket;
792                rxIpChecksums++;
793                if (cksum(ip) != 0) {
794                    DPRINTF(EthernetCksum, "Rx IP Checksum Error\n");
795                    vnic->rxDoneData |= Regs::RxDone_IpError;
796                }
797                TcpPtr tcp(ip);
798                UdpPtr udp(ip);
799                if (tcp) {
800                    vnic->rxDoneData |= Regs::RxDone_TcpPacket;
801                    rxTcpChecksums++;
802                    if (cksum(tcp) != 0) {
803                        DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n");
804                        vnic->rxDoneData |= Regs::RxDone_TcpError;
805                    }
806                } else if (udp) {
807                    vnic->rxDoneData |= Regs::RxDone_UdpPacket;
808                    rxUdpChecksums++;
809                    if (cksum(udp) != 0) {
810                        DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n");
811                        vnic->rxDoneData |= Regs::RxDone_UdpError;
812                    }
813                }
814            }
815        }
816        rxState = rxBeginCopy;
817        break;
818
819      case rxBeginCopy:
820        if (dmaPending())
821            goto exit;
822
823        rxDmaAddr = params()->platform->pciToDma(
824                Regs::get_RxData_Addr(vnic->RxData));
825        rxDmaLen = std::min<int>(Regs::get_RxData_Len(vnic->RxData),
826                            vnic->rxPacketBytes);
827        rxDmaData = (*vnic->rxPacket)->data + vnic->rxPacketOffset;
828        rxState = rxCopy;
829
830        dmaWrite(rxDmaAddr, rxDmaLen, &rxDmaEvent, rxDmaData);
831        break;
832
833      case rxCopy:
834        DPRINTF(EthernetSM, "receive machine still copying\n");
835        goto exit;
836
837      case rxCopyDone:
838        vnic->RxDone = vnic->rxDoneData | rxDmaLen;
839        vnic->RxDone |= Regs::RxDone_Complete;
840
841        if (vnic->rxPacketBytes == rxDmaLen) {
842            DPRINTF(EthernetSM, "rxKick: packet complete on vnic %d\n",
843                    rxList.front());
844            rxFifo.remove(vnic->rxPacket);
845            vnic->rxPacket = rxFifo.end();
846        } else {
847            vnic->RxDone |= Regs::RxDone_More;
848            vnic->rxPacketBytes -= rxDmaLen;
849            vnic->rxPacketOffset += rxDmaLen;
850            DPRINTF(EthernetSM,
851                    "rxKick: packet not complete on vnic %d: %d bytes left\n",
852                    rxList.front(), vnic->rxPacketBytes);
853        }
854
855        rxList.pop_front();
856        rxState = rxList.empty() ? rxIdle : rxFifoBlock;
857
858        if (rxFifo.empty()) {
859            devIntrPost(Regs::Intr_RxEmpty);
860            rxEmpty = true;
861        }
862
863        devIntrPost(Regs::Intr_RxDMA);
864        break;
865
866      default:
867        panic("Invalid rxState!");
868    }
869
870    DPRINTF(EthernetSM, "entering next rxState=%s\n",
871            RxStateStrings[rxState]);
872
873    goto next;
874
875  exit:
876    /**
877     * @todo do we want to schedule a future kick?
878     */
879    DPRINTF(EthernetSM, "rx state machine exited rxState=%s\n",
880            RxStateStrings[rxState]);
881}
882
883void
884Device::txDmaDone()
885{
886    assert(txState == txCopy);
887    txState = txCopyDone;
888    DPRINTF(EthernetDMA, "tx dma read paddr=%#x len=%d\n",
889            txDmaAddr, txDmaLen);
890    DDUMP(EthernetData, txDmaData, txDmaLen);
891
892    // If the receive state machine  has a pending DMA, let it go first
893    if (rxState == rxBeginCopy)
894        rxKick();
895
896    txKick();
897}
898
899void
900Device::transmit()
901{
902    if (txFifo.empty()) {
903        DPRINTF(Ethernet, "nothing to transmit\n");
904        return;
905    }
906
907    uint32_t interrupts;
908    EthPacketPtr packet = txFifo.front();
909    if (!interface->sendPacket(packet)) {
910        DPRINTF(Ethernet, "Packet Transmit: failed txFifo available %d\n",
911                txFifo.avail());
912        goto reschedule;
913    }
914
915    txFifo.pop();
916#if TRACING_ON
917    if (DTRACE(Ethernet)) {
918        IpPtr ip(packet);
919        if (ip) {
920            DPRINTF(Ethernet, "ID is %d\n", ip->id());
921            TcpPtr tcp(ip);
922            if (tcp) {
923                DPRINTF(Ethernet, "Src Port=%d, Dest Port=%d\n",
924                        tcp->sport(), tcp->dport());
925            }
926        }
927    }
928#endif
929
930    DDUMP(EthernetData, packet->data, packet->length);
931    txBytes += packet->length;
932    txPackets++;
933
934    DPRINTF(Ethernet, "Packet Transmit: successful txFifo Available %d\n",
935            txFifo.avail());
936
937    interrupts = Regs::Intr_TxPacket;
938    if (txFifo.size() < regs.TxFifoMark)
939        interrupts |= Regs::Intr_TxLow;
940    devIntrPost(interrupts);
941
942  reschedule:
943   if (!txFifo.empty() && !txEvent.scheduled()) {
944       DPRINTF(Ethernet, "reschedule transmit\n");
945       txEvent.schedule(curTick + retryTime);
946   }
947}
948
949void
950Device::txKick()
951{
952    VirtualReg *vnic;
953    DPRINTF(EthernetSM, "transmit kick txState=%s (txFifo.size=%d)\n",
954            TxStateStrings[txState], txFifo.size());
955
956    if (txKickTick > curTick) {
957        DPRINTF(EthernetSM, "transmit kick exiting, can't run till %d\n",
958                txKickTick);
959        return;
960    }
961
962  next:
963    if (txState == txIdle)
964        goto exit;
965
966    assert(!txList.empty());
967    vnic = &virtualRegs[txList.front()];
968
969    switch (txState) {
970      case txFifoBlock:
971        assert(Regs::get_TxDone_Busy(vnic->TxData));
972        if (!txPacket) {
973            // Grab a new packet from the fifo.
974            txPacket = new EthPacketData(16384);
975            txPacketOffset = 0;
976        }
977
978        if (txFifo.avail() - txPacket->length <
979            Regs::get_TxData_Len(vnic->TxData)) {
980            DPRINTF(EthernetSM, "transmit fifo full.  Nothing to do.\n");
981            goto exit;
982        }
983
984        txState = txBeginCopy;
985        break;
986
987      case txBeginCopy:
988        if (dmaPending())
989            goto exit;
990
991        txDmaAddr = params()->platform->pciToDma(
992                Regs::get_TxData_Addr(vnic->TxData));
993        txDmaLen = Regs::get_TxData_Len(vnic->TxData);
994        txDmaData = txPacket->data + txPacketOffset;
995        txState = txCopy;
996
997        dmaRead(txDmaAddr, txDmaLen, &txDmaEvent, txDmaData);
998        break;
999
1000      case txCopy:
1001        DPRINTF(EthernetSM, "transmit machine still copying\n");
1002        goto exit;
1003
1004      case txCopyDone:
1005        vnic->TxDone = txDmaLen | Regs::TxDone_Complete;
1006        txPacket->length += txDmaLen;
1007        if ((vnic->TxData & Regs::TxData_More)) {
1008            txPacketOffset += txDmaLen;
1009            txState = txIdle;
1010            devIntrPost(Regs::Intr_TxDMA);
1011            break;
1012        }
1013
1014        assert(txPacket->length <= txFifo.avail());
1015        if ((vnic->TxData & Regs::TxData_Checksum)) {
1016            IpPtr ip(txPacket);
1017            if (ip) {
1018                TcpPtr tcp(ip);
1019                if (tcp) {
1020                    tcp->sum(0);
1021                    tcp->sum(cksum(tcp));
1022                    txTcpChecksums++;
1023                }
1024
1025                UdpPtr udp(ip);
1026                if (udp) {
1027                    udp->sum(0);
1028                    udp->sum(cksum(udp));
1029                    txUdpChecksums++;
1030                }
1031
1032                ip->sum(0);
1033                ip->sum(cksum(ip));
1034                txIpChecksums++;
1035            }
1036        }
1037
1038        txFifo.push(txPacket);
1039        if (txFifo.avail() < regs.TxMaxCopy) {
1040            devIntrPost(Regs::Intr_TxFull);
1041            txFull = true;
1042        }
1043        txPacket = 0;
1044        transmit();
1045        txList.pop_front();
1046        txState = txList.empty() ? txIdle : txFifoBlock;
1047        devIntrPost(Regs::Intr_TxDMA);
1048        break;
1049
1050      default:
1051        panic("Invalid txState!");
1052    }
1053
1054    DPRINTF(EthernetSM, "entering next txState=%s\n",
1055            TxStateStrings[txState]);
1056
1057    goto next;
1058
1059  exit:
1060    /**
1061     * @todo do we want to schedule a future kick?
1062     */
1063    DPRINTF(EthernetSM, "tx state machine exited txState=%s\n",
1064            TxStateStrings[txState]);
1065}
1066
1067void
1068Device::transferDone()
1069{
1070    if (txFifo.empty()) {
1071        DPRINTF(Ethernet, "transfer complete: txFifo empty...nothing to do\n");
1072        return;
1073    }
1074
1075    DPRINTF(Ethernet, "transfer complete: data in txFifo...schedule xmit\n");
1076
1077    if (txEvent.scheduled())
1078        txEvent.reschedule(curTick + cycles(1));
1079    else
1080        txEvent.schedule(curTick + cycles(1));
1081}
1082
1083bool
1084Device::rxFilter(const EthPacketPtr &packet)
1085{
1086    if (!Regs::get_Config_Filter(regs.Config))
1087        return false;
1088
1089    panic("receive filter not implemented\n");
1090    bool drop = true;
1091
1092#if 0
1093    string type;
1094
1095    EthHdr *eth = packet->eth();
1096    if (eth->unicast()) {
1097        // If we're accepting all unicast addresses
1098        if (acceptUnicast)
1099            drop = false;
1100
1101        // If we make a perfect match
1102        if (acceptPerfect && params->eaddr == eth.dst())
1103            drop = false;
1104
1105        if (acceptArp && eth->type() == ETH_TYPE_ARP)
1106            drop = false;
1107
1108    } else if (eth->broadcast()) {
1109        // if we're accepting broadcasts
1110        if (acceptBroadcast)
1111            drop = false;
1112
1113    } else if (eth->multicast()) {
1114        // if we're accepting all multicasts
1115        if (acceptMulticast)
1116            drop = false;
1117
1118    }
1119
1120    if (drop) {
1121        DPRINTF(Ethernet, "rxFilter drop\n");
1122        DDUMP(EthernetData, packet->data, packet->length);
1123    }
1124#endif
1125    return drop;
1126}
1127
1128bool
1129Device::recvPacket(EthPacketPtr packet)
1130{
1131    rxBytes += packet->length;
1132    rxPackets++;
1133
1134    DPRINTF(Ethernet, "Receiving packet from wire, rxFifo Available is %d\n",
1135            rxFifo.avail());
1136
1137    if (!rxEnable) {
1138        DPRINTF(Ethernet, "receive disabled...packet dropped\n");
1139        return true;
1140    }
1141
1142    if (rxFilter(packet)) {
1143        DPRINTF(Ethernet, "packet filtered...dropped\n");
1144        return true;
1145    }
1146
1147    if (rxFifo.size() >= regs.RxFifoMark)
1148        devIntrPost(Regs::Intr_RxHigh);
1149
1150    if (!rxFifo.push(packet)) {
1151        DPRINTF(Ethernet,
1152                "packet will not fit in receive buffer...packet dropped\n");
1153        return false;
1154    }
1155
1156    // If we were at the last element, back up one ot go to the new
1157    // last element of the list.
1158    if (rxFifoPtr == rxFifo.end())
1159        --rxFifoPtr;
1160
1161    devIntrPost(Regs::Intr_RxPacket);
1162    rxKick();
1163    return true;
1164}
1165
1166//=====================================================================
1167//
1168//
1169void
1170Base::serialize(std::ostream &os)
1171{
1172    // Serialize the PciDev base class
1173    PciDev::serialize(os);
1174
1175    SERIALIZE_SCALAR(rxEnable);
1176    SERIALIZE_SCALAR(txEnable);
1177    SERIALIZE_SCALAR(cpuIntrEnable);
1178
1179    /*
1180     * Keep track of pending interrupt status.
1181     */
1182    SERIALIZE_SCALAR(intrTick);
1183    SERIALIZE_SCALAR(cpuPendingIntr);
1184    Tick intrEventTick = 0;
1185    if (intrEvent)
1186        intrEventTick = intrEvent->when();
1187    SERIALIZE_SCALAR(intrEventTick);
1188}
1189
1190void
1191Base::unserialize(Checkpoint *cp, const std::string &section)
1192{
1193    // Unserialize the PciDev base class
1194    PciDev::unserialize(cp, section);
1195
1196    UNSERIALIZE_SCALAR(rxEnable);
1197    UNSERIALIZE_SCALAR(txEnable);
1198    UNSERIALIZE_SCALAR(cpuIntrEnable);
1199
1200    /*
1201     * Keep track of pending interrupt status.
1202     */
1203    UNSERIALIZE_SCALAR(intrTick);
1204    UNSERIALIZE_SCALAR(cpuPendingIntr);
1205    Tick intrEventTick;
1206    UNSERIALIZE_SCALAR(intrEventTick);
1207    if (intrEventTick) {
1208        intrEvent = new IntrEvent(this, true);
1209        intrEvent->schedule(intrEventTick);
1210    }
1211}
1212
1213void
1214Device::serialize(std::ostream &os)
1215{
1216    // Serialize the PciDev base class
1217    Base::serialize(os);
1218
1219    if (rxState == rxCopy)
1220        panic("can't serialize with an in flight dma request rxState=%s",
1221              RxStateStrings[rxState]);
1222
1223    if (txState == txCopy)
1224        panic("can't serialize with an in flight dma request txState=%s",
1225              TxStateStrings[txState]);
1226
1227    /*
1228     * Serialize the device registers
1229     */
1230    SERIALIZE_SCALAR(regs.Config);
1231    SERIALIZE_SCALAR(regs.IntrStatus);
1232    SERIALIZE_SCALAR(regs.IntrMask);
1233    SERIALIZE_SCALAR(regs.RxMaxCopy);
1234    SERIALIZE_SCALAR(regs.TxMaxCopy);
1235    SERIALIZE_SCALAR(regs.RxMaxIntr);
1236    SERIALIZE_SCALAR(regs.RxData);
1237    SERIALIZE_SCALAR(regs.RxDone);
1238    SERIALIZE_SCALAR(regs.TxData);
1239    SERIALIZE_SCALAR(regs.TxDone);
1240
1241    /*
1242     * Serialize the virtual nic state
1243     */
1244    int virtualRegsSize = virtualRegs.size();
1245    SERIALIZE_SCALAR(virtualRegsSize);
1246    for (int i = 0; i < virtualRegsSize; ++i) {
1247        VirtualReg *vnic = &virtualRegs[i];
1248
1249        std::string reg = csprintf("vnic%d", i);
1250        paramOut(os, reg + ".RxData", vnic->RxData);
1251        paramOut(os, reg + ".RxDone", vnic->RxDone);
1252        paramOut(os, reg + ".TxData", vnic->TxData);
1253        paramOut(os, reg + ".TxDone", vnic->TxDone);
1254
1255        PacketFifo::iterator rxFifoPtr;
1256
1257        bool rxPacketExists = vnic->rxPacket != rxFifo.end();
1258        paramOut(os, reg + ".rxPacketExists", rxPacketExists);
1259        if (rxPacketExists) {
1260            int rxPacket = 0;
1261            PacketFifo::iterator i = rxFifo.begin();
1262            while (i != vnic->rxPacket) {
1263                assert(i != rxFifo.end());
1264                ++i;
1265                ++rxPacket;
1266            }
1267
1268            paramOut(os, reg + ".rxPacket", rxPacket);
1269            paramOut(os, reg + ".rxPacketOffset", vnic->rxPacketOffset);
1270            paramOut(os, reg + ".rxPacketBytes", vnic->rxPacketBytes);
1271        }
1272        paramOut(os, reg + ".rxDoneData", vnic->rxDoneData);
1273    }
1274
1275    VirtualList::iterator i, end;
1276    int count;
1277
1278    int rxListSize = rxList.size();
1279    SERIALIZE_SCALAR(rxListSize);
1280    for (count = 0, i = rxList.begin(), end = rxList.end(); i != end; ++i)
1281        paramOut(os, csprintf("rxList%d", count++), *i);
1282
1283    int txListSize = txList.size();
1284    SERIALIZE_SCALAR(txListSize);
1285    for (count = 0, i = txList.begin(), end = txList.end(); i != end; ++i)
1286        paramOut(os, csprintf("txList%d", count++), *i);
1287
1288    /*
1289     * Serialize rx state machine
1290     */
1291    int rxState = this->rxState;
1292    SERIALIZE_SCALAR(rxState);
1293    SERIALIZE_SCALAR(rxEmpty);
1294    rxFifo.serialize("rxFifo", os);
1295
1296    /*
1297     * Serialize tx state machine
1298     */
1299    int txState = this->txState;
1300    SERIALIZE_SCALAR(txState);
1301    SERIALIZE_SCALAR(txFull);
1302    txFifo.serialize("txFifo", os);
1303    bool txPacketExists = txPacket;
1304    SERIALIZE_SCALAR(txPacketExists);
1305    if (txPacketExists) {
1306        txPacket->serialize("txPacket", os);
1307        SERIALIZE_SCALAR(txPacketOffset);
1308        SERIALIZE_SCALAR(txPacketBytes);
1309    }
1310
1311    /*
1312     * If there's a pending transmit, store the time so we can
1313     * reschedule it later
1314     */
1315    Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick : 0;
1316    SERIALIZE_SCALAR(transmitTick);
1317}
1318
1319void
1320Device::unserialize(Checkpoint *cp, const std::string &section)
1321{
1322    // Unserialize the PciDev base class
1323    Base::unserialize(cp, section);
1324
1325    /*
1326     * Unserialize the device registers
1327     */
1328    UNSERIALIZE_SCALAR(regs.Config);
1329    UNSERIALIZE_SCALAR(regs.IntrStatus);
1330    UNSERIALIZE_SCALAR(regs.IntrMask);
1331    UNSERIALIZE_SCALAR(regs.RxMaxCopy);
1332    UNSERIALIZE_SCALAR(regs.TxMaxCopy);
1333    UNSERIALIZE_SCALAR(regs.RxMaxIntr);
1334    UNSERIALIZE_SCALAR(regs.RxData);
1335    UNSERIALIZE_SCALAR(regs.RxDone);
1336    UNSERIALIZE_SCALAR(regs.TxData);
1337    UNSERIALIZE_SCALAR(regs.TxDone);
1338
1339    int rxListSize;
1340    UNSERIALIZE_SCALAR(rxListSize);
1341    rxList.clear();
1342    for (int i = 0; i < rxListSize; ++i) {
1343        int value;
1344        paramIn(cp, section, csprintf("rxList%d", i), value);
1345        rxList.push_back(value);
1346    }
1347
1348    int txListSize;
1349    UNSERIALIZE_SCALAR(txListSize);
1350    txList.clear();
1351    for (int i = 0; i < txListSize; ++i) {
1352        int value;
1353        paramIn(cp, section, csprintf("txList%d", i), value);
1354        txList.push_back(value);
1355    }
1356
1357    /*
1358     * Unserialize rx state machine
1359     */
1360    int rxState;
1361    UNSERIALIZE_SCALAR(rxState);
1362    UNSERIALIZE_SCALAR(rxEmpty);
1363    this->rxState = (RxState) rxState;
1364    rxFifo.unserialize("rxFifo", cp, section);
1365
1366    /*
1367     * Unserialize tx state machine
1368     */
1369    int txState;
1370    UNSERIALIZE_SCALAR(txState);
1371    UNSERIALIZE_SCALAR(txFull);
1372    this->txState = (TxState) txState;
1373    txFifo.unserialize("txFifo", cp, section);
1374    bool txPacketExists;
1375    UNSERIALIZE_SCALAR(txPacketExists);
1376    txPacket = 0;
1377    if (txPacketExists) {
1378        txPacket = new EthPacketData(16384);
1379        txPacket->unserialize("txPacket", cp, section);
1380        UNSERIALIZE_SCALAR(txPacketOffset);
1381        UNSERIALIZE_SCALAR(txPacketBytes);
1382    }
1383
1384    /*
1385     * unserialize the virtual nic registers/state
1386     *
1387     * this must be done after the unserialization of the rxFifo
1388     * because the packet iterators depend on the fifo being populated
1389     */
1390    int virtualRegsSize;
1391    UNSERIALIZE_SCALAR(virtualRegsSize);
1392    virtualRegs.clear();
1393    virtualRegs.resize(virtualRegsSize);
1394    for (int i = 0; i < virtualRegsSize; ++i) {
1395        VirtualReg *vnic = &virtualRegs[i];
1396        std::string reg = csprintf("vnic%d", i);
1397
1398        paramIn(cp, section, reg + ".RxData", vnic->RxData);
1399        paramIn(cp, section, reg + ".RxDone", vnic->RxDone);
1400        paramIn(cp, section, reg + ".TxData", vnic->TxData);
1401        paramIn(cp, section, reg + ".TxDone", vnic->TxDone);
1402
1403        bool rxPacketExists;
1404        paramIn(cp, section, reg + ".rxPacketExists", rxPacketExists);
1405        if (rxPacketExists) {
1406            int rxPacket;
1407            paramIn(cp, section, reg + ".rxPacket", rxPacket);
1408            vnic->rxPacket = rxFifo.begin();
1409            while (rxPacket--)
1410                ++vnic->rxPacket;
1411
1412            paramIn(cp, section, reg + ".rxPacketOffset",
1413                    vnic->rxPacketOffset);
1414            paramIn(cp, section, reg + ".rxPacketBytes", vnic->rxPacketBytes);
1415        } else {
1416            vnic->rxPacket = rxFifo.end();
1417        }
1418        paramIn(cp, section, reg + ".rxDoneData", vnic->rxDoneData);
1419    }
1420
1421    /*
1422     * If there's a pending transmit, reschedule it now
1423     */
1424    Tick transmitTick;
1425    UNSERIALIZE_SCALAR(transmitTick);
1426    if (transmitTick)
1427        txEvent.schedule(curTick + transmitTick);
1428
1429    pioPort->sendStatusChange(Port::RangeChange);
1430
1431}
1432
1433
1434BEGIN_DECLARE_SIM_OBJECT_PARAMS(Interface)
1435
1436    SimObjectParam<EtherInt *> peer;
1437    SimObjectParam<Device *> device;
1438
1439END_DECLARE_SIM_OBJECT_PARAMS(Interface)
1440
1441BEGIN_INIT_SIM_OBJECT_PARAMS(Interface)
1442
1443    INIT_PARAM_DFLT(peer, "peer interface", NULL),
1444    INIT_PARAM(device, "Ethernet device of this interface")
1445
1446END_INIT_SIM_OBJECT_PARAMS(Interface)
1447
1448CREATE_SIM_OBJECT(Interface)
1449{
1450    Interface *dev_int = new Interface(getInstanceName(), device);
1451
1452    EtherInt *p = (EtherInt *)peer;
1453    if (p) {
1454        dev_int->setPeer(p);
1455        p->setPeer(dev_int);
1456    }
1457
1458    return dev_int;
1459}
1460
1461REGISTER_SIM_OBJECT("SinicInt", Interface)
1462
1463
1464BEGIN_DECLARE_SIM_OBJECT_PARAMS(Device)
1465
1466
1467    SimObjectParam<System *> system;
1468    SimObjectParam<Platform *> platform;
1469    SimObjectParam<PciConfigAll *> configspace;
1470    SimObjectParam<PciConfigData *> configdata;
1471    Param<uint32_t> pci_bus;
1472    Param<uint32_t> pci_dev;
1473    Param<uint32_t> pci_func;
1474    Param<Tick> pio_latency;
1475    Param<Tick> intr_delay;
1476
1477    Param<Tick> clock;
1478    Param<Tick> dma_read_delay;
1479    Param<Tick> dma_read_factor;
1480    Param<Tick> dma_write_delay;
1481    Param<Tick> dma_write_factor;
1482
1483    Param<Tick> rx_delay;
1484    Param<Tick> tx_delay;
1485    Param<uint32_t> rx_max_copy;
1486    Param<uint32_t> tx_max_copy;
1487    Param<uint32_t> rx_max_intr;
1488    Param<uint32_t> rx_fifo_size;
1489    Param<uint32_t> tx_fifo_size;
1490    Param<uint32_t> rx_fifo_threshold;
1491    Param<uint32_t> tx_fifo_threshold;
1492
1493    Param<bool> rx_filter;
1494    Param<std::string> hardware_address;
1495    Param<bool> rx_thread;
1496    Param<bool> tx_thread;
1497    Param<bool> rss;
1498
1499END_DECLARE_SIM_OBJECT_PARAMS(Device)
1500
1501BEGIN_INIT_SIM_OBJECT_PARAMS(Device)
1502
1503
1504    INIT_PARAM(system, "System pointer"),
1505    INIT_PARAM(platform, "Platform pointer"),
1506    INIT_PARAM(configspace, "PCI Configspace"),
1507    INIT_PARAM(configdata, "PCI Config data"),
1508    INIT_PARAM(pci_bus, "PCI bus ID"),
1509    INIT_PARAM(pci_dev, "PCI device number"),
1510    INIT_PARAM(pci_func, "PCI function code"),
1511    INIT_PARAM_DFLT(pio_latency, "Programmed IO latency in bus cycles", 1),
1512    INIT_PARAM(intr_delay, "Interrupt Delay"),
1513    INIT_PARAM(clock, "State machine cycle time"),
1514
1515    INIT_PARAM(dma_read_delay, "fixed delay for dma reads"),
1516    INIT_PARAM(dma_read_factor, "multiplier for dma reads"),
1517    INIT_PARAM(dma_write_delay, "fixed delay for dma writes"),
1518    INIT_PARAM(dma_write_factor, "multiplier for dma writes"),
1519
1520    INIT_PARAM(rx_delay, "Receive Delay"),
1521    INIT_PARAM(tx_delay, "Transmit Delay"),
1522    INIT_PARAM(rx_max_copy, "rx max copy"),
1523    INIT_PARAM(tx_max_copy, "rx max copy"),
1524    INIT_PARAM(rx_max_intr, "rx max intr"),
1525    INIT_PARAM(rx_fifo_size, "max size in bytes of rxFifo"),
1526    INIT_PARAM(tx_fifo_size, "max size in bytes of txFifo"),
1527    INIT_PARAM(rx_fifo_threshold, "max size in bytes of rxFifo"),
1528    INIT_PARAM(tx_fifo_threshold, "max size in bytes of txFifo"),
1529
1530    INIT_PARAM(rx_filter, "Enable Receive Filter"),
1531    INIT_PARAM(hardware_address, "Ethernet Hardware Address"),
1532    INIT_PARAM(rx_thread, ""),
1533    INIT_PARAM(tx_thread, ""),
1534    INIT_PARAM(rss, "")
1535
1536END_INIT_SIM_OBJECT_PARAMS(Device)
1537
1538
1539CREATE_SIM_OBJECT(Device)
1540{
1541    Device::Params *params = new Device::Params;
1542    params->name = getInstanceName();
1543    params->platform = platform;
1544    params->system = system;
1545    params->configSpace = configspace;
1546    params->configData = configdata;
1547    params->busNum = pci_bus;
1548    params->deviceNum = pci_dev;
1549    params->functionNum = pci_func;
1550    params->pio_delay = pio_latency;
1551    params->intr_delay = intr_delay;
1552    params->clock = clock;
1553
1554    params->dma_read_delay = dma_read_delay;
1555    params->dma_read_factor = dma_read_factor;
1556    params->dma_write_delay = dma_write_delay;
1557    params->dma_write_factor = dma_write_factor;
1558
1559    params->tx_delay = tx_delay;
1560    params->rx_delay = rx_delay;
1561    params->rx_max_copy = rx_max_copy;
1562    params->tx_max_copy = tx_max_copy;
1563    params->rx_max_intr = rx_max_intr;
1564    params->rx_fifo_size = rx_fifo_size;
1565    params->tx_fifo_size = tx_fifo_size;
1566    params->rx_fifo_threshold = rx_fifo_threshold;
1567    params->tx_fifo_threshold = tx_fifo_threshold;
1568
1569    params->rx_filter = rx_filter;
1570    params->eaddr = hardware_address;
1571    params->rx_thread = rx_thread;
1572    params->tx_thread = tx_thread;
1573    params->rss = rss;
1574
1575    return new Device(params);
1576}
1577
1578REGISTER_SIM_OBJECT("Sinic", Device)
1579
1580/* namespace Sinic */ }
1581