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