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