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