sinic.cc revision 1157
112739Sandreas.sandberg@arm.com/*
29525SAndreas.Sandberg@ARM.com * Copyright (c) 2004 The Regents of The University of Michigan
39525SAndreas.Sandberg@ARM.com * All rights reserved.
49525SAndreas.Sandberg@ARM.com *
59525SAndreas.Sandberg@ARM.com * Redistribution and use in source and binary forms, with or without
69525SAndreas.Sandberg@ARM.com * modification, are permitted provided that the following conditions are
79525SAndreas.Sandberg@ARM.com * met: redistributions of source code must retain the above copyright
89525SAndreas.Sandberg@ARM.com * notice, this list of conditions and the following disclaimer;
99525SAndreas.Sandberg@ARM.com * redistributions in binary form must reproduce the above copyright
109525SAndreas.Sandberg@ARM.com * notice, this list of conditions and the following disclaimer in the
119525SAndreas.Sandberg@ARM.com * documentation and/or other materials provided with the distribution;
129525SAndreas.Sandberg@ARM.com * neither the name of the copyright holders nor the names of its
139525SAndreas.Sandberg@ARM.com * contributors may be used to endorse or promote products derived from
149525SAndreas.Sandberg@ARM.com * this software without specific prior written permission.
159525SAndreas.Sandberg@ARM.com *
169525SAndreas.Sandberg@ARM.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
179525SAndreas.Sandberg@ARM.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
189525SAndreas.Sandberg@ARM.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
199525SAndreas.Sandberg@ARM.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
209525SAndreas.Sandberg@ARM.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
219525SAndreas.Sandberg@ARM.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
229525SAndreas.Sandberg@ARM.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
239525SAndreas.Sandberg@ARM.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
249525SAndreas.Sandberg@ARM.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
259525SAndreas.Sandberg@ARM.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
269525SAndreas.Sandberg@ARM.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
279525SAndreas.Sandberg@ARM.com */
289525SAndreas.Sandberg@ARM.com
299525SAndreas.Sandberg@ARM.com#include <cstdio>
309525SAndreas.Sandberg@ARM.com#include <deque>
319525SAndreas.Sandberg@ARM.com#include <string>
329525SAndreas.Sandberg@ARM.com
339525SAndreas.Sandberg@ARM.com#include "base/inet.hh"
349525SAndreas.Sandberg@ARM.com#include "cpu/exec_context.hh"
359525SAndreas.Sandberg@ARM.com#include "cpu/intr_control.hh"
369525SAndreas.Sandberg@ARM.com#include "dev/dma.hh"
379525SAndreas.Sandberg@ARM.com#include "dev/etherlink.hh"
389525SAndreas.Sandberg@ARM.com#include "dev/sinic.hh"
399525SAndreas.Sandberg@ARM.com#include "dev/pciconfigall.hh"
4013591Sciro.santilli@arm.com#include "mem/bus/bus.hh"
4110749Smatt.evans@arm.com#include "mem/bus/dma_interface.hh"
429525SAndreas.Sandberg@ARM.com#include "mem/bus/pio_interface.hh"
4313665Sandreas.sandberg@arm.com#include "mem/bus/pio_interface_impl.hh"
4413665Sandreas.sandberg@arm.com#include "mem/functional_mem/memory_control.hh"
459525SAndreas.Sandberg@ARM.com#include "mem/functional_mem/physical_memory.hh"
469525SAndreas.Sandberg@ARM.com#include "sim/builder.hh"
479525SAndreas.Sandberg@ARM.com#include "sim/debug.hh"
489525SAndreas.Sandberg@ARM.com#include "sim/eventq.hh"
499525SAndreas.Sandberg@ARM.com#include "sim/host.hh"
509525SAndreas.Sandberg@ARM.com#include "sim/stats.hh"
519525SAndreas.Sandberg@ARM.com#include "targetarch/vtophys.hh"
529525SAndreas.Sandberg@ARM.com
5313505Sgiacomo.travaglini@arm.comusing namespace Net;
5413505Sgiacomo.travaglini@arm.com
5513505Sgiacomo.travaglini@arm.comnamespace Sinic {
5613505Sgiacomo.travaglini@arm.com
5713505Sgiacomo.travaglini@arm.comconst char *RxStateStrings[] =
5813505Sgiacomo.travaglini@arm.com{
5913505Sgiacomo.travaglini@arm.com    "rxIdle",
6013505Sgiacomo.travaglini@arm.com    "rxFifoBlock",
6113505Sgiacomo.travaglini@arm.com    "rxBeginCopy",
6212739Sandreas.sandberg@arm.com    "rxCopy",
6312739Sandreas.sandberg@arm.com    "rxCopyDone"
6412739Sandreas.sandberg@arm.com};
6512974Sgiacomo.travaglini@arm.com
6612739Sandreas.sandberg@arm.comconst char *TxStateStrings[] =
6712739Sandreas.sandberg@arm.com{
6812739Sandreas.sandberg@arm.com    "txIdle",
6912739Sandreas.sandberg@arm.com    "txFifoBlock",
7012739Sandreas.sandberg@arm.com    "txBeginCopy",
7112739Sandreas.sandberg@arm.com    "txCopy",
7212739Sandreas.sandberg@arm.com    "txCopyDone"
7312739Sandreas.sandberg@arm.com};
7412974Sgiacomo.travaglini@arm.com
7512739Sandreas.sandberg@arm.com
7612739Sandreas.sandberg@arm.com///////////////////////////////////////////////////////////////////////
7712739Sandreas.sandberg@arm.com//
7812739Sandreas.sandberg@arm.com// Sinic PCI Device
7912974Sgiacomo.travaglini@arm.com//
8012739Sandreas.sandberg@arm.comBase::Base(Params *p)
8113014Sciro.santilli@arm.com    : PciDev(p), rxEnable(false), txEnable(false),
8213014Sciro.santilli@arm.com      intrDelay(US2Ticks(p->intr_delay)),
8313014Sciro.santilli@arm.com      intrTick(0), cpuIntrEnable(false), cpuPendingIntr(false), intrEvent(0),
849525SAndreas.Sandberg@ARM.com      interface(NULL)
8513013Sciro.santilli@arm.com{
8613013Sciro.santilli@arm.com}
8713013Sciro.santilli@arm.com
889525SAndreas.Sandberg@ARM.comDevice::Device(Params *p)
899525SAndreas.Sandberg@ARM.com    : Base(p), plat(p->plat), physmem(p->physmem),
909525SAndreas.Sandberg@ARM.com      rxFifo(p->rx_fifo_size), txFifo(p->tx_fifo_size),
919525SAndreas.Sandberg@ARM.com      rxKickTick(0), txKickTick(0),
9211652SCurtis.Dunham@arm.com      txEvent(this), rxDmaEvent(this), txDmaEvent(this),
9310749Smatt.evans@arm.com      dmaReadDelay(p->dma_read_delay), dmaReadFactor(p->dma_read_factor),
9413505Sgiacomo.travaglini@arm.com      dmaWriteDelay(p->dma_write_delay), dmaWriteFactor(p->dma_write_factor)
9513505Sgiacomo.travaglini@arm.com{
9613505Sgiacomo.travaglini@arm.com    reset();
9713505Sgiacomo.travaglini@arm.com
9813505Sgiacomo.travaglini@arm.com    if (p->header_bus) {
9913505Sgiacomo.travaglini@arm.com        pioInterface = newPioInterface(p->name, p->hier, p->header_bus, this,
10013505Sgiacomo.travaglini@arm.com                                       &Device::cacheAccess);
10113505Sgiacomo.travaglini@arm.com
10213505Sgiacomo.travaglini@arm.com        pioLatency = p->pio_latency * p->header_bus->clockRatio;
10313505Sgiacomo.travaglini@arm.com
10413505Sgiacomo.travaglini@arm.com        if (p->payload_bus)
10513505Sgiacomo.travaglini@arm.com            dmaInterface = new DMAInterface<Bus>(p->name + ".dma",
10613505Sgiacomo.travaglini@arm.com                                                 p->header_bus, p->payload_bus,
10710749Smatt.evans@arm.com                                                 1);
10810749Smatt.evans@arm.com        else
10910749Smatt.evans@arm.com            dmaInterface = new DMAInterface<Bus>(p->name + ".dma",
11010749Smatt.evans@arm.com                                                 p->header_bus, p->header_bus,
11110749Smatt.evans@arm.com                                                 1);
11210749Smatt.evans@arm.com    } else if (p->payload_bus) {
11310749Smatt.evans@arm.com        pioInterface = newPioInterface(p->name, p->hier, p->payload_bus, this,
11410749Smatt.evans@arm.com                                       &Device::cacheAccess);
11510749Smatt.evans@arm.com
11610749Smatt.evans@arm.com        pioLatency = p->pio_latency * p->payload_bus->clockRatio;
11710749Smatt.evans@arm.com
11810749Smatt.evans@arm.com        dmaInterface = new DMAInterface<Bus>(p->name + ".dma", p->payload_bus,
11910749Smatt.evans@arm.com                                             p->payload_bus, 1);
12010749Smatt.evans@arm.com    }
12113504Sgiacomo.travaglini@arm.com}
12213504Sgiacomo.travaglini@arm.com
12313504Sgiacomo.travaglini@arm.comDevice::~Device()
12413504Sgiacomo.travaglini@arm.com{}
12513504Sgiacomo.travaglini@arm.com
12613504Sgiacomo.travaglini@arm.comvoid
12713504Sgiacomo.travaglini@arm.comDevice::regStats()
12813504Sgiacomo.travaglini@arm.com{
12913504Sgiacomo.travaglini@arm.com    rxBytes
13013504Sgiacomo.travaglini@arm.com        .name(name() + ".rxBytes")
13113814Sgiacomo.travaglini@arm.com        .desc("Bytes Received")
13213504Sgiacomo.travaglini@arm.com        .prereq(rxBytes)
13313505Sgiacomo.travaglini@arm.com        ;
13413505Sgiacomo.travaglini@arm.com
13513505Sgiacomo.travaglini@arm.com    rxBandwidth
13613505Sgiacomo.travaglini@arm.com        .name(name() + ".rxBandwidth")
13713504Sgiacomo.travaglini@arm.com        .desc("Receive Bandwidth (bits/s)")
13813504Sgiacomo.travaglini@arm.com        .precision(0)
13913504Sgiacomo.travaglini@arm.com        .prereq(rxBytes)
14013504Sgiacomo.travaglini@arm.com        ;
14113504Sgiacomo.travaglini@arm.com
14213504Sgiacomo.travaglini@arm.com    rxPackets
14313504Sgiacomo.travaglini@arm.com        .name(name() + ".rxPackets")
14413504Sgiacomo.travaglini@arm.com        .desc("Number of Packets Received")
14513504Sgiacomo.travaglini@arm.com        .prereq(rxBytes)
14613504Sgiacomo.travaglini@arm.com        ;
14713504Sgiacomo.travaglini@arm.com
14813504Sgiacomo.travaglini@arm.com    rxPacketRate
14913504Sgiacomo.travaglini@arm.com        .name(name() + ".rxPPS")
15013504Sgiacomo.travaglini@arm.com        .desc("Packet Reception Rate (packets/s)")
15113504Sgiacomo.travaglini@arm.com        .precision(0)
15213504Sgiacomo.travaglini@arm.com        .prereq(rxBytes)
15313504Sgiacomo.travaglini@arm.com        ;
15413504Sgiacomo.travaglini@arm.com
15513504Sgiacomo.travaglini@arm.com    rxIpPackets
15613504Sgiacomo.travaglini@arm.com        .name(name() + ".rxIpPackets")
15713504Sgiacomo.travaglini@arm.com        .desc("Number of IP Packets Received")
15813504Sgiacomo.travaglini@arm.com        .prereq(rxBytes)
15913814Sgiacomo.travaglini@arm.com        ;
16013504Sgiacomo.travaglini@arm.com
16113504Sgiacomo.travaglini@arm.com    rxTcpPackets
16213504Sgiacomo.travaglini@arm.com        .name(name() + ".rxTcpPackets")
16313504Sgiacomo.travaglini@arm.com        .desc("Number of Packets Received")
16413531Sjairo.balart@metempsy.com        .prereq(rxBytes)
16513531Sjairo.balart@metempsy.com        ;
16613531Sjairo.balart@metempsy.com
16713531Sjairo.balart@metempsy.com    rxUdpPackets
16813531Sjairo.balart@metempsy.com        .name(name() + ".rxUdpPackets")
16913531Sjairo.balart@metempsy.com        .desc("Number of UDP Packets Received")
17013531Sjairo.balart@metempsy.com        .prereq(rxBytes)
17113531Sjairo.balart@metempsy.com        ;
17213531Sjairo.balart@metempsy.com
17313531Sjairo.balart@metempsy.com    rxIpChecksums
17413531Sjairo.balart@metempsy.com        .name(name() + ".rxIpChecksums")
17513531Sjairo.balart@metempsy.com        .desc("Number of rx IP Checksums done by device")
17613826Sgiacomo.travaglini@arm.com        .precision(0)
17713826Sgiacomo.travaglini@arm.com        .prereq(rxBytes)
17813826Sgiacomo.travaglini@arm.com        ;
17913826Sgiacomo.travaglini@arm.com
18013826Sgiacomo.travaglini@arm.com    rxTcpChecksums
18113877Sgiacomo.travaglini@arm.com        .name(name() + ".rxTcpChecksums")
18213877Sgiacomo.travaglini@arm.com        .desc("Number of rx TCP Checksums done by device")
18313877Sgiacomo.travaglini@arm.com        .precision(0)
18413877Sgiacomo.travaglini@arm.com        .prereq(rxBytes)
18513878Sgiacomo.travaglini@arm.com        ;
18613878Sgiacomo.travaglini@arm.com
187    rxUdpChecksums
188        .name(name() + ".rxUdpChecksums")
189        .desc("Number of rx UDP Checksums done by device")
190        .precision(0)
191        .prereq(rxBytes)
192        ;
193
194    txBytes
195        .name(name() + ".txBytes")
196        .desc("Bytes Transmitted")
197        .prereq(txBytes)
198        ;
199
200    txBandwidth
201        .name(name() + ".txBandwidth")
202        .desc("Transmit Bandwidth (bits/s)")
203        .precision(0)
204        .prereq(txBytes)
205        ;
206
207    txPackets
208        .name(name() + ".txPackets")
209        .desc("Number of Packets Transmitted")
210        .prereq(txBytes)
211        ;
212
213    txPacketRate
214        .name(name() + ".txPPS")
215        .desc("Packet Tranmission Rate (packets/s)")
216        .precision(0)
217        .prereq(txBytes)
218        ;
219
220    txIpPackets
221        .name(name() + ".txIpPackets")
222        .desc("Number of IP Packets Transmitted")
223        .prereq(txBytes)
224        ;
225
226    txTcpPackets
227        .name(name() + ".txTcpPackets")
228        .desc("Number of TCP Packets Transmitted")
229        .prereq(txBytes)
230        ;
231
232    txUdpPackets
233        .name(name() + ".txUdpPackets")
234        .desc("Number of Packets Transmitted")
235        .prereq(txBytes)
236        ;
237
238    txIpChecksums
239        .name(name() + ".txIpChecksums")
240        .desc("Number of tx IP Checksums done by device")
241        .precision(0)
242        .prereq(txBytes)
243        ;
244
245    txTcpChecksums
246        .name(name() + ".txTcpChecksums")
247        .desc("Number of tx TCP Checksums done by device")
248        .precision(0)
249        .prereq(txBytes)
250        ;
251
252    txUdpChecksums
253        .name(name() + ".txUdpChecksums")
254        .desc("Number of tx UDP Checksums done by device")
255        .precision(0)
256        .prereq(txBytes)
257        ;
258
259    txBandwidth = txBytes * Stats::constant(8) / simSeconds;
260    rxBandwidth = rxBytes * Stats::constant(8) / simSeconds;
261    txPacketRate = txPackets / simSeconds;
262    rxPacketRate = rxPackets / simSeconds;
263}
264
265/**
266 * This is to write to the PCI general configuration registers
267 */
268void
269Device::WriteConfig(int offset, int size, uint32_t data)
270{
271    switch (offset) {
272      case PCI0_BASE_ADDR0:
273        // Need to catch writes to BARs to update the PIO interface
274        PciDev::WriteConfig(offset, size, data);
275        if (BARAddrs[0] != 0) {
276            if (pioInterface)
277                pioInterface->addAddrRange(RangeSize(BARAddrs[0], BARSize[0]));
278
279            BARAddrs[0] &= EV5::PAddrUncachedMask;
280        }
281        break;
282
283      default:
284        PciDev::WriteConfig(offset, size, data);
285    }
286}
287
288/**
289 * This reads the device registers, which are detailed in the NS83820
290 * spec sheet
291 */
292Fault
293Device::read(MemReqPtr &req, uint8_t *data)
294{
295    assert(config.hdr.command & PCI_CMD_MSE);
296
297    //The mask is to give you only the offset into the device register file
298    Addr daddr = req->paddr & 0xfff;
299
300    if (Regs::regSize(daddr) == 0)
301        panic("invalid address: da=%#x pa=%#x va=%#x size=%d",
302              daddr, req->paddr, req->vaddr, req->size);
303
304    if (req->size != Regs::regSize(daddr))
305        panic("invalid size for reg %s: da=%#x pa=%#x va=%#x size=%d",
306              Regs::regName(daddr), daddr, req->paddr, req->vaddr, req->size);
307
308    DPRINTF(EthernetPIO, "read reg=%s da=%#x pa=%#x va=%#x size=%d\n",
309            Regs::regName(daddr), daddr, req->paddr, req->vaddr, req->size);
310
311    uint32_t &reg32 = *(uint32_t *)data;
312    uint64_t &reg64 = *(uint64_t *)data;
313
314    switch (daddr) {
315      case Regs::Config:
316        reg32 = regs.Config;
317        break;
318
319      case Regs::RxMaxCopy:
320        reg32 = regs.RxMaxCopy;
321        break;
322
323      case Regs::TxMaxCopy:
324        reg32 = regs.TxMaxCopy;
325        break;
326
327      case Regs::RxThreshold:
328        reg32 = regs.RxThreshold;
329        break;
330
331      case Regs::TxThreshold:
332        reg32 = regs.TxThreshold;
333        break;
334
335      case Regs::IntrStatus:
336        reg32 = regs.IntrStatus;
337        devIntrClear();
338        break;
339
340      case Regs::IntrMask:
341        reg32 = regs.IntrMask;
342        break;
343
344      case Regs::RxData:
345        reg64 = regs.RxData;
346        break;
347
348      case Regs::RxDone:
349      case Regs::RxWait:
350        reg64 = Regs::set_RxDone_FifoLen(regs.RxDone,
351                                         min(rxFifo.packets(), 255));
352        break;
353
354      case Regs::TxData:
355        reg64 = regs.TxData;
356        break;
357
358      case Regs::TxDone:
359      case Regs::TxWait:
360        reg64 = Regs::set_TxDone_FifoLen(regs.TxDone,
361                                         min(txFifo.packets(), 255));
362        break;
363
364      case Regs::HwAddr:
365        reg64 = params()->eaddr;
366        break;
367
368      default:
369        panic("reading write only register %s: da=%#x pa=%#x va=%#x size=%d",
370              Regs::regName(daddr), daddr, req->paddr, req->vaddr, req->size);
371    }
372
373    DPRINTF(EthernetPIO, "read reg=%s done val=%#x\n", Regs::regName(daddr),
374            Regs::regSize(daddr) == 4 ? reg32 : reg64);
375
376    return No_Fault;
377}
378
379Fault
380Device::write(MemReqPtr &req, const uint8_t *data)
381{
382    assert(config.hdr.command & PCI_CMD_MSE);
383    Addr daddr = req->paddr & 0xfff;
384
385    if (Regs::regSize(daddr) == 0)
386        panic("invalid address: da=%#x pa=%#x va=%#x size=%d",
387              daddr, req->paddr, req->vaddr, req->size);
388
389    if (req->size != Regs::regSize(daddr))
390        panic("invalid size: reg=%s da=%#x pa=%#x va=%#x size=%d",
391              Regs::regName(daddr), daddr, req->paddr, req->vaddr, req->size);
392
393    uint32_t reg32 = *(uint32_t *)data;
394    uint64_t reg64 = *(uint64_t *)data;
395
396    DPRINTF(EthernetPIO, "write reg=%s val=%#x da=%#x pa=%#x va=%#x size=%d\n",
397            Regs::regName(daddr), Regs::regSize(daddr) == 4 ? reg32 : reg64,
398            daddr, req->paddr, req->vaddr, req->size);
399
400
401    switch (daddr) {
402      case Regs::Config:
403        changeConfig(reg32);
404        break;
405
406      case Regs::RxThreshold:
407        regs.RxThreshold = reg32;
408        break;
409
410      case Regs::TxThreshold:
411        regs.TxThreshold = reg32;
412        break;
413
414      case Regs::IntrMask:
415        devIntrChangeMask(reg32);
416        break;
417
418      case Regs::RxData:
419        if (rxState != rxIdle)
420            panic("receive machine busy with another request!");
421
422        regs.RxDone = 0;
423        regs.RxData = reg64;
424        if (rxEnable) {
425            rxState = rxFifoBlock;
426            rxKick();
427        }
428        break;
429
430      case Regs::TxData:
431        if (txState != txIdle)
432            panic("transmit machine busy with another request!");
433
434        regs.TxDone = 0;
435        regs.TxData = reg64;
436        if (txEnable) {
437            txState = txFifoBlock;
438            txKick();
439        }
440        break;
441
442      default:
443        panic("writing read only register %s: da=%#x pa=%#x va=%#x size=%d",
444              Regs::regName(daddr), daddr, req->paddr, req->vaddr, req->size);
445    }
446
447    return No_Fault;
448}
449
450void
451Device::devIntrPost(uint32_t interrupts)
452{
453    if ((interrupts & Regs::Intr_Res))
454        panic("Cannot set a reserved interrupt");
455
456    regs.IntrStatus |= interrupts;
457
458    DPRINTF(EthernetIntr,
459            "interrupt written to intStatus: intr=%#x status=%#x mask=%#x\n",
460            interrupts, regs.IntrStatus, regs.IntrMask);
461
462    if ((regs.IntrStatus & regs.IntrMask)) {
463        Tick when = curTick;
464        if ((regs.IntrStatus & regs.IntrMask & Regs::Intr_NoDelay) == 0)
465            when += intrDelay;
466        cpuIntrPost(when);
467    }
468}
469
470void
471Device::devIntrClear(uint32_t interrupts)
472{
473    if ((interrupts & Regs::Intr_Res))
474        panic("Cannot clear a reserved interrupt");
475
476    regs.IntrStatus &= ~interrupts;
477
478    DPRINTF(EthernetIntr,
479            "interrupt cleared from intStatus: intr=%x status=%x mask=%x\n",
480            interrupts, regs.IntrStatus, regs.IntrMask);
481
482    if (!(regs.IntrStatus & regs.IntrMask))
483        cpuIntrClear();
484}
485
486void
487Device::devIntrChangeMask(uint32_t newmask)
488{
489    if (regs.IntrMask == newmask)
490        return;
491
492    regs.IntrMask = newmask;
493
494    DPRINTF(EthernetIntr,
495            "interrupt mask changed: intStatus=%x intMask=%x masked=%x\n",
496            regs.IntrStatus, regs.IntrMask, regs.IntrStatus & regs.IntrMask);
497
498    if (regs.IntrStatus & regs.IntrMask)
499        cpuIntrPost(curTick);
500    else
501        cpuIntrClear();
502}
503
504void
505Base::cpuIntrPost(Tick when)
506{
507    // If the interrupt you want to post is later than an interrupt
508    // already scheduled, just let it post in the coming one and don't
509    // schedule another.
510    // HOWEVER, must be sure that the scheduled intrTick is in the
511    // future (this was formerly the source of a bug)
512    /**
513     * @todo this warning should be removed and the intrTick code should
514     * be fixed.
515     */
516    assert(when >= curTick);
517    assert(intrTick >= curTick || intrTick == 0);
518    if (!cpuIntrEnable) {
519        DPRINTF(EthernetIntr, "interrupts not enabled.\n",
520                intrTick);
521        return;
522    }
523
524    if (when > intrTick && intrTick != 0) {
525        DPRINTF(EthernetIntr, "don't need to schedule event...intrTick=%d\n",
526                intrTick);
527        return;
528    }
529
530    intrTick = when;
531    if (intrTick < curTick) {
532        debug_break();
533        intrTick = curTick;
534    }
535
536    DPRINTF(EthernetIntr, "going to schedule an interrupt for intrTick=%d\n",
537            intrTick);
538
539    if (intrEvent)
540        intrEvent->squash();
541    intrEvent = new IntrEvent(this, true);
542    intrEvent->schedule(intrTick);
543}
544
545void
546Base::cpuInterrupt()
547{
548    assert(intrTick == curTick);
549
550    // Whether or not there's a pending interrupt, we don't care about
551    // it anymore
552    intrEvent = 0;
553    intrTick = 0;
554
555    // Don't send an interrupt if there's already one
556    if (cpuPendingIntr) {
557        DPRINTF(EthernetIntr,
558                "would send an interrupt now, but there's already pending\n");
559    } else {
560        // Send interrupt
561        cpuPendingIntr = true;
562
563        DPRINTF(EthernetIntr, "posting interrupt\n");
564        intrPost();
565    }
566}
567
568void
569Base::cpuIntrClear()
570{
571    if (!cpuPendingIntr)
572        return;
573
574    if (intrEvent) {
575        intrEvent->squash();
576        intrEvent = 0;
577    }
578
579    intrTick = 0;
580
581    cpuPendingIntr = false;
582
583    DPRINTF(EthernetIntr, "clearing cchip interrupt\n");
584    intrClear();
585}
586
587bool
588Base::cpuIntrPending() const
589{ return cpuPendingIntr; }
590
591void
592Device::changeConfig(uint32_t newconf)
593{
594    uint32_t changed = regs.Config ^ newconf;
595    if (!changed)
596        return;
597
598    regs.Config = newconf;
599
600    if ((changed & Regs::Config_Reset)) {
601        assert(regs.Config & Regs::Config_Reset);
602        reset();
603        regs.Config &= ~Regs::Config_Reset;
604    }
605
606    if ((changed & Regs::Config_IntEn)) {
607        cpuIntrEnable = regs.Config & Regs::Config_IntEn;
608        if (cpuIntrEnable) {
609            if (regs.IntrStatus & regs.IntrMask)
610                cpuIntrPost(curTick);
611        } else {
612            cpuIntrClear();
613        }
614    }
615
616    if ((changed & Regs::Config_TxEn)) {
617        txEnable = regs.Config & Regs::Config_TxEn;
618        if (txEnable)
619            txKick();
620    }
621
622    if ((changed & Regs::Config_RxEn)) {
623        rxEnable = regs.Config & Regs::Config_RxEn;
624        if (rxEnable)
625            rxKick();
626    }
627}
628
629void
630Device::reset()
631{
632    using namespace Regs;
633    memset(&regs, 0, sizeof(regs));
634    regs.RxMaxCopy = params()->rx_max_copy;
635    regs.TxMaxCopy = params()->tx_max_copy;
636    regs.IntrMask = Intr_TxFifo | Intr_RxFifo | Intr_RxData;
637
638    rxState = rxIdle;
639    txState = txIdle;
640
641    rxFifo.clear();
642    txFifo.clear();
643}
644
645void
646Device::rxDmaCopy()
647{
648    assert(rxState == rxCopy);
649    rxState = rxCopyDone;
650    physmem->dma_write(rxDmaAddr, (uint8_t *)rxDmaData, rxDmaLen);
651    DPRINTF(EthernetDMA, "rx dma write paddr=%#x len=%d\n",
652            rxDmaAddr, rxDmaLen);
653    DDUMP(EthernetDMA, rxDmaData, rxDmaLen);
654}
655
656void
657Device::rxDmaDone()
658{
659    rxDmaCopy();
660    rxKick();
661}
662
663void
664Device::rxKick()
665{
666    DPRINTF(EthernetSM, "receive kick rxState=%s (rxFifo.size=%d)\n",
667            RxStateStrings[rxState], rxFifo.size());
668
669    if (rxKickTick > curTick) {
670        DPRINTF(EthernetSM, "receive kick exiting, can't run till %d\n",
671                rxKickTick);
672        return;
673    }
674
675  next:
676    switch (rxState) {
677      case rxIdle:
678        if (rxPioRequest) {
679            pioInterface->respond(rxPioRequest, curTick);
680            rxPioRequest = 0;
681        }
682        goto exit;
683
684      case rxFifoBlock:
685        if (rxPacket) {
686            rxState = rxBeginCopy;
687            break;
688        }
689
690        if (rxFifo.empty()) {
691            DPRINTF(EthernetSM, "receive waiting for data.  Nothing to do.\n");
692            goto exit;
693        }
694
695        // Grab a new packet from the fifo.
696        rxPacket = rxFifo.front();
697        rxPacketBufPtr = rxPacket->data;
698        rxPktBytes = rxPacket->length;
699        assert(rxPktBytes);
700
701        rxDoneData = 0;
702        /* scope for variables */ {
703            IpPtr ip(rxPacket);
704            if (ip) {
705                rxDoneData |= Regs::RxDone_IpPacket;
706                rxIpChecksums++;
707                if (cksum(ip) != 0) {
708                    DPRINTF(EthernetCksum, "Rx IP Checksum Error\n");
709                    rxDoneData |= Regs::RxDone_IpError;
710                }
711                TcpPtr tcp(ip);
712                UdpPtr udp(ip);
713                if (tcp) {
714                    rxDoneData |= Regs::RxDone_TcpPacket;
715                    rxTcpChecksums++;
716                    if (cksum(tcp) != 0) {
717                        DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n");
718                        rxDoneData |= Regs::RxDone_TcpError;
719                    }
720                } else if (udp) {
721                    rxDoneData |= Regs::RxDone_UdpPacket;
722                    rxUdpChecksums++;
723                    if (cksum(udp) != 0) {
724                        DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n");
725                        rxDoneData |= Regs::RxDone_UdpError;
726                    }
727                }
728            }
729        }
730        rxState = rxBeginCopy;
731        break;
732
733      case rxBeginCopy:
734        rxDmaAddr = plat->pciToDma(Regs::get_RxData_Addr(regs.RxData));
735        rxDmaLen = min<int>(Regs::get_RxData_Len(regs.RxData), rxPktBytes);
736        rxDmaData = rxPacketBufPtr;
737
738        if (dmaInterface) {
739            if (!dmaInterface->busy()) {
740                dmaInterface->doDMA(WriteInvalidate, rxDmaAddr, rxDmaLen,
741                                    curTick, &rxDmaEvent, true);
742                rxState = rxCopy;
743            }
744            goto exit;
745        }
746
747        rxState = rxCopy;
748        if (dmaWriteDelay != 0 || dmaWriteFactor != 0) {
749            Tick factor = ((rxDmaLen + ULL(63)) >> ULL(6)) * dmaWriteFactor;
750            Tick start = curTick + dmaWriteDelay + factor;
751            rxDmaEvent.schedule(start);
752            goto exit;
753        }
754
755        rxDmaCopy();
756        break;
757
758      case rxCopy:
759        DPRINTF(EthernetSM, "receive machine still copying\n");
760        goto exit;
761
762      case rxCopyDone:
763        regs.RxDone = rxDoneData | rxDmaLen;
764
765        if (rxPktBytes == rxDmaLen) {
766            rxPacket = NULL;
767            rxFifo.pop();
768        } else {
769            regs.RxDone |= Regs::RxDone_More;
770            rxPktBytes -= rxDmaLen;
771            rxPacketBufPtr += rxDmaLen;
772        }
773
774        regs.RxDone |= Regs::RxDone_Complete;
775        devIntrPost(Regs::Intr_RxData);
776        rxState = rxIdle;
777        break;
778
779      default:
780        panic("Invalid rxState!");
781    }
782
783    DPRINTF(EthernetSM, "entering next rxState=%s\n",
784            RxStateStrings[rxState]);
785
786    goto next;
787
788  exit:
789    /**
790     * @todo do we want to schedule a future kick?
791     */
792    DPRINTF(EthernetSM, "rx state machine exited rxState=%s\n",
793            RxStateStrings[rxState]);
794}
795
796void
797Device::txDmaCopy()
798{
799    assert(txState == txCopy);
800    txState = txCopyDone;
801    physmem->dma_read((uint8_t *)txDmaData, txDmaAddr, txDmaLen);
802    DPRINTF(EthernetDMA, "tx dma read paddr=%#x len=%d\n",
803            txDmaAddr, txDmaLen);
804    DDUMP(EthernetDMA, txDmaData, txDmaLen);
805}
806
807void
808Device::txDmaDone()
809{
810    txDmaCopy();
811    txKick();
812}
813
814void
815Device::transmit()
816{
817    if (txFifo.empty()) {
818        DPRINTF(Ethernet, "nothing to transmit\n");
819        return;
820    }
821
822    PacketPtr packet = txFifo.front();
823    if (!interface->sendPacket(packet)) {
824        DPRINTF(Ethernet, "Packet Transmit: failed txFifo available %d\n",
825                txFifo.avail());
826        goto reschedule;
827    }
828
829    txFifo.pop();
830
831#if TRACING_ON
832    if (DTRACE(Ethernet)) {
833        IpPtr ip(packet);
834        if (ip) {
835            DPRINTF(Ethernet, "ID is %d\n", ip->id());
836            TcpPtr tcp(ip);
837            if (tcp) {
838                DPRINTF(Ethernet, "Src Port=%d, Dest Port=%d\n",
839                        tcp->sport(), tcp->dport());
840            }
841        }
842    }
843#endif
844
845    DDUMP(Ethernet, packet->data, packet->length);
846    txBytes += packet->length;
847    txPackets++;
848
849    DPRINTF(Ethernet, "Packet Transmit: successful txFifo Available %d\n",
850            txFifo.avail());
851
852    if (txFifo.size() <= params()->tx_fifo_threshold)
853        devIntrPost(Regs::Intr_TxFifo);
854
855    devIntrPost(Regs::Intr_TxDone);
856
857  reschedule:
858   if (!txFifo.empty() && !txEvent.scheduled()) {
859       DPRINTF(Ethernet, "reschedule transmit\n");
860       txEvent.schedule(curTick + 1000);
861   }
862}
863
864void
865Device::txKick()
866{
867    DPRINTF(EthernetSM, "transmit kick txState=%s (txFifo.size=%d)\n",
868            TxStateStrings[txState], txFifo.size());
869
870    if (txKickTick > curTick) {
871        DPRINTF(EthernetSM, "transmit kick exiting, can't run till %d\n",
872                txKickTick);
873        return;
874    }
875
876  next:
877    switch (txState) {
878      case txIdle:
879        if (txPioRequest) {
880            pioInterface->respond(txPioRequest, curTick + pioLatency);
881            txPioRequest = 0;
882        }
883        goto exit;
884
885      case txFifoBlock:
886        if (!txPacket) {
887            // Grab a new packet from the fifo.
888            txPacket = new PacketData(16384);
889            txPacketBufPtr = txPacket->data;
890        }
891
892        if (txFifo.avail() - txPacket->length <
893            Regs::get_TxData_Len(regs.TxData)) {
894            DPRINTF(EthernetSM, "transmit fifo full.  Nothing to do.\n");
895            goto exit;
896        }
897
898        txState = txBeginCopy;
899        break;
900
901      case txBeginCopy:
902        txDmaAddr = plat->pciToDma(Regs::get_TxData_Addr(regs.TxData));
903        txDmaLen = Regs::get_TxData_Len(regs.TxData);
904        txDmaData = txPacketBufPtr;
905
906        if (dmaInterface) {
907            if (!dmaInterface->busy()) {
908                dmaInterface->doDMA(Read, txDmaAddr, txDmaLen,
909                                    curTick, &txDmaEvent, true);
910                txState = txCopy;
911            }
912
913            goto exit;
914        }
915
916        txState = txCopy;
917        if (dmaReadDelay != 0 || dmaReadFactor != 0) {
918            Tick factor = ((txDmaLen + ULL(63)) >> ULL(6)) * dmaReadFactor;
919            Tick start = curTick + dmaReadDelay + factor;
920            txDmaEvent.schedule(start);
921            goto exit;
922        }
923
924        txDmaCopy();
925        break;
926
927      case txCopy:
928        DPRINTF(EthernetSM, "transmit machine still copying\n");
929        goto exit;
930
931      case txCopyDone:
932        txPacket->length += txDmaLen;
933        if ((regs.TxData & Regs::TxData_More)) {
934            txPacketBufPtr += txDmaLen;
935        } else {
936            assert(txPacket->length <= txFifo.avail());
937            if ((regs.TxData & Regs::TxData_Checksum)) {
938                IpPtr ip(txPacket);
939                if (ip) {
940                    TcpPtr tcp(ip);
941                    if (tcp) {
942                        tcp->sum(0);
943                        tcp->sum(cksum(tcp));
944                        txTcpChecksums++;
945                    }
946
947                    UdpPtr udp(ip);
948                    if (udp) {
949                        udp->sum(0);
950                        udp->sum(cksum(udp));
951                        txUdpChecksums++;
952                    }
953
954                    ip->sum(0);
955                    ip->sum(cksum(ip));
956                    txIpChecksums++;
957                }
958            }
959            txFifo.push(txPacket);
960            txPacket = 0;
961            transmit();
962        }
963
964        regs.TxDone = txDmaLen | Regs::TxDone_Complete;
965        devIntrPost(Regs::Intr_TxData);
966        txState = txIdle;
967        break;
968
969      default:
970        panic("Invalid txState!");
971    }
972
973    DPRINTF(EthernetSM, "entering next txState=%s\n",
974            TxStateStrings[txState]);
975
976    goto next;
977
978  exit:
979    /**
980     * @todo do we want to schedule a future kick?
981     */
982    DPRINTF(EthernetSM, "tx state machine exited txState=%s\n",
983            TxStateStrings[txState]);
984}
985
986void
987Device::transferDone()
988{
989    if (txFifo.empty()) {
990        DPRINTF(Ethernet, "transfer complete: txFifo empty...nothing to do\n");
991        return;
992    }
993
994    DPRINTF(Ethernet, "transfer complete: data in txFifo...schedule xmit\n");
995
996    if (txEvent.scheduled())
997        txEvent.reschedule(curTick + 1);
998    else
999        txEvent.schedule(curTick + 1);
1000}
1001
1002bool
1003Device::rxFilter(const PacketPtr &packet)
1004{
1005    if (!Regs::get_Config_Filter(regs.Config))
1006        return false;
1007
1008    panic("receive filter not implemented\n");
1009    bool drop = true;
1010
1011#if 0
1012    string type;
1013
1014    EthHdr *eth = packet->eth();
1015    if (eth->unicast()) {
1016        // If we're accepting all unicast addresses
1017        if (acceptUnicast)
1018            drop = false;
1019
1020        // If we make a perfect match
1021        if (acceptPerfect && params->eaddr == eth.dst())
1022            drop = false;
1023
1024        if (acceptArp && eth->type() == ETH_TYPE_ARP)
1025            drop = false;
1026
1027    } else if (eth->broadcast()) {
1028        // if we're accepting broadcasts
1029        if (acceptBroadcast)
1030            drop = false;
1031
1032    } else if (eth->multicast()) {
1033        // if we're accepting all multicasts
1034        if (acceptMulticast)
1035            drop = false;
1036
1037    }
1038
1039    if (drop) {
1040        DPRINTF(Ethernet, "rxFilter drop\n");
1041        DDUMP(EthernetData, packet->data, packet->length);
1042    }
1043#endif
1044    return drop;
1045}
1046
1047bool
1048Device::recvPacket(PacketPtr packet)
1049{
1050    rxBytes += packet->length;
1051    rxPackets++;
1052
1053    DPRINTF(Ethernet, "Receiving packet from wire, rxFifo Available is %d\n",
1054            rxFifo.avail());
1055
1056    if (!rxEnable) {
1057        DPRINTF(Ethernet, "receive disabled...packet dropped\n");
1058        interface->recvDone();
1059        return true;
1060    }
1061
1062    if (rxFilter(packet)) {
1063        DPRINTF(Ethernet, "packet filtered...dropped\n");
1064        interface->recvDone();
1065        return true;
1066    }
1067
1068    if (rxFifo.size() >= params()->rx_fifo_threshold)
1069        devIntrPost(Regs::Intr_RxFifo);
1070
1071    if (!rxFifo.push(packet)) {
1072        DPRINTF(Ethernet,
1073                "packet will not fit in receive buffer...packet dropped\n");
1074        return false;
1075    }
1076
1077    interface->recvDone();
1078    devIntrPost(Regs::Intr_RxDone);
1079    rxKick();
1080    return true;
1081}
1082
1083//=====================================================================
1084//
1085//
1086void
1087Base::serialize(ostream &os)
1088{
1089    // Serialize the PciDev base class
1090    PciDev::serialize(os);
1091
1092    SERIALIZE_SCALAR(rxEnable);
1093    SERIALIZE_SCALAR(txEnable);
1094    SERIALIZE_SCALAR(cpuIntrEnable);
1095
1096    /*
1097     * Keep track of pending interrupt status.
1098     */
1099    SERIALIZE_SCALAR(intrTick);
1100    SERIALIZE_SCALAR(cpuPendingIntr);
1101    Tick intrEventTick = 0;
1102    if (intrEvent)
1103        intrEventTick = intrEvent->when();
1104    SERIALIZE_SCALAR(intrEventTick);
1105}
1106
1107void
1108Base::unserialize(Checkpoint *cp, const std::string &section)
1109{
1110    // Unserialize the PciDev base class
1111    PciDev::unserialize(cp, section);
1112
1113    UNSERIALIZE_SCALAR(rxEnable);
1114    UNSERIALIZE_SCALAR(txEnable);
1115    UNSERIALIZE_SCALAR(cpuIntrEnable);
1116
1117    /*
1118     * Keep track of pending interrupt status.
1119     */
1120    UNSERIALIZE_SCALAR(intrTick);
1121    UNSERIALIZE_SCALAR(cpuPendingIntr);
1122    Tick intrEventTick;
1123    UNSERIALIZE_SCALAR(intrEventTick);
1124    if (intrEventTick) {
1125        intrEvent = new IntrEvent(this, true);
1126        intrEvent->schedule(intrEventTick);
1127    }
1128}
1129
1130void
1131Device::serialize(ostream &os)
1132{
1133    // Serialize the PciDev base class
1134    Base::serialize(os);
1135
1136    if (rxDmaEvent.scheduled())
1137        rxDmaCopy();
1138
1139    if (txDmaEvent.scheduled())
1140        txDmaCopy();
1141
1142    /*
1143     * Serialize the device registers
1144     */
1145    SERIALIZE_SCALAR(regs.Config);
1146    SERIALIZE_SCALAR(regs.RxMaxCopy);
1147    SERIALIZE_SCALAR(regs.TxMaxCopy);
1148    SERIALIZE_SCALAR(regs.RxThreshold);
1149    SERIALIZE_SCALAR(regs.TxThreshold);
1150    SERIALIZE_SCALAR(regs.IntrStatus);
1151    SERIALIZE_SCALAR(regs.IntrMask);
1152    SERIALIZE_SCALAR(regs.RxData);
1153    SERIALIZE_SCALAR(regs.RxDone);
1154    SERIALIZE_SCALAR(regs.TxData);
1155    SERIALIZE_SCALAR(regs.TxDone);
1156
1157    /*
1158     * Serialize rx state machine
1159     */
1160    int rxState = this->rxState;
1161    SERIALIZE_SCALAR(rxState);
1162    rxFifo.serialize("rxFifo", os);
1163    bool rxPacketExists = rxPacket;
1164    SERIALIZE_SCALAR(rxPacketExists);
1165    if (rxPacketExists) {
1166        rxPacket->serialize("rxPacket", os);
1167        uint32_t rxPktBufPtr = (uint32_t) (rxPacketBufPtr - rxPacket->data);
1168        SERIALIZE_SCALAR(rxPktBufPtr);
1169        SERIALIZE_SCALAR(rxPktBytes);
1170    }
1171    SERIALIZE_SCALAR(rxDoneData);
1172
1173    /*
1174     * Serialize tx state machine
1175     */
1176    int txState = this->txState;
1177    SERIALIZE_SCALAR(txState);
1178    txFifo.serialize("txFifo", os);
1179    bool txPacketExists = txPacket;
1180    SERIALIZE_SCALAR(txPacketExists);
1181    if (txPacketExists) {
1182        txPacket->serialize("txPacket", os);
1183        uint32_t txPktBufPtr = (uint32_t) (txPacketBufPtr - txPacket->data);
1184        SERIALIZE_SCALAR(txPktBufPtr);
1185        SERIALIZE_SCALAR(txPktBytes);
1186    }
1187
1188    /*
1189     * If there's a pending transmit, store the time so we can
1190     * reschedule it later
1191     */
1192    Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick : 0;
1193    SERIALIZE_SCALAR(transmitTick);
1194}
1195
1196void
1197Device::unserialize(Checkpoint *cp, const std::string &section)
1198{
1199    // Unserialize the PciDev base class
1200    Base::unserialize(cp, section);
1201
1202    /*
1203     * Unserialize the device registers
1204     */
1205    UNSERIALIZE_SCALAR(regs.Config);
1206    UNSERIALIZE_SCALAR(regs.RxMaxCopy);
1207    UNSERIALIZE_SCALAR(regs.TxMaxCopy);
1208    UNSERIALIZE_SCALAR(regs.RxThreshold);
1209    UNSERIALIZE_SCALAR(regs.TxThreshold);
1210    UNSERIALIZE_SCALAR(regs.IntrStatus);
1211    UNSERIALIZE_SCALAR(regs.IntrMask);
1212    UNSERIALIZE_SCALAR(regs.RxData);
1213    UNSERIALIZE_SCALAR(regs.RxDone);
1214    UNSERIALIZE_SCALAR(regs.TxData);
1215    UNSERIALIZE_SCALAR(regs.TxDone);
1216
1217    /*
1218     * Unserialize rx state machine
1219     */
1220    int rxState;
1221    UNSERIALIZE_SCALAR(rxState);
1222    this->rxState = (RxState) rxState;
1223    rxFifo.unserialize("rxFifo", cp, section);
1224    bool rxPacketExists;
1225    UNSERIALIZE_SCALAR(rxPacketExists);
1226    rxPacket = 0;
1227    if (rxPacketExists) {
1228        rxPacket = new PacketData;
1229        rxPacket->unserialize("rxPacket", cp, section);
1230        uint32_t rxPktBufPtr;
1231        UNSERIALIZE_SCALAR(rxPktBufPtr);
1232        this->rxPacketBufPtr = (uint8_t *) rxPacket->data + rxPktBufPtr;
1233        UNSERIALIZE_SCALAR(rxPktBytes);
1234    }
1235    UNSERIALIZE_SCALAR(rxDoneData);
1236
1237    /*
1238     * Unserialize tx state machine
1239     */
1240    int txState;
1241    UNSERIALIZE_SCALAR(txState);
1242    this->txState = (TxState) txState;
1243    txFifo.unserialize("txFifo", cp, section);
1244    bool txPacketExists;
1245    UNSERIALIZE_SCALAR(txPacketExists);
1246    txPacket = 0;
1247    if (txPacketExists) {
1248        txPacket = new PacketData;
1249        txPacket->unserialize("txPacket", cp, section);
1250        uint32_t txPktBufPtr;
1251        UNSERIALIZE_SCALAR(txPktBufPtr);
1252        this->txPacketBufPtr = (uint8_t *) txPacket->data + txPktBufPtr;
1253        UNSERIALIZE_SCALAR(txPktBytes);
1254    }
1255
1256    /*
1257     * If there's a pending transmit, reschedule it now
1258     */
1259    Tick transmitTick;
1260    UNSERIALIZE_SCALAR(transmitTick);
1261    if (transmitTick)
1262        txEvent.schedule(curTick + transmitTick);
1263
1264    /*
1265     * re-add addrRanges to bus bridges
1266     */
1267    if (pioInterface) {
1268        pioInterface->addAddrRange(RangeSize(BARAddrs[0], BARSize[0]));
1269        pioInterface->addAddrRange(RangeSize(BARAddrs[1], BARSize[1]));
1270    }
1271}
1272
1273Tick
1274Device::cacheAccess(MemReqPtr &req)
1275{
1276    //The mask is to give you only the offset into the device register file
1277    Addr daddr = req->paddr - addr;
1278
1279    DPRINTF(EthernetPIO, "timing access to paddr=%#x (daddr=%#x)\n",
1280            req->paddr, daddr);
1281
1282    Tick when = curTick + pioLatency;
1283
1284    switch (daddr) {
1285      case Regs::RxDone:
1286        if (rxState != rxIdle) {
1287            rxPioRequest = req;
1288            when = 0;
1289        }
1290        break;
1291
1292      case Regs::TxDone:
1293        if (txState != txIdle) {
1294            txPioRequest = req;
1295            when = 0;
1296        }
1297        break;
1298    }
1299
1300    return when;
1301}
1302
1303BEGIN_DECLARE_SIM_OBJECT_PARAMS(Interface)
1304
1305    SimObjectParam<EtherInt *> peer;
1306    SimObjectParam<Device *> device;
1307
1308END_DECLARE_SIM_OBJECT_PARAMS(Interface)
1309
1310BEGIN_INIT_SIM_OBJECT_PARAMS(Interface)
1311
1312    INIT_PARAM_DFLT(peer, "peer interface", NULL),
1313    INIT_PARAM(device, "Ethernet device of this interface")
1314
1315END_INIT_SIM_OBJECT_PARAMS(Interface)
1316
1317CREATE_SIM_OBJECT(Interface)
1318{
1319    Interface *dev_int = new Interface(getInstanceName(), device);
1320
1321    EtherInt *p = (EtherInt *)peer;
1322    if (p) {
1323        dev_int->setPeer(p);
1324        p->setPeer(dev_int);
1325    }
1326
1327    return dev_int;
1328}
1329
1330REGISTER_SIM_OBJECT("SinicInt", Interface)
1331
1332
1333BEGIN_DECLARE_SIM_OBJECT_PARAMS(Device)
1334
1335    Param<Tick> tx_delay;
1336    Param<Tick> rx_delay;
1337    Param<Tick> intr_delay;
1338    SimObjectParam<MemoryController *> mmu;
1339    SimObjectParam<PhysicalMemory *> physmem;
1340    Param<bool> rx_filter;
1341    Param<string> hardware_address;
1342    SimObjectParam<Bus*> header_bus;
1343    SimObjectParam<Bus*> payload_bus;
1344    SimObjectParam<HierParams *> hier;
1345    Param<Tick> pio_latency;
1346    SimObjectParam<PciConfigAll *> configspace;
1347    SimObjectParam<PciConfigData *> configdata;
1348    SimObjectParam<Platform *> platform;
1349    Param<uint32_t> pci_bus;
1350    Param<uint32_t> pci_dev;
1351    Param<uint32_t> pci_func;
1352    Param<uint32_t> rx_max_copy;
1353    Param<uint32_t> tx_max_copy;
1354    Param<uint32_t> rx_fifo_size;
1355    Param<uint32_t> tx_fifo_size;
1356    Param<uint32_t> rx_fifo_threshold;
1357    Param<uint32_t> tx_fifo_threshold;
1358    Param<Tick> dma_read_delay;
1359    Param<Tick> dma_read_factor;
1360    Param<Tick> dma_write_delay;
1361    Param<Tick> dma_write_factor;
1362
1363END_DECLARE_SIM_OBJECT_PARAMS(Device)
1364
1365BEGIN_INIT_SIM_OBJECT_PARAMS(Device)
1366
1367    INIT_PARAM_DFLT(tx_delay, "Transmit Delay", 1000),
1368    INIT_PARAM_DFLT(rx_delay, "Receive Delay", 1000),
1369    INIT_PARAM_DFLT(intr_delay, "Interrupt Delay in microseconds", 0),
1370    INIT_PARAM(mmu, "Memory Controller"),
1371    INIT_PARAM(physmem, "Physical Memory"),
1372    INIT_PARAM_DFLT(rx_filter, "Enable Receive Filter", true),
1373    INIT_PARAM_DFLT(hardware_address, "Ethernet Hardware Address",
1374                    "00:99:00:00:00:01"),
1375    INIT_PARAM_DFLT(header_bus, "The IO Bus to attach to for headers", NULL),
1376    INIT_PARAM_DFLT(payload_bus, "The IO Bus to attach to for payload", NULL),
1377    INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams),
1378    INIT_PARAM_DFLT(pio_latency, "Programmed IO latency in bus cycles", 1),
1379    INIT_PARAM(configspace, "PCI Configspace"),
1380    INIT_PARAM(configdata, "PCI Config data"),
1381    INIT_PARAM(platform, "Platform"),
1382    INIT_PARAM(pci_bus, "PCI bus"),
1383    INIT_PARAM(pci_dev, "PCI device number"),
1384    INIT_PARAM(pci_func, "PCI function code"),
1385    INIT_PARAM_DFLT(rx_max_copy, "rx max copy", 16*1024),
1386    INIT_PARAM_DFLT(tx_max_copy, "rx max copy", 16*1024),
1387    INIT_PARAM_DFLT(rx_fifo_size, "max size in bytes of rxFifo", 64*1024),
1388    INIT_PARAM_DFLT(tx_fifo_size, "max size in bytes of txFifo", 64*1024),
1389    INIT_PARAM_DFLT(rx_fifo_threshold, "max size in bytes of rxFifo", 48*1024),
1390    INIT_PARAM_DFLT(tx_fifo_threshold, "max size in bytes of txFifo", 16*1024),
1391    INIT_PARAM_DFLT(dma_read_delay, "fixed delay for dma reads", 0),
1392    INIT_PARAM_DFLT(dma_read_factor, "multiplier for dma reads", 0),
1393    INIT_PARAM_DFLT(dma_write_delay, "fixed delay for dma writes", 0),
1394    INIT_PARAM_DFLT(dma_write_factor, "multiplier for dma writes", 0)
1395
1396END_INIT_SIM_OBJECT_PARAMS(Device)
1397
1398
1399CREATE_SIM_OBJECT(Device)
1400{
1401    Device::Params *params = new Device::Params;
1402    params->name = getInstanceName();
1403    params->intr_delay = intr_delay;
1404    params->physmem = physmem;
1405    params->tx_delay = tx_delay;
1406    params->rx_delay = rx_delay;
1407    params->mmu = mmu;
1408    params->hier = hier;
1409    params->header_bus = header_bus;
1410    params->payload_bus = payload_bus;
1411    params->pio_latency = pio_latency;
1412    params->configSpace = configspace;
1413    params->configData = configdata;
1414    params->plat = platform;
1415    params->busNum = pci_bus;
1416    params->deviceNum = pci_dev;
1417    params->functionNum = pci_func;
1418    params->rx_filter = rx_filter;
1419    params->eaddr = hardware_address;
1420    params->rx_max_copy = rx_max_copy;
1421    params->tx_max_copy = tx_max_copy;
1422    params->rx_fifo_size = rx_fifo_size;
1423    params->tx_fifo_size = tx_fifo_size;
1424    params->rx_fifo_threshold = rx_fifo_threshold;
1425    params->tx_fifo_threshold = tx_fifo_threshold;
1426    params->dma_read_delay = dma_read_delay;
1427    params->dma_read_factor = dma_read_factor;
1428    params->dma_write_delay = dma_write_delay;
1429    params->dma_write_factor = dma_write_factor;
1430    return new Device(params);
1431}
1432
1433REGISTER_SIM_OBJECT("Sinic", Device)
1434
1435/* namespace Sinic */ }
1436