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