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