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