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