sinic.cc revision 2090
110553Salexandru.dutu@amd.com/*
210553Salexandru.dutu@amd.com * Copyright (c) 2004-2005 The Regents of The University of Michigan
310553Salexandru.dutu@amd.com * All rights reserved.
410553Salexandru.dutu@amd.com *
510553Salexandru.dutu@amd.com * Redistribution and use in source and binary forms, with or without
610553Salexandru.dutu@amd.com * modification, are permitted provided that the following conditions are
710553Salexandru.dutu@amd.com * met: redistributions of source code must retain the above copyright
810553Salexandru.dutu@amd.com * notice, this list of conditions and the following disclaimer;
910553Salexandru.dutu@amd.com * redistributions in binary form must reproduce the above copyright
1010553Salexandru.dutu@amd.com * notice, this list of conditions and the following disclaimer in the
1110553Salexandru.dutu@amd.com * documentation and/or other materials provided with the distribution;
1210553Salexandru.dutu@amd.com * neither the name of the copyright holders nor the names of its
1310553Salexandru.dutu@amd.com * contributors may be used to endorse or promote products derived from
1410553Salexandru.dutu@amd.com * this software without specific prior written permission.
1510553Salexandru.dutu@amd.com *
1610553Salexandru.dutu@amd.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1710553Salexandru.dutu@amd.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1810553Salexandru.dutu@amd.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
1910553Salexandru.dutu@amd.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2010553Salexandru.dutu@amd.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2110553Salexandru.dutu@amd.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2210553Salexandru.dutu@amd.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2310553Salexandru.dutu@amd.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2410553Salexandru.dutu@amd.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2510553Salexandru.dutu@amd.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2610553Salexandru.dutu@amd.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2710553Salexandru.dutu@amd.com */
2810553Salexandru.dutu@amd.com
2910553Salexandru.dutu@amd.com#include <cstdio>
3010553Salexandru.dutu@amd.com#include <deque>
3110553Salexandru.dutu@amd.com#include <string>
3211793Sbrandon.potter@amd.com
3310553Salexandru.dutu@amd.com#include "base/inet.hh"
3410553Salexandru.dutu@amd.com#include "cpu/exec_context.hh"
3510553Salexandru.dutu@amd.com#include "cpu/intr_control.hh"
3610553Salexandru.dutu@amd.com#include "dev/etherlink.hh"
3710553Salexandru.dutu@amd.com#include "dev/sinic.hh"
3810553Salexandru.dutu@amd.com#include "dev/pciconfigall.hh"
3910553Salexandru.dutu@amd.com#include "mem/bus/bus.hh"
4010553Salexandru.dutu@amd.com#include "mem/bus/dma_interface.hh"
4110553Salexandru.dutu@amd.com#include "mem/bus/pio_interface.hh"
4210553Salexandru.dutu@amd.com#include "mem/bus/pio_interface_impl.hh"
4310553Salexandru.dutu@amd.com#include "mem/functional/memory_control.hh"
4410553Salexandru.dutu@amd.com#include "mem/functional/physical.hh"
4510553Salexandru.dutu@amd.com#include "sim/builder.hh"
4610553Salexandru.dutu@amd.com#include "sim/debug.hh"
4710553Salexandru.dutu@amd.com#include "sim/eventq.hh"
4810553Salexandru.dutu@amd.com#include "sim/host.hh"
4910553Salexandru.dutu@amd.com#include "sim/stats.hh"
50#include "targetarch/vtophys.hh"
51
52using namespace Net;
53
54namespace Sinic {
55
56const char *RxStateStrings[] =
57{
58    "rxIdle",
59    "rxFifoBlock",
60    "rxBeginCopy",
61    "rxCopy",
62    "rxCopyDone"
63};
64
65const char *TxStateStrings[] =
66{
67    "txIdle",
68    "txFifoBlock",
69    "txBeginCopy",
70    "txCopy",
71    "txCopyDone"
72};
73
74
75///////////////////////////////////////////////////////////////////////
76//
77// Sinic PCI Device
78//
79Base::Base(Params *p)
80    : PciDev(p), rxEnable(false), txEnable(false), clock(p->clock),
81      intrDelay(p->intr_delay), intrTick(0), cpuIntrEnable(false),
82      cpuPendingIntr(false), intrEvent(0), interface(NULL)
83{
84}
85
86Device::Device(Params *p)
87    : Base(p), plat(p->plat), physmem(p->physmem),
88      rxFifo(p->rx_fifo_size), txFifo(p->tx_fifo_size),
89      rxKickTick(0), txKickTick(0),
90      txEvent(this), rxDmaEvent(this), txDmaEvent(this),
91      dmaReadDelay(p->dma_read_delay), dmaReadFactor(p->dma_read_factor),
92      dmaWriteDelay(p->dma_write_delay), dmaWriteFactor(p->dma_write_factor)
93{
94    reset();
95
96    if (p->pio_bus) {
97        pioInterface = newPioInterface(p->name + ".pio", p->hier, p->pio_bus,
98                                       this, &Device::cacheAccess);
99        pioLatency = p->pio_latency * p->pio_bus->clockRate;
100    }
101
102    if (p->header_bus) {
103        if (p->payload_bus)
104            dmaInterface = new DMAInterface<Bus>(p->name + ".dma",
105                                                 p->header_bus,
106                                                 p->payload_bus, 1,
107                                                 p->dma_no_allocate);
108        else
109            dmaInterface = new DMAInterface<Bus>(p->name + ".dma",
110                                                 p->header_bus,
111                                                 p->header_bus, 1,
112                                                 p->dma_no_allocate);
113    } else if (p->payload_bus)
114        panic("must define a header bus if defining a payload bus");
115
116    pioDelayWrite = p->pio_delay_write && pioInterface;
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        return;
321
322    virtualRegs.resize(index + 1);
323    for (int i = size; i <= index; ++i)
324        virtualRegs[i].rxPacket = rxFifo.end();
325}
326
327void
328Device::prepareRead(int cpu, int index)
329{
330    using namespace Regs;
331    prepareIO(cpu, index);
332
333    VirtualReg &vnic = virtualRegs[index];
334
335    // update rx registers
336    uint64_t rxdone = vnic.RxDone;
337    rxdone = set_RxDone_Packets(rxdone, rxFifo.packets());
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    if (cpu >= writeQueue.size())
356        writeQueue.resize(cpu + 1);
357
358    prepareIO(cpu, index);
359}
360
361/**
362 * I/O read of device register
363 */
364Fault *
365Device::read(MemReqPtr &req, uint8_t *data)
366{
367    assert(config.command & PCI_CMD_MSE);
368    Fault * fault = readBar(req, data);
369
370    if (fault == MachineCheckFault) {
371        panic("address does not map to a BAR pa=%#x va=%#x size=%d",
372              req->paddr, req->vaddr, req->size);
373
374        return MachineCheckFault;
375    }
376
377    return fault;
378}
379
380Fault *
381Device::readBar0(MemReqPtr &req, Addr daddr, uint8_t *data)
382{
383    int cpu = (req->xc->regs.ipr[TheISA::IPR_PALtemp16] >> 8) & 0xff;
384    Addr index = daddr >> Regs::VirtualShift;
385    Addr raddr = daddr & Regs::VirtualMask;
386
387    if (!regValid(raddr))
388        panic("invalid register: cpu=%d, da=%#x pa=%#x va=%#x size=%d",
389              cpu, daddr, req->paddr, req->vaddr, req->size);
390
391    const Regs::Info &info = regInfo(raddr);
392    if (!info.read)
393        panic("reading %s (write only): cpu=%d da=%#x pa=%#x va=%#x size=%d",
394              info.name, cpu, daddr, req->paddr, req->vaddr, req->size);
395
396    if (req->size != info.size)
397        panic("invalid size for reg %s: cpu=%d da=%#x pa=%#x va=%#x size=%d",
398              info.name, cpu, daddr, req->paddr, req->vaddr, req->size);
399
400    prepareRead(cpu, index);
401
402    uint64_t value = 0;
403    if (req->size == 4) {
404        uint32_t &reg = *(uint32_t *)data;
405        reg = regData32(raddr);
406        value = reg;
407    }
408
409    if (req->size == 8) {
410        uint64_t &reg = *(uint64_t *)data;
411        reg = regData64(raddr);
412        value = reg;
413    }
414
415    DPRINTF(EthernetPIO,
416            "read %s cpu=%d da=%#x pa=%#x va=%#x size=%d val=%#x\n",
417            info.name, cpu, daddr, req->paddr, req->vaddr, req->size, 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 == MachineCheckFault) {
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 MachineCheckFault;
471    }
472
473    return fault;
474}
475
476Fault *
477Device::writeBar0(MemReqPtr &req, Addr daddr, const uint8_t *data)
478{
479    int cpu = (req->xc->regs.ipr[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("writing %s (read only): cpu=%d da=%#x",
490              info.name, cpu, daddr);
491
492    if (req->size != info.size)
493        panic("invalid size for %s: cpu=%d da=%#x pa=%#x va=%#x size=%d",
494              info.name, cpu, daddr, req->paddr, req->vaddr, req->size);
495
496    uint32_t reg32 = *(uint32_t *)data;
497    uint64_t reg64 = *(uint64_t *)data;
498    DPRINTF(EthernetPIO,
499            "write %s: cpu=%d val=%#x da=%#x pa=%#x va=%#x size=%d\n",
500            info.name, cpu, info.size == 4 ? reg32 : reg64, daddr,
501            req->paddr, req->vaddr, req->size);
502
503    prepareWrite(cpu, index);
504
505    if (pioDelayWrite)
506        writeQueue[cpu].push_back(RegWriteData(daddr, reg64));
507
508    if (!pioDelayWrite || !info.delay_write)
509        regWrite(daddr, cpu, data);
510
511    return NoFault;
512}
513
514void
515Device::regWrite(Addr daddr, int cpu, const uint8_t *data)
516{
517    Addr index = daddr >> Regs::VirtualShift;
518    Addr raddr = daddr & Regs::VirtualMask;
519
520    uint32_t reg32 = *(uint32_t *)data;
521    uint64_t reg64 = *(uint64_t *)data;
522    VirtualReg &vnic = virtualRegs[index];
523
524    switch (raddr) {
525      case Regs::Config:
526        changeConfig(reg32);
527        break;
528
529      case Regs::Command:
530        command(reg32);
531        break;
532
533      case Regs::IntrStatus:
534        devIntrClear(regs.IntrStatus & reg32);
535        break;
536
537      case Regs::IntrMask:
538        devIntrChangeMask(reg32);
539        break;
540
541      case Regs::RxData:
542        if (Regs::get_RxDone_Busy(vnic.RxDone))
543            panic("receive machine busy with another request! rxState=%s",
544                  RxStateStrings[rxState]);
545
546        vnic.RxDone = Regs::RxDone_Busy;
547        vnic.RxData = reg64;
548        rxList.push_back(index);
549        if (rxEnable && rxState == rxIdle) {
550            rxState = rxFifoBlock;
551            rxKick();
552        }
553        break;
554
555      case Regs::TxData:
556        if (Regs::get_TxDone_Busy(vnic.TxDone))
557            panic("transmit machine busy with another request! txState=%s",
558                  TxStateStrings[txState]);
559
560        vnic.TxDone = Regs::TxDone_Busy;
561        vnic.TxData = reg64;
562        if (txList.empty() || txList.front() != index)
563            txList.push_back(index);
564        if (txEnable && txState == txIdle && txList.front() == index) {
565            txState = txFifoBlock;
566            txKick();
567        }
568        break;
569    }
570}
571
572void
573Device::devIntrPost(uint32_t interrupts)
574{
575    if ((interrupts & Regs::Intr_Res))
576        panic("Cannot set a reserved interrupt");
577
578    regs.IntrStatus |= interrupts;
579
580    DPRINTF(EthernetIntr,
581            "interrupt written to intStatus: intr=%#x status=%#x mask=%#x\n",
582            interrupts, regs.IntrStatus, regs.IntrMask);
583
584    interrupts = regs.IntrStatus & regs.IntrMask;
585
586    // Intr_RxHigh is special, we only signal it if we've emptied the fifo
587    // and then filled it above the high watermark
588    if (rxEmpty)
589        rxEmpty = false;
590    else
591        interrupts &= ~Regs::Intr_RxHigh;
592
593    // Intr_TxLow is special, we only signal it if we've filled up the fifo
594    // and then dropped below the low watermark
595    if (txFull)
596        txFull = false;
597    else
598        interrupts &= ~Regs::Intr_TxLow;
599
600    if (interrupts) {
601        Tick when = curTick;
602        if ((interrupts & Regs::Intr_NoDelay) == 0)
603            when += intrDelay;
604        cpuIntrPost(when);
605    }
606}
607
608void
609Device::devIntrClear(uint32_t interrupts)
610{
611    if ((interrupts & Regs::Intr_Res))
612        panic("Cannot clear a reserved interrupt");
613
614    regs.IntrStatus &= ~interrupts;
615
616    DPRINTF(EthernetIntr,
617            "interrupt cleared from intStatus: intr=%x status=%x mask=%x\n",
618            interrupts, regs.IntrStatus, regs.IntrMask);
619
620    if (!(regs.IntrStatus & regs.IntrMask))
621        cpuIntrClear();
622}
623
624void
625Device::devIntrChangeMask(uint32_t newmask)
626{
627    if (regs.IntrMask == newmask)
628        return;
629
630    regs.IntrMask = newmask;
631
632    DPRINTF(EthernetIntr,
633            "interrupt mask changed: intStatus=%x intMask=%x masked=%x\n",
634            regs.IntrStatus, regs.IntrMask, regs.IntrStatus & regs.IntrMask);
635
636    if (regs.IntrStatus & regs.IntrMask)
637        cpuIntrPost(curTick);
638    else
639        cpuIntrClear();
640}
641
642void
643Base::cpuIntrPost(Tick when)
644{
645    // If the interrupt you want to post is later than an interrupt
646    // already scheduled, just let it post in the coming one and don't
647    // schedule another.
648    // HOWEVER, must be sure that the scheduled intrTick is in the
649    // future (this was formerly the source of a bug)
650    /**
651     * @todo this warning should be removed and the intrTick code should
652     * be fixed.
653     */
654    assert(when >= curTick);
655    assert(intrTick >= curTick || intrTick == 0);
656    if (!cpuIntrEnable) {
657        DPRINTF(EthernetIntr, "interrupts not enabled.\n",
658                intrTick);
659        return;
660    }
661
662    if (when > intrTick && intrTick != 0) {
663        DPRINTF(EthernetIntr, "don't need to schedule event...intrTick=%d\n",
664                intrTick);
665        return;
666    }
667
668    intrTick = when;
669    if (intrTick < curTick) {
670        debug_break();
671        intrTick = curTick;
672    }
673
674    DPRINTF(EthernetIntr, "going to schedule an interrupt for intrTick=%d\n",
675            intrTick);
676
677    if (intrEvent)
678        intrEvent->squash();
679    intrEvent = new IntrEvent(this, true);
680    intrEvent->schedule(intrTick);
681}
682
683void
684Base::cpuInterrupt()
685{
686    assert(intrTick == curTick);
687
688    // Whether or not there's a pending interrupt, we don't care about
689    // it anymore
690    intrEvent = 0;
691    intrTick = 0;
692
693    // Don't send an interrupt if there's already one
694    if (cpuPendingIntr) {
695        DPRINTF(EthernetIntr,
696                "would send an interrupt now, but there's already pending\n");
697    } else {
698        // Send interrupt
699        cpuPendingIntr = true;
700
701        DPRINTF(EthernetIntr, "posting interrupt\n");
702        intrPost();
703    }
704}
705
706void
707Base::cpuIntrClear()
708{
709    if (!cpuPendingIntr)
710        return;
711
712    if (intrEvent) {
713        intrEvent->squash();
714        intrEvent = 0;
715    }
716
717    intrTick = 0;
718
719    cpuPendingIntr = false;
720
721    DPRINTF(EthernetIntr, "clearing cchip interrupt\n");
722    intrClear();
723}
724
725bool
726Base::cpuIntrPending() const
727{ return cpuPendingIntr; }
728
729void
730Device::changeConfig(uint32_t newconf)
731{
732    uint32_t changed = regs.Config ^ newconf;
733    if (!changed)
734        return;
735
736    regs.Config = newconf;
737
738    if ((changed & Regs::Config_IntEn)) {
739        cpuIntrEnable = regs.Config & Regs::Config_IntEn;
740        if (cpuIntrEnable) {
741            if (regs.IntrStatus & regs.IntrMask)
742                cpuIntrPost(curTick);
743        } else {
744            cpuIntrClear();
745        }
746    }
747
748    if ((changed & Regs::Config_TxEn)) {
749        txEnable = regs.Config & Regs::Config_TxEn;
750        if (txEnable)
751            txKick();
752    }
753
754    if ((changed & Regs::Config_RxEn)) {
755        rxEnable = regs.Config & Regs::Config_RxEn;
756        if (rxEnable)
757            rxKick();
758    }
759}
760
761void
762Device::command(uint32_t command)
763{
764    if (command & Regs::Command_Intr)
765        devIntrPost(Regs::Intr_Soft);
766
767    if (command & Regs::Command_Reset)
768        reset();
769}
770
771void
772Device::reset()
773{
774    using namespace Regs;
775
776    memset(&regs, 0, sizeof(regs));
777
778    regs.Config = 0;
779    if (params()->rx_thread)
780        regs.Config |= Config_RxThread;
781    if (params()->tx_thread)
782        regs.Config |= Config_TxThread;
783    regs.IntrMask = Intr_Soft | Intr_RxHigh | Intr_RxPacket | Intr_TxLow;
784    regs.RxMaxCopy = params()->rx_max_copy;
785    regs.TxMaxCopy = params()->tx_max_copy;
786    regs.RxMaxIntr = params()->rx_max_intr;
787    regs.RxFifoSize = params()->rx_fifo_size;
788    regs.TxFifoSize = params()->tx_fifo_size;
789    regs.RxFifoMark = params()->rx_fifo_threshold;
790    regs.TxFifoMark = params()->tx_fifo_threshold;
791    regs.HwAddr = params()->eaddr;
792
793    rxList.clear();
794    txList.clear();
795
796    rxState = rxIdle;
797    txState = txIdle;
798
799    rxFifo.clear();
800    rxFifoPtr = rxFifo.end();
801    txFifo.clear();
802    rxEmpty = false;
803    txFull = false;
804
805    int size = virtualRegs.size();
806    virtualRegs.clear();
807    virtualRegs.resize(size);
808    for (int i = 0; i < size; ++i)
809        virtualRegs[i].rxPacket = rxFifo.end();
810}
811
812void
813Device::rxDmaCopy()
814{
815    assert(rxState == rxCopy);
816    rxState = rxCopyDone;
817    physmem->dma_write(rxDmaAddr, (uint8_t *)rxDmaData, rxDmaLen);
818    DPRINTF(EthernetDMA, "rx dma write paddr=%#x len=%d\n",
819            rxDmaAddr, rxDmaLen);
820    DDUMP(EthernetData, rxDmaData, rxDmaLen);
821}
822
823void
824Device::rxDmaDone()
825{
826    rxDmaCopy();
827
828    // If the transmit state machine  has a pending DMA, let it go first
829    if (txState == txBeginCopy)
830        txKick();
831
832    rxKick();
833}
834
835void
836Device::rxKick()
837{
838    VirtualReg *vnic;
839
840    DPRINTF(EthernetSM, "receive kick rxState=%s (rxFifo.size=%d)\n",
841            RxStateStrings[rxState], rxFifo.size());
842
843    if (rxKickTick > curTick) {
844        DPRINTF(EthernetSM, "receive kick exiting, can't run till %d\n",
845                rxKickTick);
846        return;
847    }
848
849  next:
850    if (rxState == rxIdle)
851        goto exit;
852
853    assert(!rxList.empty());
854    vnic = &virtualRegs[rxList.front()];
855
856    DPRINTF(EthernetSM, "processing rxState=%s for virtual nic %d\n",
857            RxStateStrings[rxState], rxList.front());
858
859    switch (rxState) {
860      case rxFifoBlock:
861        if (vnic->rxPacket != rxFifo.end()) {
862            rxState = rxBeginCopy;
863            break;
864        }
865
866        if (rxFifoPtr == rxFifo.end()) {
867            DPRINTF(EthernetSM, "receive waiting for data.  Nothing to do.\n");
868            goto exit;
869        }
870
871        assert(!rxFifo.empty());
872
873        // Grab a new packet from the fifo.
874        vnic->rxPacket = rxFifoPtr++;
875        vnic->rxPacketOffset = 0;
876        vnic->rxPacketBytes = (*vnic->rxPacket)->length;
877        assert(vnic->rxPacketBytes);
878
879        vnic->rxDoneData = 0;
880        /* scope for variables */ {
881            IpPtr ip(*vnic->rxPacket);
882            if (ip) {
883                vnic->rxDoneData |= Regs::RxDone_IpPacket;
884                rxIpChecksums++;
885                if (cksum(ip) != 0) {
886                    DPRINTF(EthernetCksum, "Rx IP Checksum Error\n");
887                    vnic->rxDoneData |= Regs::RxDone_IpError;
888                }
889                TcpPtr tcp(ip);
890                UdpPtr udp(ip);
891                if (tcp) {
892                    vnic->rxDoneData |= Regs::RxDone_TcpPacket;
893                    rxTcpChecksums++;
894                    if (cksum(tcp) != 0) {
895                        DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n");
896                        vnic->rxDoneData |= Regs::RxDone_TcpError;
897                    }
898                } else if (udp) {
899                    vnic->rxDoneData |= Regs::RxDone_UdpPacket;
900                    rxUdpChecksums++;
901                    if (cksum(udp) != 0) {
902                        DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n");
903                        vnic->rxDoneData |= Regs::RxDone_UdpError;
904                    }
905                }
906            }
907        }
908        rxState = rxBeginCopy;
909        break;
910
911      case rxBeginCopy:
912        if (dmaInterface && dmaInterface->busy())
913            goto exit;
914
915        rxDmaAddr = plat->pciToDma(Regs::get_RxData_Addr(vnic->RxData));
916        rxDmaLen = min<int>(Regs::get_RxData_Len(vnic->RxData),
917                            vnic->rxPacketBytes);
918        rxDmaData = (*vnic->rxPacket)->data + vnic->rxPacketOffset;
919        rxState = rxCopy;
920
921        if (dmaInterface) {
922            dmaInterface->doDMA(WriteInvalidate, rxDmaAddr, rxDmaLen,
923                                curTick, &rxDmaEvent, true);
924            goto exit;
925        }
926
927        if (dmaWriteDelay != 0 || dmaWriteFactor != 0) {
928            Tick factor = ((rxDmaLen + ULL(63)) >> ULL(6)) * dmaWriteFactor;
929            Tick start = curTick + dmaWriteDelay + factor;
930            rxDmaEvent.schedule(start);
931            goto exit;
932        }
933
934        rxDmaCopy();
935        break;
936
937      case rxCopy:
938        DPRINTF(EthernetSM, "receive machine still copying\n");
939        goto exit;
940
941      case rxCopyDone:
942        vnic->RxDone = vnic->rxDoneData | rxDmaLen;
943        vnic->RxDone |= Regs::RxDone_Complete;
944
945        if (vnic->rxPacketBytes == rxDmaLen) {
946            DPRINTF(EthernetSM, "rxKick: packet complete on vnic %d\n",
947                    rxList.front());
948            rxFifo.remove(vnic->rxPacket);
949            vnic->rxPacket = rxFifo.end();
950        } else {
951            vnic->RxDone |= Regs::RxDone_More;
952            vnic->rxPacketBytes -= rxDmaLen;
953            vnic->rxPacketOffset += rxDmaLen;
954            DPRINTF(EthernetSM,
955                    "rxKick: packet not complete on vnic %d: %d bytes left\n",
956                    rxList.front(), vnic->rxPacketBytes);
957        }
958
959        rxList.pop_front();
960        rxState = rxList.empty() ? rxIdle : rxFifoBlock;
961
962        if (rxFifo.empty()) {
963            devIntrPost(Regs::Intr_RxEmpty);
964            rxEmpty = true;
965        }
966
967        devIntrPost(Regs::Intr_RxDMA);
968        break;
969
970      default:
971        panic("Invalid rxState!");
972    }
973
974    DPRINTF(EthernetSM, "entering next rxState=%s\n",
975            RxStateStrings[rxState]);
976
977    goto next;
978
979  exit:
980    /**
981     * @todo do we want to schedule a future kick?
982     */
983    DPRINTF(EthernetSM, "rx state machine exited rxState=%s\n",
984            RxStateStrings[rxState]);
985}
986
987void
988Device::txDmaCopy()
989{
990    assert(txState == txCopy);
991    txState = txCopyDone;
992    physmem->dma_read((uint8_t *)txDmaData, txDmaAddr, txDmaLen);
993    DPRINTF(EthernetDMA, "tx dma read paddr=%#x len=%d\n",
994            txDmaAddr, txDmaLen);
995    DDUMP(EthernetData, txDmaData, txDmaLen);
996}
997
998void
999Device::txDmaDone()
1000{
1001    txDmaCopy();
1002
1003    // If the receive state machine  has a pending DMA, let it go first
1004    if (rxState == rxBeginCopy)
1005        rxKick();
1006
1007    txKick();
1008}
1009
1010void
1011Device::transmit()
1012{
1013    if (txFifo.empty()) {
1014        DPRINTF(Ethernet, "nothing to transmit\n");
1015        return;
1016    }
1017
1018    uint32_t interrupts;
1019    PacketPtr packet = txFifo.front();
1020    if (!interface->sendPacket(packet)) {
1021        DPRINTF(Ethernet, "Packet Transmit: failed txFifo available %d\n",
1022                txFifo.avail());
1023        goto reschedule;
1024    }
1025
1026    txFifo.pop();
1027#if TRACING_ON
1028    if (DTRACE(Ethernet)) {
1029        IpPtr ip(packet);
1030        if (ip) {
1031            DPRINTF(Ethernet, "ID is %d\n", ip->id());
1032            TcpPtr tcp(ip);
1033            if (tcp) {
1034                DPRINTF(Ethernet, "Src Port=%d, Dest Port=%d\n",
1035                        tcp->sport(), tcp->dport());
1036            }
1037        }
1038    }
1039#endif
1040
1041    DDUMP(EthernetData, packet->data, packet->length);
1042    txBytes += packet->length;
1043    txPackets++;
1044
1045    DPRINTF(Ethernet, "Packet Transmit: successful txFifo Available %d\n",
1046            txFifo.avail());
1047
1048    interrupts = Regs::Intr_TxPacket;
1049    if (txFifo.size() < regs.TxFifoMark)
1050        interrupts |= Regs::Intr_TxLow;
1051    devIntrPost(interrupts);
1052
1053  reschedule:
1054   if (!txFifo.empty() && !txEvent.scheduled()) {
1055       DPRINTF(Ethernet, "reschedule transmit\n");
1056       txEvent.schedule(curTick + retryTime);
1057   }
1058}
1059
1060void
1061Device::txKick()
1062{
1063    VirtualReg *vnic;
1064    DPRINTF(EthernetSM, "transmit kick txState=%s (txFifo.size=%d)\n",
1065            TxStateStrings[txState], txFifo.size());
1066
1067    if (txKickTick > curTick) {
1068        DPRINTF(EthernetSM, "transmit kick exiting, can't run till %d\n",
1069                txKickTick);
1070        return;
1071    }
1072
1073  next:
1074    if (txState == txIdle)
1075        goto exit;
1076
1077    assert(!txList.empty());
1078    vnic = &virtualRegs[txList.front()];
1079
1080    switch (txState) {
1081      case txFifoBlock:
1082        assert(Regs::get_TxDone_Busy(vnic->TxData));
1083        if (!txPacket) {
1084            // Grab a new packet from the fifo.
1085            txPacket = new PacketData(16384);
1086            txPacketOffset = 0;
1087        }
1088
1089        if (txFifo.avail() - txPacket->length <
1090            Regs::get_TxData_Len(vnic->TxData)) {
1091            DPRINTF(EthernetSM, "transmit fifo full.  Nothing to do.\n");
1092            goto exit;
1093        }
1094
1095        txState = txBeginCopy;
1096        break;
1097
1098      case txBeginCopy:
1099        if (dmaInterface && dmaInterface->busy())
1100            goto exit;
1101
1102        txDmaAddr = plat->pciToDma(Regs::get_TxData_Addr(vnic->TxData));
1103        txDmaLen = Regs::get_TxData_Len(vnic->TxData);
1104        txDmaData = txPacket->data + txPacketOffset;
1105        txState = txCopy;
1106
1107        if (dmaInterface) {
1108            dmaInterface->doDMA(Read, txDmaAddr, txDmaLen,
1109                                curTick, &txDmaEvent, true);
1110            goto exit;
1111        }
1112
1113        if (dmaReadDelay != 0 || dmaReadFactor != 0) {
1114            Tick factor = ((txDmaLen + ULL(63)) >> ULL(6)) * dmaReadFactor;
1115            Tick start = curTick + dmaReadDelay + factor;
1116            txDmaEvent.schedule(start);
1117            goto exit;
1118        }
1119
1120        txDmaCopy();
1121        break;
1122
1123      case txCopy:
1124        DPRINTF(EthernetSM, "transmit machine still copying\n");
1125        goto exit;
1126
1127      case txCopyDone:
1128        vnic->TxDone = txDmaLen | Regs::TxDone_Complete;
1129        txPacket->length += txDmaLen;
1130        if ((vnic->TxData & Regs::TxData_More)) {
1131            txPacketOffset += txDmaLen;
1132            txState = txIdle;
1133            devIntrPost(Regs::Intr_TxDMA);
1134            break;
1135        }
1136
1137        assert(txPacket->length <= txFifo.avail());
1138        if ((vnic->TxData & Regs::TxData_Checksum)) {
1139            IpPtr ip(txPacket);
1140            if (ip) {
1141                TcpPtr tcp(ip);
1142                if (tcp) {
1143                    tcp->sum(0);
1144                    tcp->sum(cksum(tcp));
1145                    txTcpChecksums++;
1146                }
1147
1148                UdpPtr udp(ip);
1149                if (udp) {
1150                    udp->sum(0);
1151                    udp->sum(cksum(udp));
1152                    txUdpChecksums++;
1153                }
1154
1155                ip->sum(0);
1156                ip->sum(cksum(ip));
1157                txIpChecksums++;
1158            }
1159        }
1160
1161        txFifo.push(txPacket);
1162        if (txFifo.avail() < regs.TxMaxCopy) {
1163            devIntrPost(Regs::Intr_TxFull);
1164            txFull = true;
1165        }
1166        txPacket = 0;
1167        transmit();
1168        txList.pop_front();
1169        txState = txList.empty() ? txIdle : txFifoBlock;
1170        devIntrPost(Regs::Intr_TxDMA);
1171        break;
1172
1173      default:
1174        panic("Invalid txState!");
1175    }
1176
1177    DPRINTF(EthernetSM, "entering next txState=%s\n",
1178            TxStateStrings[txState]);
1179
1180    goto next;
1181
1182  exit:
1183    /**
1184     * @todo do we want to schedule a future kick?
1185     */
1186    DPRINTF(EthernetSM, "tx state machine exited txState=%s\n",
1187            TxStateStrings[txState]);
1188}
1189
1190void
1191Device::transferDone()
1192{
1193    if (txFifo.empty()) {
1194        DPRINTF(Ethernet, "transfer complete: txFifo empty...nothing to do\n");
1195        return;
1196    }
1197
1198    DPRINTF(Ethernet, "transfer complete: data in txFifo...schedule xmit\n");
1199
1200    if (txEvent.scheduled())
1201        txEvent.reschedule(curTick + cycles(1));
1202    else
1203        txEvent.schedule(curTick + cycles(1));
1204}
1205
1206bool
1207Device::rxFilter(const PacketPtr &packet)
1208{
1209    if (!Regs::get_Config_Filter(regs.Config))
1210        return false;
1211
1212    panic("receive filter not implemented\n");
1213    bool drop = true;
1214
1215#if 0
1216    string type;
1217
1218    EthHdr *eth = packet->eth();
1219    if (eth->unicast()) {
1220        // If we're accepting all unicast addresses
1221        if (acceptUnicast)
1222            drop = false;
1223
1224        // If we make a perfect match
1225        if (acceptPerfect && params->eaddr == eth.dst())
1226            drop = false;
1227
1228        if (acceptArp && eth->type() == ETH_TYPE_ARP)
1229            drop = false;
1230
1231    } else if (eth->broadcast()) {
1232        // if we're accepting broadcasts
1233        if (acceptBroadcast)
1234            drop = false;
1235
1236    } else if (eth->multicast()) {
1237        // if we're accepting all multicasts
1238        if (acceptMulticast)
1239            drop = false;
1240
1241    }
1242
1243    if (drop) {
1244        DPRINTF(Ethernet, "rxFilter drop\n");
1245        DDUMP(EthernetData, packet->data, packet->length);
1246    }
1247#endif
1248    return drop;
1249}
1250
1251bool
1252Device::recvPacket(PacketPtr packet)
1253{
1254    rxBytes += packet->length;
1255    rxPackets++;
1256
1257    DPRINTF(Ethernet, "Receiving packet from wire, rxFifo Available is %d\n",
1258            rxFifo.avail());
1259
1260    if (!rxEnable) {
1261        DPRINTF(Ethernet, "receive disabled...packet dropped\n");
1262        return true;
1263    }
1264
1265    if (rxFilter(packet)) {
1266        DPRINTF(Ethernet, "packet filtered...dropped\n");
1267        return true;
1268    }
1269
1270    if (rxFifo.size() >= regs.RxFifoMark)
1271        devIntrPost(Regs::Intr_RxHigh);
1272
1273    if (!rxFifo.push(packet)) {
1274        DPRINTF(Ethernet,
1275                "packet will not fit in receive buffer...packet dropped\n");
1276        return false;
1277    }
1278
1279    // If we were at the last element, back up one ot go to the new
1280    // last element of the list.
1281    if (rxFifoPtr == rxFifo.end())
1282        --rxFifoPtr;
1283
1284    devIntrPost(Regs::Intr_RxPacket);
1285    rxKick();
1286    return true;
1287}
1288
1289//=====================================================================
1290//
1291//
1292void
1293Base::serialize(ostream &os)
1294{
1295    // Serialize the PciDev base class
1296    PciDev::serialize(os);
1297
1298    SERIALIZE_SCALAR(rxEnable);
1299    SERIALIZE_SCALAR(txEnable);
1300    SERIALIZE_SCALAR(cpuIntrEnable);
1301
1302    /*
1303     * Keep track of pending interrupt status.
1304     */
1305    SERIALIZE_SCALAR(intrTick);
1306    SERIALIZE_SCALAR(cpuPendingIntr);
1307    Tick intrEventTick = 0;
1308    if (intrEvent)
1309        intrEventTick = intrEvent->when();
1310    SERIALIZE_SCALAR(intrEventTick);
1311}
1312
1313void
1314Base::unserialize(Checkpoint *cp, const std::string &section)
1315{
1316    // Unserialize the PciDev base class
1317    PciDev::unserialize(cp, section);
1318
1319    UNSERIALIZE_SCALAR(rxEnable);
1320    UNSERIALIZE_SCALAR(txEnable);
1321    UNSERIALIZE_SCALAR(cpuIntrEnable);
1322
1323    /*
1324     * Keep track of pending interrupt status.
1325     */
1326    UNSERIALIZE_SCALAR(intrTick);
1327    UNSERIALIZE_SCALAR(cpuPendingIntr);
1328    Tick intrEventTick;
1329    UNSERIALIZE_SCALAR(intrEventTick);
1330    if (intrEventTick) {
1331        intrEvent = new IntrEvent(this, true);
1332        intrEvent->schedule(intrEventTick);
1333    }
1334}
1335
1336void
1337Device::serialize(ostream &os)
1338{
1339    // Serialize the PciDev base class
1340    Base::serialize(os);
1341
1342    if (rxState == rxCopy)
1343        panic("can't serialize with an in flight dma request rxState=%s",
1344              RxStateStrings[rxState]);
1345
1346    if (txState == txCopy)
1347        panic("can't serialize with an in flight dma request txState=%s",
1348              TxStateStrings[txState]);
1349
1350    /*
1351     * Serialize the device registers
1352     */
1353    SERIALIZE_SCALAR(regs.Config);
1354    SERIALIZE_SCALAR(regs.IntrStatus);
1355    SERIALIZE_SCALAR(regs.IntrMask);
1356    SERIALIZE_SCALAR(regs.RxMaxCopy);
1357    SERIALIZE_SCALAR(regs.TxMaxCopy);
1358    SERIALIZE_SCALAR(regs.RxMaxIntr);
1359    SERIALIZE_SCALAR(regs.RxData);
1360    SERIALIZE_SCALAR(regs.RxDone);
1361    SERIALIZE_SCALAR(regs.TxData);
1362    SERIALIZE_SCALAR(regs.TxDone);
1363
1364    /*
1365     * Serialize the virtual nic state
1366     */
1367    int virtualRegsSize = virtualRegs.size();
1368    SERIALIZE_SCALAR(virtualRegsSize);
1369    for (int i = 0; i < virtualRegsSize; ++i) {
1370        VirtualReg *vnic = &virtualRegs[i];
1371
1372        string reg = csprintf("vnic%d", i);
1373        paramOut(os, reg + ".RxData", vnic->RxData);
1374        paramOut(os, reg + ".RxDone", vnic->RxDone);
1375        paramOut(os, reg + ".TxData", vnic->TxData);
1376        paramOut(os, reg + ".TxDone", vnic->TxDone);
1377
1378        PacketFifo::iterator rxFifoPtr;
1379
1380        bool rxPacketExists = vnic->rxPacket != rxFifo.end();
1381        paramOut(os, reg + ".rxPacketExists", rxPacketExists);
1382        if (rxPacketExists) {
1383            int rxPacket = 0;
1384            PacketFifo::iterator i = rxFifo.begin();
1385            while (i != vnic->rxPacket) {
1386                assert(i != rxFifo.end());
1387                ++i;
1388                ++rxPacket;
1389            }
1390
1391            paramOut(os, reg + ".rxPacket", rxPacket);
1392            paramOut(os, reg + ".rxPacketOffset", vnic->rxPacketOffset);
1393            paramOut(os, reg + ".rxPacketBytes", vnic->rxPacketBytes);
1394        }
1395        paramOut(os, reg + ".rxDoneData", vnic->rxDoneData);
1396    }
1397
1398    VirtualList::iterator i, end;
1399    int count;
1400
1401    int rxListSize = rxList.size();
1402    SERIALIZE_SCALAR(rxListSize);
1403    for (count = 0, i = rxList.begin(), end = rxList.end(); i != end; ++i)
1404        paramOut(os, csprintf("rxList%d", count++), *i);
1405
1406    int txListSize = txList.size();
1407    SERIALIZE_SCALAR(txListSize);
1408    for (count = 0, i = txList.begin(), end = txList.end(); i != end; ++i)
1409        paramOut(os, csprintf("txList%d", count++), *i);
1410
1411    /*
1412     * Serialize rx state machine
1413     */
1414    int rxState = this->rxState;
1415    SERIALIZE_SCALAR(rxState);
1416    SERIALIZE_SCALAR(rxEmpty);
1417    rxFifo.serialize("rxFifo", os);
1418
1419    /*
1420     * Serialize tx state machine
1421     */
1422    int txState = this->txState;
1423    SERIALIZE_SCALAR(txState);
1424    SERIALIZE_SCALAR(txFull);
1425    txFifo.serialize("txFifo", os);
1426    bool txPacketExists = txPacket;
1427    SERIALIZE_SCALAR(txPacketExists);
1428    if (txPacketExists) {
1429        txPacket->serialize("txPacket", os);
1430        SERIALIZE_SCALAR(txPacketOffset);
1431        SERIALIZE_SCALAR(txPacketBytes);
1432    }
1433
1434    /*
1435     * If there's a pending transmit, store the time so we can
1436     * reschedule it later
1437     */
1438    Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick : 0;
1439    SERIALIZE_SCALAR(transmitTick);
1440}
1441
1442void
1443Device::unserialize(Checkpoint *cp, const std::string &section)
1444{
1445    // Unserialize the PciDev base class
1446    Base::unserialize(cp, section);
1447
1448    /*
1449     * Unserialize the device registers
1450     */
1451    UNSERIALIZE_SCALAR(regs.Config);
1452    UNSERIALIZE_SCALAR(regs.IntrStatus);
1453    UNSERIALIZE_SCALAR(regs.IntrMask);
1454    UNSERIALIZE_SCALAR(regs.RxMaxCopy);
1455    UNSERIALIZE_SCALAR(regs.TxMaxCopy);
1456    UNSERIALIZE_SCALAR(regs.RxMaxIntr);
1457    UNSERIALIZE_SCALAR(regs.RxData);
1458    UNSERIALIZE_SCALAR(regs.RxDone);
1459    UNSERIALIZE_SCALAR(regs.TxData);
1460    UNSERIALIZE_SCALAR(regs.TxDone);
1461
1462    int rxListSize;
1463    UNSERIALIZE_SCALAR(rxListSize);
1464    rxList.clear();
1465    for (int i = 0; i < rxListSize; ++i) {
1466        int value;
1467        paramIn(cp, section, csprintf("rxList%d", i), value);
1468        rxList.push_back(value);
1469    }
1470
1471    int txListSize;
1472    UNSERIALIZE_SCALAR(txListSize);
1473    txList.clear();
1474    for (int i = 0; i < txListSize; ++i) {
1475        int value;
1476        paramIn(cp, section, csprintf("txList%d", i), value);
1477        txList.push_back(value);
1478    }
1479
1480    /*
1481     * Unserialize rx state machine
1482     */
1483    int rxState;
1484    UNSERIALIZE_SCALAR(rxState);
1485    UNSERIALIZE_SCALAR(rxEmpty);
1486    this->rxState = (RxState) rxState;
1487    rxFifo.unserialize("rxFifo", cp, section);
1488
1489    /*
1490     * Unserialize tx state machine
1491     */
1492    int txState;
1493    UNSERIALIZE_SCALAR(txState);
1494    UNSERIALIZE_SCALAR(txFull);
1495    this->txState = (TxState) txState;
1496    txFifo.unserialize("txFifo", cp, section);
1497    bool txPacketExists;
1498    UNSERIALIZE_SCALAR(txPacketExists);
1499    txPacket = 0;
1500    if (txPacketExists) {
1501        txPacket = new PacketData(16384);
1502        txPacket->unserialize("txPacket", cp, section);
1503        UNSERIALIZE_SCALAR(txPacketOffset);
1504        UNSERIALIZE_SCALAR(txPacketBytes);
1505    }
1506
1507    /*
1508     * unserialize the virtual nic registers/state
1509     *
1510     * this must be done after the unserialization of the rxFifo
1511     * because the packet iterators depend on the fifo being populated
1512     */
1513    int virtualRegsSize;
1514    UNSERIALIZE_SCALAR(virtualRegsSize);
1515    virtualRegs.clear();
1516    virtualRegs.resize(virtualRegsSize);
1517    for (int i = 0; i < virtualRegsSize; ++i) {
1518        VirtualReg *vnic = &virtualRegs[i];
1519        string reg = csprintf("vnic%d", i);
1520
1521        paramIn(cp, section, reg + ".RxData", vnic->RxData);
1522        paramIn(cp, section, reg + ".RxDone", vnic->RxDone);
1523        paramIn(cp, section, reg + ".TxData", vnic->TxData);
1524        paramIn(cp, section, reg + ".TxDone", vnic->TxDone);
1525
1526        bool rxPacketExists;
1527        paramIn(cp, section, reg + ".rxPacketExists", rxPacketExists);
1528        if (rxPacketExists) {
1529            int rxPacket;
1530            paramIn(cp, section, reg + ".rxPacket", rxPacket);
1531            vnic->rxPacket = rxFifo.begin();
1532            while (rxPacket--)
1533                ++vnic->rxPacket;
1534
1535            paramIn(cp, section, reg + ".rxPacketOffset",
1536                    vnic->rxPacketOffset);
1537            paramIn(cp, section, reg + ".rxPacketBytes", vnic->rxPacketBytes);
1538        } else {
1539            vnic->rxPacket = rxFifo.end();
1540        }
1541        paramIn(cp, section, reg + ".rxDoneData", vnic->rxDoneData);
1542    }
1543
1544    /*
1545     * If there's a pending transmit, reschedule it now
1546     */
1547    Tick transmitTick;
1548    UNSERIALIZE_SCALAR(transmitTick);
1549    if (transmitTick)
1550        txEvent.schedule(curTick + transmitTick);
1551
1552    /*
1553     * re-add addrRanges to bus bridges
1554     */
1555    if (pioInterface) {
1556        pioInterface->addAddrRange(RangeSize(BARAddrs[0], BARSize[0]));
1557        pioInterface->addAddrRange(RangeSize(BARAddrs[1], BARSize[1]));
1558    }
1559}
1560
1561Tick
1562Device::cacheAccess(MemReqPtr &req)
1563{
1564    Addr daddr;
1565    int bar;
1566    if (!getBAR(req->paddr, daddr, bar))
1567        panic("address does not map to a BAR pa=%#x va=%#x size=%d",
1568              req->paddr, req->vaddr, req->size);
1569
1570    DPRINTF(EthernetPIO, "timing %s to paddr=%#x bar=%d daddr=%#x\n",
1571            req->cmd.toString(), req->paddr, bar, daddr);
1572
1573    if (!pioDelayWrite || !req->cmd.isWrite())
1574        return curTick + pioLatency;
1575
1576    if (bar == 0) {
1577        int cpu = (req->xc->regs.ipr[TheISA::IPR_PALtemp16] >> 8) & 0xff;
1578        std::list<RegWriteData> &wq = writeQueue[cpu];
1579        if (wq.empty())
1580            panic("WriteQueue for cpu %d empty timing daddr=%#x", cpu, daddr);
1581
1582        const RegWriteData &data = wq.front();
1583        if (data.daddr != daddr)
1584            panic("read mismatch on cpu %d, daddr functional=%#x timing=%#x",
1585                  cpu, data.daddr, daddr);
1586
1587        const Regs::Info &info = regInfo(data.daddr);
1588        if (info.delay_write)
1589            regWrite(daddr, cpu, (uint8_t *)&data.value);
1590
1591        wq.pop_front();
1592    }
1593
1594    return curTick + pioLatency;
1595}
1596
1597BEGIN_DECLARE_SIM_OBJECT_PARAMS(Interface)
1598
1599    SimObjectParam<EtherInt *> peer;
1600    SimObjectParam<Device *> device;
1601
1602END_DECLARE_SIM_OBJECT_PARAMS(Interface)
1603
1604BEGIN_INIT_SIM_OBJECT_PARAMS(Interface)
1605
1606    INIT_PARAM_DFLT(peer, "peer interface", NULL),
1607    INIT_PARAM(device, "Ethernet device of this interface")
1608
1609END_INIT_SIM_OBJECT_PARAMS(Interface)
1610
1611CREATE_SIM_OBJECT(Interface)
1612{
1613    Interface *dev_int = new Interface(getInstanceName(), device);
1614
1615    EtherInt *p = (EtherInt *)peer;
1616    if (p) {
1617        dev_int->setPeer(p);
1618        p->setPeer(dev_int);
1619    }
1620
1621    return dev_int;
1622}
1623
1624REGISTER_SIM_OBJECT("SinicInt", Interface)
1625
1626
1627BEGIN_DECLARE_SIM_OBJECT_PARAMS(Device)
1628
1629    Param<Tick> clock;
1630
1631    Param<Addr> addr;
1632    SimObjectParam<MemoryController *> mmu;
1633    SimObjectParam<PhysicalMemory *> physmem;
1634    SimObjectParam<PciConfigAll *> configspace;
1635    SimObjectParam<PciConfigData *> configdata;
1636    SimObjectParam<Platform *> platform;
1637    Param<uint32_t> pci_bus;
1638    Param<uint32_t> pci_dev;
1639    Param<uint32_t> pci_func;
1640
1641    SimObjectParam<HierParams *> hier;
1642    SimObjectParam<Bus*> pio_bus;
1643    SimObjectParam<Bus*> dma_bus;
1644    SimObjectParam<Bus*> payload_bus;
1645    Param<Tick> dma_read_delay;
1646    Param<Tick> dma_read_factor;
1647    Param<Tick> dma_write_delay;
1648    Param<Tick> dma_write_factor;
1649    Param<bool> dma_no_allocate;
1650    Param<Tick> pio_latency;
1651    Param<bool> pio_delay_write;
1652    Param<Tick> intr_delay;
1653
1654    Param<Tick> rx_delay;
1655    Param<Tick> tx_delay;
1656    Param<uint32_t> rx_max_copy;
1657    Param<uint32_t> tx_max_copy;
1658    Param<uint32_t> rx_max_intr;
1659    Param<uint32_t> rx_fifo_size;
1660    Param<uint32_t> tx_fifo_size;
1661    Param<uint32_t> rx_fifo_threshold;
1662    Param<uint32_t> tx_fifo_threshold;
1663
1664    Param<bool> rx_filter;
1665    Param<string> hardware_address;
1666    Param<bool> rx_thread;
1667    Param<bool> tx_thread;
1668
1669END_DECLARE_SIM_OBJECT_PARAMS(Device)
1670
1671BEGIN_INIT_SIM_OBJECT_PARAMS(Device)
1672
1673    INIT_PARAM(clock, "State machine cycle time"),
1674
1675    INIT_PARAM(addr, "Device Address"),
1676    INIT_PARAM(mmu, "Memory Controller"),
1677    INIT_PARAM(physmem, "Physical Memory"),
1678    INIT_PARAM(configspace, "PCI Configspace"),
1679    INIT_PARAM(configdata, "PCI Config data"),
1680    INIT_PARAM(platform, "Platform"),
1681    INIT_PARAM(pci_bus, "PCI bus"),
1682    INIT_PARAM(pci_dev, "PCI device number"),
1683    INIT_PARAM(pci_func, "PCI function code"),
1684
1685    INIT_PARAM(hier, "Hierarchy global variables"),
1686    INIT_PARAM(pio_bus, ""),
1687    INIT_PARAM(dma_bus, ""),
1688    INIT_PARAM(payload_bus, "The IO Bus to attach to for payload"),
1689    INIT_PARAM(dma_read_delay, "fixed delay for dma reads"),
1690    INIT_PARAM(dma_read_factor, "multiplier for dma reads"),
1691    INIT_PARAM(dma_write_delay, "fixed delay for dma writes"),
1692    INIT_PARAM(dma_write_factor, "multiplier for dma writes"),
1693    INIT_PARAM(dma_no_allocate, "Should we allocat on read in cache"),
1694    INIT_PARAM(pio_latency, "Programmed IO latency in bus cycles"),
1695    INIT_PARAM(pio_delay_write, ""),
1696    INIT_PARAM(intr_delay, "Interrupt Delay"),
1697
1698    INIT_PARAM(rx_delay, "Receive Delay"),
1699    INIT_PARAM(tx_delay, "Transmit Delay"),
1700    INIT_PARAM(rx_max_copy, "rx max copy"),
1701    INIT_PARAM(tx_max_copy, "rx max copy"),
1702    INIT_PARAM(rx_max_intr, "rx max intr"),
1703    INIT_PARAM(rx_fifo_size, "max size in bytes of rxFifo"),
1704    INIT_PARAM(tx_fifo_size, "max size in bytes of txFifo"),
1705    INIT_PARAM(rx_fifo_threshold, "max size in bytes of rxFifo"),
1706    INIT_PARAM(tx_fifo_threshold, "max size in bytes of txFifo"),
1707
1708    INIT_PARAM(rx_filter, "Enable Receive Filter"),
1709    INIT_PARAM(hardware_address, "Ethernet Hardware Address"),
1710    INIT_PARAM(rx_thread, ""),
1711    INIT_PARAM(tx_thread, "")
1712
1713END_INIT_SIM_OBJECT_PARAMS(Device)
1714
1715
1716CREATE_SIM_OBJECT(Device)
1717{
1718    Device::Params *params = new Device::Params;
1719
1720    params->name = getInstanceName();
1721
1722    params->clock = clock;
1723
1724    params->mmu = mmu;
1725    params->physmem = physmem;
1726    params->configSpace = configspace;
1727    params->configData = configdata;
1728    params->plat = platform;
1729    params->busNum = pci_bus;
1730    params->deviceNum = pci_dev;
1731    params->functionNum = pci_func;
1732
1733    params->hier = hier;
1734    params->pio_bus = pio_bus;
1735    params->header_bus = dma_bus;
1736    params->payload_bus = payload_bus;
1737    params->dma_read_delay = dma_read_delay;
1738    params->dma_read_factor = dma_read_factor;
1739    params->dma_write_delay = dma_write_delay;
1740    params->dma_write_factor = dma_write_factor;
1741    params->dma_no_allocate = dma_no_allocate;
1742    params->pio_latency = pio_latency;
1743    params->pio_delay_write = pio_delay_write;
1744    params->intr_delay = intr_delay;
1745
1746    params->tx_delay = tx_delay;
1747    params->rx_delay = rx_delay;
1748    params->rx_max_copy = rx_max_copy;
1749    params->tx_max_copy = tx_max_copy;
1750    params->rx_max_intr = rx_max_intr;
1751    params->rx_fifo_size = rx_fifo_size;
1752    params->tx_fifo_size = tx_fifo_size;
1753    params->rx_fifo_threshold = rx_fifo_threshold;
1754    params->tx_fifo_threshold = tx_fifo_threshold;
1755
1756    params->rx_filter = rx_filter;
1757    params->eaddr = hardware_address;
1758    params->rx_thread = rx_thread;
1759    params->tx_thread = tx_thread;
1760
1761    return new Device(params);
1762}
1763
1764REGISTER_SIM_OBJECT("Sinic", Device)
1765
1766/* namespace Sinic */ }
1767