sinic.cc revision 4762
16166Ssteve.reinhardt@amd.com/*
26166Ssteve.reinhardt@amd.com * Copyright (c) 2004-2005 The Regents of The University of Michigan
36166Ssteve.reinhardt@amd.com * All rights reserved.
46166Ssteve.reinhardt@amd.com *
56166Ssteve.reinhardt@amd.com * Redistribution and use in source and binary forms, with or without
66166Ssteve.reinhardt@amd.com * modification, are permitted provided that the following conditions are
76166Ssteve.reinhardt@amd.com * met: redistributions of source code must retain the above copyright
86166Ssteve.reinhardt@amd.com * notice, this list of conditions and the following disclaimer;
96166Ssteve.reinhardt@amd.com * redistributions in binary form must reproduce the above copyright
106166Ssteve.reinhardt@amd.com * notice, this list of conditions and the following disclaimer in the
116166Ssteve.reinhardt@amd.com * documentation and/or other materials provided with the distribution;
126166Ssteve.reinhardt@amd.com * neither the name of the copyright holders nor the names of its
136166Ssteve.reinhardt@amd.com * contributors may be used to endorse or promote products derived from
146166Ssteve.reinhardt@amd.com * this software without specific prior written permission.
156166Ssteve.reinhardt@amd.com *
166166Ssteve.reinhardt@amd.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
176166Ssteve.reinhardt@amd.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
186166Ssteve.reinhardt@amd.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
196166Ssteve.reinhardt@amd.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
206166Ssteve.reinhardt@amd.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
216166Ssteve.reinhardt@amd.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
226166Ssteve.reinhardt@amd.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
236166Ssteve.reinhardt@amd.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
246166Ssteve.reinhardt@amd.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
256166Ssteve.reinhardt@amd.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
266166Ssteve.reinhardt@amd.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
276166Ssteve.reinhardt@amd.com *
286166Ssteve.reinhardt@amd.com * Authors: Nathan Binkert
296166Ssteve.reinhardt@amd.com */
306166Ssteve.reinhardt@amd.com
316928SBrad.Beckmann@amd.com#include <deque>
326928SBrad.Beckmann@amd.com#include <limits>
336928SBrad.Beckmann@amd.com#include <string>
346928SBrad.Beckmann@amd.com
356928SBrad.Beckmann@amd.com#include "arch/vtophys.hh"
366928SBrad.Beckmann@amd.com#include "base/inet.hh"
376928SBrad.Beckmann@amd.com#include "cpu/thread_context.hh"
386928SBrad.Beckmann@amd.com#include "cpu/intr_control.hh"
396928SBrad.Beckmann@amd.com#include "dev/etherlink.hh"
406928SBrad.Beckmann@amd.com#include "dev/sinic.hh"
416928SBrad.Beckmann@amd.com#include "mem/packet.hh"
428920Snilay@cs.wisc.edu#include "mem/packet_access.hh"
436928SBrad.Beckmann@amd.com#include "sim/debug.hh"
446928SBrad.Beckmann@amd.com#include "sim/eventq.hh"
456928SBrad.Beckmann@amd.com#include "sim/host.hh"
468920Snilay@cs.wisc.edu#include "sim/stats.hh"
476928SBrad.Beckmann@amd.com
487570SBrad.Beckmann@amd.comusing namespace Net;
497570SBrad.Beckmann@amd.comusing namespace TheISA;
506928SBrad.Beckmann@amd.com
516928SBrad.Beckmann@amd.comnamespace Sinic {
526166Ssteve.reinhardt@amd.com
537570SBrad.Beckmann@amd.comconst char *RxStateStrings[] =
547570SBrad.Beckmann@amd.com{
557570SBrad.Beckmann@amd.com    "rxIdle",
567570SBrad.Beckmann@amd.com    "rxFifoBlock",
577570SBrad.Beckmann@amd.com    "rxBeginCopy",
587570SBrad.Beckmann@amd.com    "rxCopy",
597570SBrad.Beckmann@amd.com    "rxCopyDone"
607570SBrad.Beckmann@amd.com};
617570SBrad.Beckmann@amd.com
627570SBrad.Beckmann@amd.comconst char *TxStateStrings[] =
637570SBrad.Beckmann@amd.com{
647570SBrad.Beckmann@amd.com    "txIdle",
657570SBrad.Beckmann@amd.com    "txFifoBlock",
666166Ssteve.reinhardt@amd.com    "txBeginCopy",
676166Ssteve.reinhardt@amd.com    "txCopy",
686166Ssteve.reinhardt@amd.com    "txCopyDone"
696928SBrad.Beckmann@amd.com};
706928SBrad.Beckmann@amd.com
716289Snate@binkert.org
726166Ssteve.reinhardt@amd.com///////////////////////////////////////////////////////////////////////
738931Sandreas.hansson@arm.com//
746166Ssteve.reinhardt@amd.com// Sinic PCI Device
758436SBrad.Beckmann@amd.com//
766166Ssteve.reinhardt@amd.comBase::Base(Params *p)
778322Ssteve.reinhardt@amd.com    : PciDev(p), rxEnable(false), txEnable(false), clock(p->clock),
786166Ssteve.reinhardt@amd.com      intrDelay(p->intr_delay), intrTick(0), cpuIntrEnable(false),
796928SBrad.Beckmann@amd.com      cpuPendingIntr(false), intrEvent(0), interface(NULL)
809067Smarc.orr@gmail.com{
819067Smarc.orr@gmail.com}
829067Smarc.orr@gmail.com
836928SBrad.Beckmann@amd.comDevice::Device(Params *p)
846928SBrad.Beckmann@amd.com    : Base(p), rxUnique(0), txUnique(0),
856928SBrad.Beckmann@amd.com      virtualRegs(p->virtual_count < 1 ? 1 : p->virtual_count),
869067Smarc.orr@gmail.com      rxFifo(p->rx_fifo_size), txFifo(p->tx_fifo_size),
876166Ssteve.reinhardt@amd.com      rxKickTick(0), txKickTick(0),
886166Ssteve.reinhardt@amd.com      txEvent(this), rxDmaEvent(this), txDmaEvent(this),
896166Ssteve.reinhardt@amd.com      dmaReadDelay(p->dma_read_delay), dmaReadFactor(p->dma_read_factor),
906166Ssteve.reinhardt@amd.com      dmaWriteDelay(p->dma_write_delay), dmaWriteFactor(p->dma_write_factor)
916166Ssteve.reinhardt@amd.com{
928801Sgblack@eecs.umich.edu    reset();
936166Ssteve.reinhardt@amd.com
946928SBrad.Beckmann@amd.com}
956928SBrad.Beckmann@amd.com
966928SBrad.Beckmann@amd.comDevice::~Device()
97{}
98
99void
100Device::regStats()
101{
102    rxBytes
103        .name(name() + ".rxBytes")
104        .desc("Bytes Received")
105        .prereq(rxBytes)
106        ;
107
108    rxBandwidth
109        .name(name() + ".rxBandwidth")
110        .desc("Receive Bandwidth (bits/s)")
111        .precision(0)
112        .prereq(rxBytes)
113        ;
114
115    rxPackets
116        .name(name() + ".rxPackets")
117        .desc("Number of Packets Received")
118        .prereq(rxBytes)
119        ;
120
121    rxPacketRate
122        .name(name() + ".rxPPS")
123        .desc("Packet Reception Rate (packets/s)")
124        .precision(0)
125        .prereq(rxBytes)
126        ;
127
128    rxIpPackets
129        .name(name() + ".rxIpPackets")
130        .desc("Number of IP Packets Received")
131        .prereq(rxBytes)
132        ;
133
134    rxTcpPackets
135        .name(name() + ".rxTcpPackets")
136        .desc("Number of Packets Received")
137        .prereq(rxBytes)
138        ;
139
140    rxUdpPackets
141        .name(name() + ".rxUdpPackets")
142        .desc("Number of UDP Packets Received")
143        .prereq(rxBytes)
144        ;
145
146    rxIpChecksums
147        .name(name() + ".rxIpChecksums")
148        .desc("Number of rx IP Checksums done by device")
149        .precision(0)
150        .prereq(rxBytes)
151        ;
152
153    rxTcpChecksums
154        .name(name() + ".rxTcpChecksums")
155        .desc("Number of rx TCP Checksums done by device")
156        .precision(0)
157        .prereq(rxBytes)
158        ;
159
160    rxUdpChecksums
161        .name(name() + ".rxUdpChecksums")
162        .desc("Number of rx UDP Checksums done by device")
163        .precision(0)
164        .prereq(rxBytes)
165        ;
166
167    totBandwidth
168        .name(name() + ".totBandwidth")
169        .desc("Total Bandwidth (bits/s)")
170        .precision(0)
171        .prereq(totBytes)
172        ;
173
174    totPackets
175        .name(name() + ".totPackets")
176        .desc("Total Packets")
177        .precision(0)
178        .prereq(totBytes)
179        ;
180
181    totBytes
182        .name(name() + ".totBytes")
183        .desc("Total Bytes")
184        .precision(0)
185        .prereq(totBytes)
186        ;
187
188    totPacketRate
189        .name(name() + ".totPPS")
190        .desc("Total Tranmission Rate (packets/s)")
191        .precision(0)
192        .prereq(totBytes)
193        ;
194
195    txBytes
196        .name(name() + ".txBytes")
197        .desc("Bytes Transmitted")
198        .prereq(txBytes)
199        ;
200
201    txBandwidth
202        .name(name() + ".txBandwidth")
203        .desc("Transmit Bandwidth (bits/s)")
204        .precision(0)
205        .prereq(txBytes)
206        ;
207
208    txPackets
209        .name(name() + ".txPackets")
210        .desc("Number of Packets Transmitted")
211        .prereq(txBytes)
212        ;
213
214    txPacketRate
215        .name(name() + ".txPPS")
216        .desc("Packet Tranmission Rate (packets/s)")
217        .precision(0)
218        .prereq(txBytes)
219        ;
220
221    txIpPackets
222        .name(name() + ".txIpPackets")
223        .desc("Number of IP Packets Transmitted")
224        .prereq(txBytes)
225        ;
226
227    txTcpPackets
228        .name(name() + ".txTcpPackets")
229        .desc("Number of TCP Packets Transmitted")
230        .prereq(txBytes)
231        ;
232
233    txUdpPackets
234        .name(name() + ".txUdpPackets")
235        .desc("Number of Packets Transmitted")
236        .prereq(txBytes)
237        ;
238
239    txIpChecksums
240        .name(name() + ".txIpChecksums")
241        .desc("Number of tx IP Checksums done by device")
242        .precision(0)
243        .prereq(txBytes)
244        ;
245
246    txTcpChecksums
247        .name(name() + ".txTcpChecksums")
248        .desc("Number of tx TCP Checksums done by device")
249        .precision(0)
250        .prereq(txBytes)
251        ;
252
253    txUdpChecksums
254        .name(name() + ".txUdpChecksums")
255        .desc("Number of tx UDP Checksums done by device")
256        .precision(0)
257        .prereq(txBytes)
258        ;
259
260    txBandwidth = txBytes * Stats::constant(8) / simSeconds;
261    rxBandwidth = rxBytes * Stats::constant(8) / simSeconds;
262    totBandwidth = txBandwidth + rxBandwidth;
263    totBytes = txBytes + rxBytes;
264    totPackets = txPackets + rxPackets;
265    txPacketRate = txPackets / simSeconds;
266    rxPacketRate = rxPackets / simSeconds;
267}
268
269void
270Device::prepareIO(int cpu, int index)
271{
272    int size = virtualRegs.size();
273    if (index > size)
274        panic("Trying to access a vnic that doesn't exist %d > %d\n",
275              index, size);
276}
277
278void
279Device::prepareRead(int cpu, int index)
280{
281    using namespace Regs;
282    prepareIO(cpu, index);
283
284    VirtualReg &vnic = virtualRegs[index];
285
286    // update rx registers
287    uint64_t rxdone = vnic.RxDone;
288    rxdone = set_RxDone_Packets(rxdone, rxFifo.countPacketsAfter(rxFifoPtr));
289    rxdone = set_RxDone_Empty(rxdone, rxFifo.empty());
290    rxdone = set_RxDone_High(rxdone, rxFifo.size() > regs.RxFifoMark);
291    rxdone = set_RxDone_NotHigh(rxdone, rxLow);
292    regs.RxData = vnic.RxData;
293    regs.RxDone = rxdone;
294    regs.RxWait = rxdone;
295
296    // update tx regsiters
297    uint64_t txdone = vnic.TxDone;
298    txdone = set_TxDone_Packets(txdone, txFifo.packets());
299    txdone = set_TxDone_Full(txdone, txFifo.avail() < regs.TxMaxCopy);
300    txdone = set_TxDone_Low(txdone, txFifo.size() < regs.TxFifoMark);
301    regs.TxData = vnic.TxData;
302    regs.TxDone = txdone;
303    regs.TxWait = txdone;
304}
305
306void
307Device::prepareWrite(int cpu, int index)
308{
309    prepareIO(cpu, index);
310}
311
312/**
313 * I/O read of device register
314 */
315Tick
316Device::read(PacketPtr pkt)
317{
318    assert(config.command & PCI_CMD_MSE);
319    assert(pkt->getAddr() >= BARAddrs[0] && pkt->getSize() < BARSize[0]);
320
321    int cpu = pkt->req->getCpuNum();
322    Addr daddr = pkt->getAddr() - BARAddrs[0];
323    Addr index = daddr >> Regs::VirtualShift;
324    Addr raddr = daddr & Regs::VirtualMask;
325
326    pkt->allocate();
327
328    if (!regValid(raddr))
329        panic("invalid register: cpu=%d vnic=%d da=%#x pa=%#x size=%d",
330              cpu, index, daddr, pkt->getAddr(), pkt->getSize());
331
332    const Regs::Info &info = regInfo(raddr);
333    if (!info.read)
334        panic("read %s (write only): "
335              "cpu=%d vnic=%d da=%#x pa=%#x size=%d",
336              info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize());
337
338        panic("read %s (invalid size): "
339              "cpu=%d vnic=%d da=%#x pa=%#x size=%d",
340              info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize());
341
342    prepareRead(cpu, index);
343
344    uint64_t value = 0;
345    if (pkt->getSize() == 4) {
346        uint32_t reg = regData32(raddr);
347        pkt->set(reg);
348        value = reg;
349    }
350
351    if (pkt->getSize() == 8) {
352        uint64_t reg = regData64(raddr);
353        pkt->set(reg);
354        value = reg;
355    }
356
357    DPRINTF(EthernetPIO,
358            "read %s: cpu=%d vnic=%d da=%#x pa=%#x size=%d val=%#x\n",
359            info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize(), value);
360
361    // reading the interrupt status register has the side effect of
362    // clearing it
363    if (raddr == Regs::IntrStatus)
364        devIntrClear();
365
366    return pioDelay;
367}
368
369/**
370 * IPR read of device register
371
372    Fault
373Device::iprRead(Addr daddr, int cpu, uint64_t &result)
374{
375    if (!regValid(daddr))
376        panic("invalid address: da=%#x", daddr);
377
378    const Regs::Info &info = regInfo(daddr);
379    if (!info.read)
380        panic("reading %s (write only): cpu=%d da=%#x", info.name, cpu, daddr);
381
382    DPRINTF(EthernetPIO, "IPR read %s: cpu=%d da=%#x\n",
383            info.name, cpu, daddr);
384
385    prepareRead(cpu, 0);
386
387    if (info.size == 4)
388        result = regData32(daddr);
389
390    if (info.size == 8)
391        result = regData64(daddr);
392
393    DPRINTF(EthernetPIO, "IPR read %s: cpu=%s da=%#x val=%#x\n",
394            info.name, cpu, result);
395
396    return NoFault;
397}
398*/
399/**
400 * I/O write of device register
401 */
402Tick
403Device::write(PacketPtr pkt)
404{
405    assert(config.command & PCI_CMD_MSE);
406    assert(pkt->getAddr() >= BARAddrs[0] && pkt->getSize() < BARSize[0]);
407
408    int cpu = pkt->req->getCpuNum();
409    Addr daddr = pkt->getAddr() - BARAddrs[0];
410    Addr index = daddr >> Regs::VirtualShift;
411    Addr raddr = daddr & Regs::VirtualMask;
412
413    if (!regValid(raddr))
414        panic("invalid register: cpu=%d, da=%#x pa=%#x size=%d",
415                cpu, daddr, pkt->getAddr(), pkt->getSize());
416
417    const Regs::Info &info = regInfo(raddr);
418    if (!info.write)
419        panic("write %s (read only): "
420              "cpu=%d vnic=%d da=%#x pa=%#x size=%d",
421              info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize());
422
423    if (pkt->getSize() != info.size)
424        panic("write %s (invalid size): "
425              "cpu=%d vnic=%d da=%#x pa=%#x size=%d",
426              info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize());
427
428    VirtualReg &vnic = virtualRegs[index];
429
430    DPRINTF(EthernetPIO,
431            "write %s vnic %d: cpu=%d val=%#x da=%#x pa=%#x size=%d\n",
432            info.name, index, cpu, info.size == 4 ? pkt->get<uint32_t>() :
433            pkt->get<uint64_t>(), daddr, pkt->getAddr(), pkt->getSize());
434
435    prepareWrite(cpu, index);
436
437    switch (raddr) {
438      case Regs::Config:
439        changeConfig(pkt->get<uint32_t>());
440        break;
441
442      case Regs::Command:
443        command(pkt->get<uint32_t>());
444        break;
445
446      case Regs::IntrStatus:
447        devIntrClear(regs.IntrStatus & pkt->get<uint32_t>());
448        break;
449
450      case Regs::IntrMask:
451        devIntrChangeMask(pkt->get<uint32_t>());
452        break;
453
454      case Regs::RxData:
455        if (Regs::get_RxDone_Busy(vnic.RxDone))
456            panic("receive machine busy with another request! rxState=%s",
457                  RxStateStrings[rxState]);
458
459        vnic.rxUnique = rxUnique++;
460        vnic.RxDone = Regs::RxDone_Busy;
461        vnic.RxData = pkt->get<uint64_t>();
462
463        if (Regs::get_RxData_Vaddr(pkt->get<uint64_t>())) {
464            panic("vtophys not implemented in newmem");
465/*            Addr vaddr = Regs::get_RxData_Addr(reg64);
466            Addr paddr = vtophys(req->xc, vaddr);
467            DPRINTF(EthernetPIO, "write RxData vnic %d (rxunique %d): "
468                    "vaddr=%#x, paddr=%#x\n",
469                    index, vnic.rxUnique, vaddr, paddr);
470
471            vnic.RxData = Regs::set_RxData_Addr(vnic.RxData, paddr);*/
472        } else {
473            DPRINTF(EthernetPIO, "write RxData vnic %d (rxunique %d)\n",
474                    index, vnic.rxUnique);
475        }
476
477        if (vnic.rxPacket == rxFifo.end()) {
478            DPRINTF(EthernetPIO, "request new packet...appending to rxList\n");
479            rxList.push_back(index);
480        } else {
481            DPRINTF(EthernetPIO, "packet exists...appending to rxBusy\n");
482            rxBusy.push_back(index);
483        }
484
485        if (rxEnable && (rxState == rxIdle || rxState == rxFifoBlock)) {
486            rxState = rxFifoBlock;
487            rxKick();
488        }
489        break;
490
491      case Regs::TxData:
492        if (Regs::get_TxDone_Busy(vnic.TxDone))
493            panic("transmit machine busy with another request! txState=%s",
494                  TxStateStrings[txState]);
495
496        vnic.txUnique = txUnique++;
497        vnic.TxDone = Regs::TxDone_Busy;
498
499        if (Regs::get_TxData_Vaddr(pkt->get<uint64_t>())) {
500            panic("vtophys won't work here in newmem.\n");
501            /*Addr vaddr = Regs::get_TxData_Addr(reg64);
502            Addr paddr = vtophys(req->xc, vaddr);
503            DPRINTF(EthernetPIO, "write TxData vnic %d (rxunique %d): "
504                    "vaddr=%#x, paddr=%#x\n",
505                    index, vnic.txUnique, vaddr, paddr);
506
507            vnic.TxData = Regs::set_TxData_Addr(vnic.TxData, paddr);*/
508        } else {
509            DPRINTF(EthernetPIO, "write TxData vnic %d (rxunique %d)\n",
510                    index, vnic.txUnique);
511        }
512
513        if (txList.empty() || txList.front() != index)
514            txList.push_back(index);
515        if (txEnable && txState == txIdle && txList.front() == index) {
516            txState = txFifoBlock;
517            txKick();
518        }
519        break;
520    }
521
522    return pioDelay;
523}
524
525void
526Device::devIntrPost(uint32_t interrupts)
527{
528    if ((interrupts & Regs::Intr_Res))
529        panic("Cannot set a reserved interrupt");
530
531    regs.IntrStatus |= interrupts;
532
533    DPRINTF(EthernetIntr,
534            "interrupt written to intStatus: intr=%#x status=%#x mask=%#x\n",
535            interrupts, regs.IntrStatus, regs.IntrMask);
536
537    interrupts = regs.IntrStatus & regs.IntrMask;
538
539    // Intr_RxHigh is special, we only signal it if we've emptied the fifo
540    // and then filled it above the high watermark
541    if (rxEmpty)
542        rxEmpty = false;
543    else
544        interrupts &= ~Regs::Intr_RxHigh;
545
546    // Intr_TxLow is special, we only signal it if we've filled up the fifo
547    // and then dropped below the low watermark
548    if (txFull)
549        txFull = false;
550    else
551        interrupts &= ~Regs::Intr_TxLow;
552
553    if (interrupts) {
554        Tick when = curTick;
555        if ((interrupts & Regs::Intr_NoDelay) == 0)
556            when += intrDelay;
557        cpuIntrPost(when);
558    }
559}
560
561void
562Device::devIntrClear(uint32_t interrupts)
563{
564    if ((interrupts & Regs::Intr_Res))
565        panic("Cannot clear a reserved interrupt");
566
567    regs.IntrStatus &= ~interrupts;
568
569    DPRINTF(EthernetIntr,
570            "interrupt cleared from intStatus: intr=%x status=%x mask=%x\n",
571            interrupts, regs.IntrStatus, regs.IntrMask);
572
573    if (!(regs.IntrStatus & regs.IntrMask))
574        cpuIntrClear();
575}
576
577void
578Device::devIntrChangeMask(uint32_t newmask)
579{
580    if (regs.IntrMask == newmask)
581        return;
582
583    regs.IntrMask = newmask;
584
585    DPRINTF(EthernetIntr,
586            "interrupt mask changed: intStatus=%x intMask=%x masked=%x\n",
587            regs.IntrStatus, regs.IntrMask, regs.IntrStatus & regs.IntrMask);
588
589    if (regs.IntrStatus & regs.IntrMask)
590        cpuIntrPost(curTick);
591    else
592        cpuIntrClear();
593}
594
595void
596Base::cpuIntrPost(Tick when)
597{
598    // If the interrupt you want to post is later than an interrupt
599    // already scheduled, just let it post in the coming one and don't
600    // schedule another.
601    // HOWEVER, must be sure that the scheduled intrTick is in the
602    // future (this was formerly the source of a bug)
603    /**
604     * @todo this warning should be removed and the intrTick code should
605     * be fixed.
606     */
607    assert(when >= curTick);
608    assert(intrTick >= curTick || intrTick == 0);
609    if (!cpuIntrEnable) {
610        DPRINTF(EthernetIntr, "interrupts not enabled.\n",
611                intrTick);
612        return;
613    }
614
615    if (when > intrTick && intrTick != 0) {
616        DPRINTF(EthernetIntr, "don't need to schedule event...intrTick=%d\n",
617                intrTick);
618        return;
619    }
620
621    intrTick = when;
622    if (intrTick < curTick) {
623        debug_break();
624        intrTick = curTick;
625    }
626
627    DPRINTF(EthernetIntr, "going to schedule an interrupt for intrTick=%d\n",
628            intrTick);
629
630    if (intrEvent)
631        intrEvent->squash();
632    intrEvent = new IntrEvent(this, intrTick, true);
633}
634
635void
636Base::cpuInterrupt()
637{
638    assert(intrTick == curTick);
639
640    // Whether or not there's a pending interrupt, we don't care about
641    // it anymore
642    intrEvent = 0;
643    intrTick = 0;
644
645    // Don't send an interrupt if there's already one
646    if (cpuPendingIntr) {
647        DPRINTF(EthernetIntr,
648                "would send an interrupt now, but there's already pending\n");
649    } else {
650        // Send interrupt
651        cpuPendingIntr = true;
652
653        DPRINTF(EthernetIntr, "posting interrupt\n");
654        intrPost();
655    }
656}
657
658void
659Base::cpuIntrClear()
660{
661    if (!cpuPendingIntr)
662        return;
663
664    if (intrEvent) {
665        intrEvent->squash();
666        intrEvent = 0;
667    }
668
669    intrTick = 0;
670
671    cpuPendingIntr = false;
672
673    DPRINTF(EthernetIntr, "clearing cchip interrupt\n");
674    intrClear();
675}
676
677bool
678Base::cpuIntrPending() const
679{ return cpuPendingIntr; }
680
681void
682Device::changeConfig(uint32_t newconf)
683{
684    uint32_t changed = regs.Config ^ newconf;
685    if (!changed)
686        return;
687
688    regs.Config = newconf;
689
690    if ((changed & Regs::Config_IntEn)) {
691        cpuIntrEnable = regs.Config & Regs::Config_IntEn;
692        if (cpuIntrEnable) {
693            if (regs.IntrStatus & regs.IntrMask)
694                cpuIntrPost(curTick);
695        } else {
696            cpuIntrClear();
697        }
698    }
699
700    if ((changed & Regs::Config_TxEn)) {
701        txEnable = regs.Config & Regs::Config_TxEn;
702        if (txEnable)
703            txKick();
704    }
705
706    if ((changed & Regs::Config_RxEn)) {
707        rxEnable = regs.Config & Regs::Config_RxEn;
708        if (rxEnable)
709            rxKick();
710    }
711}
712
713void
714Device::command(uint32_t command)
715{
716    if (command & Regs::Command_Intr)
717        devIntrPost(Regs::Intr_Soft);
718
719    if (command & Regs::Command_Reset)
720        reset();
721}
722
723void
724Device::reset()
725{
726    using namespace Regs;
727
728    memset(&regs, 0, sizeof(regs));
729
730    regs.Config = 0;
731    if (params()->rx_thread)
732        regs.Config |= Config_RxThread;
733    if (params()->tx_thread)
734        regs.Config |= Config_TxThread;
735    if (params()->rss)
736        regs.Config |= Config_RSS;
737    if (params()->zero_copy)
738        regs.Config |= Config_ZeroCopy;
739    if (params()->delay_copy)
740        regs.Config |= Config_DelayCopy;
741    if (params()->virtual_addr)
742        regs.Config |= Config_Vaddr;
743
744    if (params()->delay_copy && params()->zero_copy)
745        panic("Can't delay copy and zero copy");
746
747    regs.IntrMask = Intr_Soft | Intr_RxHigh | Intr_RxPacket | Intr_TxLow;
748    regs.RxMaxCopy = params()->rx_max_copy;
749    regs.TxMaxCopy = params()->tx_max_copy;
750    regs.RxMaxIntr = params()->rx_max_intr;
751    regs.VirtualCount = params()->virtual_count;
752    regs.RxFifoSize = params()->rx_fifo_size;
753    regs.TxFifoSize = params()->tx_fifo_size;
754    regs.RxFifoMark = params()->rx_fifo_threshold;
755    regs.TxFifoMark = params()->tx_fifo_threshold;
756    regs.HwAddr = params()->hardware_address;
757
758    rxList.clear();
759    rxBusy.clear();
760    rxActive = -1;
761    txList.clear();
762
763    rxState = rxIdle;
764    txState = txIdle;
765
766    rxFifo.clear();
767    rxFifoPtr = rxFifo.end();
768    txFifo.clear();
769    rxEmpty = false;
770    rxLow = true;
771    txFull = false;
772
773    int size = virtualRegs.size();
774    virtualRegs.clear();
775    virtualRegs.resize(size);
776    for (int i = 0; i < size; ++i)
777        virtualRegs[i].rxPacket = rxFifo.end();
778}
779
780void
781Device::rxDmaDone()
782{
783    assert(rxState == rxCopy);
784    rxState = rxCopyDone;
785    DPRINTF(EthernetDMA, "end rx dma write paddr=%#x len=%d\n",
786            rxDmaAddr, rxDmaLen);
787    DDUMP(EthernetData, rxDmaData, rxDmaLen);
788
789    // If the transmit state machine  has a pending DMA, let it go first
790    if (txState == txBeginCopy)
791        txKick();
792
793    rxKick();
794}
795
796void
797Device::rxKick()
798{
799    VirtualReg *vnic = NULL;
800
801    DPRINTF(EthernetSM, "rxKick: rxState=%s (rxFifo.size=%d)\n",
802            RxStateStrings[rxState], rxFifo.size());
803
804    if (rxKickTick > curTick) {
805        DPRINTF(EthernetSM, "rxKick: exiting, can't run till %d\n",
806                rxKickTick);
807        return;
808    }
809
810  next:
811    if (rxState == rxIdle)
812        goto exit;
813
814    if (rxActive == -1) {
815        if (rxState != rxFifoBlock)
816            panic("no active vnic while in state %s", RxStateStrings[rxState]);
817
818        DPRINTF(EthernetSM, "processing rxState=%s\n",
819                RxStateStrings[rxState]);
820    } else {
821        vnic = &virtualRegs[rxActive];
822        DPRINTF(EthernetSM,
823                "processing rxState=%s for vnic %d (rxunique %d)\n",
824                RxStateStrings[rxState], rxActive, vnic->rxUnique);
825    }
826
827    switch (rxState) {
828      case rxFifoBlock:
829        if (DTRACE(EthernetSM)) {
830            PacketFifo::iterator end = rxFifo.end();
831            int size = virtualRegs.size();
832            for (int i = 0; i < size; ++i) {
833                VirtualReg *vn = &virtualRegs[i];
834                if (vn->rxPacket != end &&
835                    !Regs::get_RxDone_Busy(vn->RxDone)) {
836                    DPRINTF(EthernetSM,
837                            "vnic %d (rxunique %d), has outstanding packet %d\n",
838                            i, vn->rxUnique,
839                            rxFifo.countPacketsBefore(vn->rxPacket));
840                }
841            }
842        }
843
844        if (!rxBusy.empty()) {
845            rxActive = rxBusy.front();
846            rxBusy.pop_front();
847            vnic = &virtualRegs[rxActive];
848
849            if (vnic->rxPacket == rxFifo.end())
850                panic("continuing vnic without packet\n");
851
852            DPRINTF(EthernetSM,
853                    "continue processing for vnic %d (rxunique %d)\n",
854                    rxActive, vnic->rxUnique);
855
856            rxState = rxBeginCopy;
857
858            break;
859        }
860
861        if (rxFifoPtr == rxFifo.end()) {
862            DPRINTF(EthernetSM, "receive waiting for data.  Nothing to do.\n");
863            goto exit;
864        }
865
866        if (rxList.empty())
867            panic("Not idle, but nothing to do!");
868
869        assert(!rxFifo.empty());
870
871        rxActive = rxList.front();
872        rxList.pop_front();
873        vnic = &virtualRegs[rxActive];
874
875        DPRINTF(EthernetSM,
876                "processing new packet for vnic %d (rxunique %d)\n",
877                rxActive, vnic->rxUnique);
878
879        // Grab a new packet from the fifo.
880        vnic->rxPacket = rxFifoPtr++;
881        vnic->rxPacketOffset = 0;
882        vnic->rxPacketBytes = (*vnic->rxPacket)->length;
883        assert(vnic->rxPacketBytes);
884
885        vnic->rxDoneData = 0;
886        /* scope for variables */ {
887            IpPtr ip(*vnic->rxPacket);
888            if (ip) {
889                DPRINTF(Ethernet, "ID is %d\n", ip->id());
890                vnic->rxDoneData |= Regs::RxDone_IpPacket;
891                rxIpChecksums++;
892                if (cksum(ip) != 0) {
893                    DPRINTF(EthernetCksum, "Rx IP Checksum Error\n");
894                    vnic->rxDoneData |= Regs::RxDone_IpError;
895                }
896                TcpPtr tcp(ip);
897                UdpPtr udp(ip);
898                if (tcp) {
899                    DPRINTF(Ethernet,
900                            "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n",
901                            tcp->sport(), tcp->dport(), tcp->seq(),
902                            tcp->ack());
903                    vnic->rxDoneData |= Regs::RxDone_TcpPacket;
904                    rxTcpChecksums++;
905                    if (cksum(tcp) != 0) {
906                        DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n");
907                        vnic->rxDoneData |= Regs::RxDone_TcpError;
908                    }
909                } else if (udp) {
910                    vnic->rxDoneData |= Regs::RxDone_UdpPacket;
911                    rxUdpChecksums++;
912                    if (cksum(udp) != 0) {
913                        DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n");
914                        vnic->rxDoneData |= Regs::RxDone_UdpError;
915                    }
916                }
917            }
918        }
919        rxState = rxBeginCopy;
920        break;
921
922      case rxBeginCopy:
923        if (dmaPending() || getState() != Running)
924            goto exit;
925
926        rxDmaAddr = params()->platform->pciToDma(
927                Regs::get_RxData_Addr(vnic->RxData));
928        rxDmaLen = std::min<int>(Regs::get_RxData_Len(vnic->RxData),
929                            vnic->rxPacketBytes);
930        rxDmaData = (*vnic->rxPacket)->data + vnic->rxPacketOffset;
931        rxState = rxCopy;
932        if (rxDmaAddr == 1LL) {
933            rxState = rxCopyDone;
934            break;
935        }
936
937
938        dmaWrite(rxDmaAddr, rxDmaLen, &rxDmaEvent, rxDmaData);
939        break;
940
941      case rxCopy:
942        DPRINTF(EthernetSM, "receive machine still copying\n");
943        goto exit;
944
945      case rxCopyDone:
946        vnic->RxDone = vnic->rxDoneData;
947        vnic->RxDone |= Regs::RxDone_Complete;
948
949        if (vnic->rxPacketBytes == rxDmaLen) {
950            // Packet is complete.  Indicate how many bytes were copied
951            vnic->RxDone = Regs::set_RxDone_CopyLen(vnic->RxDone, rxDmaLen);
952
953            DPRINTF(EthernetSM,
954                    "rxKick: packet complete on vnic %d (rxunique %d)\n",
955                    rxActive, vnic->rxUnique);
956            rxFifo.remove(vnic->rxPacket);
957            vnic->rxPacket = rxFifo.end();
958        } else {
959            vnic->rxPacketBytes -= rxDmaLen;
960            vnic->rxPacketOffset += rxDmaLen;
961            vnic->RxDone |= Regs::RxDone_More;
962            vnic->RxDone = Regs::set_RxDone_CopyLen(vnic->RxDone,
963                                                    vnic->rxPacketBytes);
964            DPRINTF(EthernetSM,
965                    "rxKick: packet not complete on vnic %d (rxunique %d): "
966                    "%d bytes left\n",
967                    rxActive, vnic->rxUnique, vnic->rxPacketBytes);
968        }
969
970        rxActive = -1;
971        rxState = rxBusy.empty() && rxList.empty() ? rxIdle : rxFifoBlock;
972
973        if (rxFifo.empty()) {
974            devIntrPost(Regs::Intr_RxEmpty);
975            rxEmpty = true;
976        }
977
978        if (rxFifo.size() < params()->rx_fifo_low_mark)
979            rxLow = true;
980
981        if (rxFifo.size() > params()->rx_fifo_threshold)
982            rxLow = false;
983
984        devIntrPost(Regs::Intr_RxDMA);
985        break;
986
987      default:
988        panic("Invalid rxState!");
989    }
990
991    DPRINTF(EthernetSM, "entering next rxState=%s\n",
992            RxStateStrings[rxState]);
993
994    goto next;
995
996  exit:
997    /**
998     * @todo do we want to schedule a future kick?
999     */
1000    DPRINTF(EthernetSM, "rx state machine exited rxState=%s\n",
1001            RxStateStrings[rxState]);
1002}
1003
1004void
1005Device::txDmaDone()
1006{
1007    assert(txState == txCopy);
1008    txState = txCopyDone;
1009    DPRINTF(EthernetDMA, "tx dma read paddr=%#x len=%d\n",
1010            txDmaAddr, txDmaLen);
1011    DDUMP(EthernetData, txDmaData, txDmaLen);
1012
1013    // If the receive state machine  has a pending DMA, let it go first
1014    if (rxState == rxBeginCopy)
1015        rxKick();
1016
1017    txKick();
1018}
1019
1020void
1021Device::transmit()
1022{
1023    if (txFifo.empty()) {
1024        DPRINTF(Ethernet, "nothing to transmit\n");
1025        return;
1026    }
1027
1028    uint32_t interrupts;
1029    EthPacketPtr packet = txFifo.front();
1030    if (!interface->sendPacket(packet)) {
1031        DPRINTF(Ethernet, "Packet Transmit: failed txFifo available %d\n",
1032                txFifo.avail());
1033        goto reschedule;
1034    }
1035
1036    txFifo.pop();
1037#if TRACING_ON
1038    if (DTRACE(Ethernet)) {
1039        IpPtr ip(packet);
1040        if (ip) {
1041            DPRINTF(Ethernet, "ID is %d\n", ip->id());
1042            TcpPtr tcp(ip);
1043            if (tcp) {
1044                DPRINTF(Ethernet,
1045                        "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n",
1046                        tcp->sport(), tcp->dport(), tcp->seq(),
1047                        tcp->ack());
1048            }
1049        }
1050    }
1051#endif
1052
1053    DDUMP(EthernetData, packet->data, packet->length);
1054    txBytes += packet->length;
1055    txPackets++;
1056
1057    DPRINTF(Ethernet, "Packet Transmit: successful txFifo Available %d\n",
1058            txFifo.avail());
1059
1060    interrupts = Regs::Intr_TxPacket;
1061    if (txFifo.size() < regs.TxFifoMark)
1062        interrupts |= Regs::Intr_TxLow;
1063    devIntrPost(interrupts);
1064
1065  reschedule:
1066   if (!txFifo.empty() && !txEvent.scheduled()) {
1067       DPRINTF(Ethernet, "reschedule transmit\n");
1068       txEvent.schedule(curTick + retryTime);
1069   }
1070}
1071
1072void
1073Device::txKick()
1074{
1075    VirtualReg *vnic;
1076    DPRINTF(EthernetSM, "txKick: txState=%s (txFifo.size=%d)\n",
1077            TxStateStrings[txState], txFifo.size());
1078
1079    if (txKickTick > curTick) {
1080        DPRINTF(EthernetSM, "txKick: exiting, can't run till %d\n",
1081                txKickTick);
1082        return;
1083    }
1084
1085  next:
1086    if (txState == txIdle)
1087        goto exit;
1088
1089    assert(!txList.empty());
1090    vnic = &virtualRegs[txList.front()];
1091
1092    switch (txState) {
1093      case txFifoBlock:
1094        assert(Regs::get_TxDone_Busy(vnic->TxDone));
1095        if (!txPacket) {
1096            // Grab a new packet from the fifo.
1097            txPacket = new EthPacketData(16384);
1098            txPacketOffset = 0;
1099        }
1100
1101        if (txFifo.avail() - txPacket->length <
1102            Regs::get_TxData_Len(vnic->TxData)) {
1103            DPRINTF(EthernetSM, "transmit fifo full.  Nothing to do.\n");
1104            goto exit;
1105        }
1106
1107        txState = txBeginCopy;
1108        break;
1109
1110      case txBeginCopy:
1111        if (dmaPending() || getState() != Running)
1112            goto exit;
1113
1114        txDmaAddr = params()->platform->pciToDma(
1115                Regs::get_TxData_Addr(vnic->TxData));
1116        txDmaLen = Regs::get_TxData_Len(vnic->TxData);
1117        txDmaData = txPacket->data + txPacketOffset;
1118        txState = txCopy;
1119
1120        dmaRead(txDmaAddr, txDmaLen, &txDmaEvent, txDmaData);
1121        break;
1122
1123      case txCopy:
1124        DPRINTF(EthernetSM, "transmit machine still copying\n");
1125        goto exit;
1126
1127      case txCopyDone:
1128        vnic->TxDone = txDmaLen | Regs::TxDone_Complete;
1129        txPacket->length += txDmaLen;
1130        if ((vnic->TxData & Regs::TxData_More)) {
1131            txPacketOffset += txDmaLen;
1132            txState = txIdle;
1133            devIntrPost(Regs::Intr_TxDMA);
1134            break;
1135        }
1136
1137        assert(txPacket->length <= txFifo.avail());
1138        if ((vnic->TxData & Regs::TxData_Checksum)) {
1139            IpPtr ip(txPacket);
1140            if (ip) {
1141                TcpPtr tcp(ip);
1142                if (tcp) {
1143                    tcp->sum(0);
1144                    tcp->sum(cksum(tcp));
1145                    txTcpChecksums++;
1146                }
1147
1148                UdpPtr udp(ip);
1149                if (udp) {
1150                    udp->sum(0);
1151                    udp->sum(cksum(udp));
1152                    txUdpChecksums++;
1153                }
1154
1155                ip->sum(0);
1156                ip->sum(cksum(ip));
1157                txIpChecksums++;
1158            }
1159        }
1160
1161        txFifo.push(txPacket);
1162        if (txFifo.avail() < regs.TxMaxCopy) {
1163            devIntrPost(Regs::Intr_TxFull);
1164            txFull = true;
1165        }
1166        txPacket = 0;
1167        transmit();
1168        txList.pop_front();
1169        txState = txList.empty() ? txIdle : txFifoBlock;
1170        devIntrPost(Regs::Intr_TxDMA);
1171        break;
1172
1173      default:
1174        panic("Invalid txState!");
1175    }
1176
1177    DPRINTF(EthernetSM, "entering next txState=%s\n",
1178            TxStateStrings[txState]);
1179
1180    goto next;
1181
1182  exit:
1183    /**
1184     * @todo do we want to schedule a future kick?
1185     */
1186    DPRINTF(EthernetSM, "tx state machine exited txState=%s\n",
1187            TxStateStrings[txState]);
1188}
1189
1190void
1191Device::transferDone()
1192{
1193    if (txFifo.empty()) {
1194        DPRINTF(Ethernet, "transfer complete: txFifo empty...nothing to do\n");
1195        return;
1196    }
1197
1198    DPRINTF(Ethernet, "transfer complete: data in txFifo...schedule xmit\n");
1199
1200    txEvent.reschedule(curTick + cycles(1), true);
1201}
1202
1203bool
1204Device::rxFilter(const EthPacketPtr &packet)
1205{
1206    if (!Regs::get_Config_Filter(regs.Config))
1207        return false;
1208
1209    panic("receive filter not implemented\n");
1210    bool drop = true;
1211
1212#if 0
1213    string type;
1214
1215    EthHdr *eth = packet->eth();
1216    if (eth->unicast()) {
1217        // If we're accepting all unicast addresses
1218        if (acceptUnicast)
1219            drop = false;
1220
1221        // If we make a perfect match
1222        if (acceptPerfect && params->eaddr == eth.dst())
1223            drop = false;
1224
1225        if (acceptArp && eth->type() == ETH_TYPE_ARP)
1226            drop = false;
1227
1228    } else if (eth->broadcast()) {
1229        // if we're accepting broadcasts
1230        if (acceptBroadcast)
1231            drop = false;
1232
1233    } else if (eth->multicast()) {
1234        // if we're accepting all multicasts
1235        if (acceptMulticast)
1236            drop = false;
1237
1238    }
1239
1240    if (drop) {
1241        DPRINTF(Ethernet, "rxFilter drop\n");
1242        DDUMP(EthernetData, packet->data, packet->length);
1243    }
1244#endif
1245    return drop;
1246}
1247
1248bool
1249Device::recvPacket(EthPacketPtr packet)
1250{
1251    rxBytes += packet->length;
1252    rxPackets++;
1253
1254    DPRINTF(Ethernet, "Receiving packet from wire, rxFifo Available is %d\n",
1255            rxFifo.avail());
1256
1257    if (!rxEnable) {
1258        DPRINTF(Ethernet, "receive disabled...packet dropped\n");
1259        return true;
1260    }
1261
1262    if (rxFilter(packet)) {
1263        DPRINTF(Ethernet, "packet filtered...dropped\n");
1264        return true;
1265    }
1266
1267    if (rxFifo.size() >= regs.RxFifoMark)
1268        devIntrPost(Regs::Intr_RxHigh);
1269
1270    if (!rxFifo.push(packet)) {
1271        DPRINTF(Ethernet,
1272                "packet will not fit in receive buffer...packet dropped\n");
1273        return false;
1274    }
1275
1276    // If we were at the last element, back up one ot go to the new
1277    // last element of the list.
1278    if (rxFifoPtr == rxFifo.end())
1279        --rxFifoPtr;
1280
1281    devIntrPost(Regs::Intr_RxPacket);
1282    rxKick();
1283    return true;
1284}
1285
1286void
1287Device::resume()
1288{
1289    SimObject::resume();
1290
1291    // During drain we could have left the state machines in a waiting state and
1292    // they wouldn't get out until some other event occured to kick them.
1293    // This way they'll get out immediately
1294    txKick();
1295    rxKick();
1296}
1297
1298//=====================================================================
1299//
1300//
1301void
1302Base::serialize(std::ostream &os)
1303{
1304    // Serialize the PciDev base class
1305    PciDev::serialize(os);
1306
1307    SERIALIZE_SCALAR(rxEnable);
1308    SERIALIZE_SCALAR(txEnable);
1309    SERIALIZE_SCALAR(cpuIntrEnable);
1310
1311    /*
1312     * Keep track of pending interrupt status.
1313     */
1314    SERIALIZE_SCALAR(intrTick);
1315    SERIALIZE_SCALAR(cpuPendingIntr);
1316    Tick intrEventTick = 0;
1317    if (intrEvent)
1318        intrEventTick = intrEvent->when();
1319    SERIALIZE_SCALAR(intrEventTick);
1320}
1321
1322void
1323Base::unserialize(Checkpoint *cp, const std::string &section)
1324{
1325    // Unserialize the PciDev base class
1326    PciDev::unserialize(cp, section);
1327
1328    UNSERIALIZE_SCALAR(rxEnable);
1329    UNSERIALIZE_SCALAR(txEnable);
1330    UNSERIALIZE_SCALAR(cpuIntrEnable);
1331
1332    /*
1333     * Keep track of pending interrupt status.
1334     */
1335    UNSERIALIZE_SCALAR(intrTick);
1336    UNSERIALIZE_SCALAR(cpuPendingIntr);
1337    Tick intrEventTick;
1338    UNSERIALIZE_SCALAR(intrEventTick);
1339    if (intrEventTick) {
1340        intrEvent = new IntrEvent(this, intrEventTick, true);
1341    }
1342}
1343
1344void
1345Device::serialize(std::ostream &os)
1346{
1347    int count;
1348
1349    // Serialize the PciDev base class
1350    Base::serialize(os);
1351
1352    if (rxState == rxCopy)
1353        panic("can't serialize with an in flight dma request rxState=%s",
1354              RxStateStrings[rxState]);
1355
1356    if (txState == txCopy)
1357        panic("can't serialize with an in flight dma request txState=%s",
1358              TxStateStrings[txState]);
1359
1360    /*
1361     * Serialize the device registers
1362     */
1363    SERIALIZE_SCALAR(regs.Config);
1364    SERIALIZE_SCALAR(regs.IntrStatus);
1365    SERIALIZE_SCALAR(regs.IntrMask);
1366    SERIALIZE_SCALAR(regs.RxMaxCopy);
1367    SERIALIZE_SCALAR(regs.TxMaxCopy);
1368    SERIALIZE_SCALAR(regs.RxMaxIntr);
1369    SERIALIZE_SCALAR(regs.VirtualCount);
1370    SERIALIZE_SCALAR(regs.RxData);
1371    SERIALIZE_SCALAR(regs.RxDone);
1372    SERIALIZE_SCALAR(regs.TxData);
1373    SERIALIZE_SCALAR(regs.TxDone);
1374
1375    /*
1376     * Serialize the virtual nic state
1377     */
1378    int virtualRegsSize = virtualRegs.size();
1379    SERIALIZE_SCALAR(virtualRegsSize);
1380    for (int i = 0; i < virtualRegsSize; ++i) {
1381        VirtualReg *vnic = &virtualRegs[i];
1382
1383        std::string reg = csprintf("vnic%d", i);
1384        paramOut(os, reg + ".RxData", vnic->RxData);
1385        paramOut(os, reg + ".RxDone", vnic->RxDone);
1386        paramOut(os, reg + ".TxData", vnic->TxData);
1387        paramOut(os, reg + ".TxDone", vnic->TxDone);
1388
1389        bool rxPacketExists = vnic->rxPacket != rxFifo.end();
1390        paramOut(os, reg + ".rxPacketExists", rxPacketExists);
1391        if (rxPacketExists) {
1392            int rxPacket = 0;
1393            PacketFifo::iterator i = rxFifo.begin();
1394            while (i != vnic->rxPacket) {
1395                assert(i != rxFifo.end());
1396                ++i;
1397                ++rxPacket;
1398            }
1399
1400            paramOut(os, reg + ".rxPacket", rxPacket);
1401            paramOut(os, reg + ".rxPacketOffset", vnic->rxPacketOffset);
1402            paramOut(os, reg + ".rxPacketBytes", vnic->rxPacketBytes);
1403        }
1404        paramOut(os, reg + ".rxDoneData", vnic->rxDoneData);
1405    }
1406
1407    int rxFifoPtr = rxFifo.countPacketsBefore(this->rxFifoPtr);
1408    SERIALIZE_SCALAR(rxFifoPtr);
1409
1410    SERIALIZE_SCALAR(rxActive);
1411
1412    VirtualList::iterator i, end;
1413    for (count = 0, i = rxList.begin(), end = rxList.end(); i != end; ++i)
1414        paramOut(os, csprintf("rxList%d", count++), *i);
1415    int rxListSize = count;
1416    SERIALIZE_SCALAR(rxListSize);
1417
1418    for (count = 0, i = rxBusy.begin(), end = rxBusy.end(); i != end; ++i)
1419        paramOut(os, csprintf("rxBusy%d", count++), *i);
1420    int rxBusySize = count;
1421    SERIALIZE_SCALAR(rxBusySize);
1422
1423    for (count = 0, i = txList.begin(), end = txList.end(); i != end; ++i)
1424        paramOut(os, csprintf("txList%d", count++), *i);
1425    int txListSize = count;
1426    SERIALIZE_SCALAR(txListSize);
1427
1428    /*
1429     * Serialize rx state machine
1430     */
1431    int rxState = this->rxState;
1432    SERIALIZE_SCALAR(rxState);
1433    SERIALIZE_SCALAR(rxEmpty);
1434    SERIALIZE_SCALAR(rxLow);
1435    rxFifo.serialize("rxFifo", os);
1436
1437    /*
1438     * Serialize tx state machine
1439     */
1440    int txState = this->txState;
1441    SERIALIZE_SCALAR(txState);
1442    SERIALIZE_SCALAR(txFull);
1443    txFifo.serialize("txFifo", os);
1444    bool txPacketExists = txPacket;
1445    SERIALIZE_SCALAR(txPacketExists);
1446    if (txPacketExists) {
1447        txPacket->serialize("txPacket", os);
1448        SERIALIZE_SCALAR(txPacketOffset);
1449        SERIALIZE_SCALAR(txPacketBytes);
1450    }
1451
1452    /*
1453     * If there's a pending transmit, store the time so we can
1454     * reschedule it later
1455     */
1456    Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick : 0;
1457    SERIALIZE_SCALAR(transmitTick);
1458}
1459
1460void
1461Device::unserialize(Checkpoint *cp, const std::string &section)
1462{
1463    // Unserialize the PciDev base class
1464    Base::unserialize(cp, section);
1465
1466    /*
1467     * Unserialize the device registers
1468     */
1469    UNSERIALIZE_SCALAR(regs.Config);
1470    UNSERIALIZE_SCALAR(regs.IntrStatus);
1471    UNSERIALIZE_SCALAR(regs.IntrMask);
1472    UNSERIALIZE_SCALAR(regs.RxMaxCopy);
1473    UNSERIALIZE_SCALAR(regs.TxMaxCopy);
1474    UNSERIALIZE_SCALAR(regs.RxMaxIntr);
1475    UNSERIALIZE_SCALAR(regs.VirtualCount);
1476    UNSERIALIZE_SCALAR(regs.RxData);
1477    UNSERIALIZE_SCALAR(regs.RxDone);
1478    UNSERIALIZE_SCALAR(regs.TxData);
1479    UNSERIALIZE_SCALAR(regs.TxDone);
1480
1481    UNSERIALIZE_SCALAR(rxActive);
1482
1483    int rxListSize;
1484    UNSERIALIZE_SCALAR(rxListSize);
1485    rxList.clear();
1486    for (int i = 0; i < rxListSize; ++i) {
1487        int value;
1488        paramIn(cp, section, csprintf("rxList%d", i), value);
1489        rxList.push_back(value);
1490    }
1491
1492    int rxBusySize;
1493    UNSERIALIZE_SCALAR(rxBusySize);
1494    rxBusy.clear();
1495    for (int i = 0; i < rxBusySize; ++i) {
1496        int value;
1497        paramIn(cp, section, csprintf("rxBusy%d", i), value);
1498        rxBusy.push_back(value);
1499    }
1500
1501    int txListSize;
1502    UNSERIALIZE_SCALAR(txListSize);
1503    txList.clear();
1504    for (int i = 0; i < txListSize; ++i) {
1505        int value;
1506        paramIn(cp, section, csprintf("txList%d", i), value);
1507        txList.push_back(value);
1508    }
1509
1510    /*
1511     * Unserialize rx state machine
1512     */
1513    int rxState;
1514    UNSERIALIZE_SCALAR(rxState);
1515    UNSERIALIZE_SCALAR(rxEmpty);
1516    UNSERIALIZE_SCALAR(rxLow);
1517    this->rxState = (RxState) rxState;
1518    rxFifo.unserialize("rxFifo", cp, section);
1519
1520    int rxFifoPtr;
1521    UNSERIALIZE_SCALAR(rxFifoPtr);
1522    this->rxFifoPtr = rxFifo.begin();
1523    for (int i = 0; i < rxFifoPtr; ++i)
1524        ++this->rxFifoPtr;
1525
1526    /*
1527     * Unserialize tx state machine
1528     */
1529    int txState;
1530    UNSERIALIZE_SCALAR(txState);
1531    UNSERIALIZE_SCALAR(txFull);
1532    this->txState = (TxState) txState;
1533    txFifo.unserialize("txFifo", cp, section);
1534    bool txPacketExists;
1535    UNSERIALIZE_SCALAR(txPacketExists);
1536    txPacket = 0;
1537    if (txPacketExists) {
1538        txPacket = new EthPacketData(16384);
1539        txPacket->unserialize("txPacket", cp, section);
1540        UNSERIALIZE_SCALAR(txPacketOffset);
1541        UNSERIALIZE_SCALAR(txPacketBytes);
1542    }
1543
1544    /*
1545     * unserialize the virtual nic registers/state
1546     *
1547     * this must be done after the unserialization of the rxFifo
1548     * because the packet iterators depend on the fifo being populated
1549     */
1550    int virtualRegsSize;
1551    UNSERIALIZE_SCALAR(virtualRegsSize);
1552    virtualRegs.clear();
1553    virtualRegs.resize(virtualRegsSize);
1554    for (int i = 0; i < virtualRegsSize; ++i) {
1555        VirtualReg *vnic = &virtualRegs[i];
1556        std::string reg = csprintf("vnic%d", i);
1557
1558        paramIn(cp, section, reg + ".RxData", vnic->RxData);
1559        paramIn(cp, section, reg + ".RxDone", vnic->RxDone);
1560        paramIn(cp, section, reg + ".TxData", vnic->TxData);
1561        paramIn(cp, section, reg + ".TxDone", vnic->TxDone);
1562
1563        vnic->rxUnique = rxUnique++;
1564        vnic->txUnique = txUnique++;
1565
1566        bool rxPacketExists;
1567        paramIn(cp, section, reg + ".rxPacketExists", rxPacketExists);
1568        if (rxPacketExists) {
1569            int rxPacket;
1570            paramIn(cp, section, reg + ".rxPacket", rxPacket);
1571            vnic->rxPacket = rxFifo.begin();
1572            while (rxPacket--)
1573                ++vnic->rxPacket;
1574
1575            paramIn(cp, section, reg + ".rxPacketOffset",
1576                    vnic->rxPacketOffset);
1577            paramIn(cp, section, reg + ".rxPacketBytes", vnic->rxPacketBytes);
1578        } else {
1579            vnic->rxPacket = rxFifo.end();
1580        }
1581        paramIn(cp, section, reg + ".rxDoneData", vnic->rxDoneData);
1582    }
1583
1584    /*
1585     * If there's a pending transmit, reschedule it now
1586     */
1587    Tick transmitTick;
1588    UNSERIALIZE_SCALAR(transmitTick);
1589    if (transmitTick)
1590        txEvent.schedule(curTick + transmitTick);
1591
1592    pioPort->sendStatusChange(Port::RangeChange);
1593
1594}
1595
1596/* namespace Sinic */ }
1597
1598Sinic::Interface *
1599SinicIntParams::create()
1600{
1601    using namespace Sinic;
1602
1603    Interface *dev_int = new Interface(name, device);
1604
1605    if (peer) {
1606        dev_int->setPeer(peer);
1607        peer->setPeer(dev_int);
1608    }
1609
1610    return dev_int;
1611}
1612
1613Sinic::Device *
1614SinicParams::create()
1615{
1616    return new Sinic::Device(this);
1617}
1618