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