ns_gige.cc revision 879
15680Sgblack@eecs.umich.edu/*
25680Sgblack@eecs.umich.edu * Copyright (c) 2003 The Regents of The University of Michigan
35680Sgblack@eecs.umich.edu * All rights reserved.
45680Sgblack@eecs.umich.edu *
55680Sgblack@eecs.umich.edu * Redistribution and use in source and binary forms, with or without
65680Sgblack@eecs.umich.edu * modification, are permitted provided that the following conditions are
75680Sgblack@eecs.umich.edu * met: redistributions of source code must retain the above copyright
85680Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer;
95680Sgblack@eecs.umich.edu * redistributions in binary form must reproduce the above copyright
105680Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the
115680Sgblack@eecs.umich.edu * documentation and/or other materials provided with the distribution;
125680Sgblack@eecs.umich.edu * neither the name of the copyright holders nor the names of its
135680Sgblack@eecs.umich.edu * contributors may be used to endorse or promote products derived from
145680Sgblack@eecs.umich.edu * this software without specific prior written permission.
155680Sgblack@eecs.umich.edu *
165680Sgblack@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
175680Sgblack@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
185680Sgblack@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
195680Sgblack@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
205680Sgblack@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
215680Sgblack@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
225680Sgblack@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
235680Sgblack@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
245680Sgblack@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
255680Sgblack@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
265680Sgblack@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
275680Sgblack@eecs.umich.edu */
285680Sgblack@eecs.umich.edu
295856Sgblack@eecs.umich.edu/* @file
305680Sgblack@eecs.umich.edu * Device module for modelling the National Semiconductor
315680Sgblack@eecs.umich.edu * DP83820 ethernet controller.  Does not support priority queueing
325680Sgblack@eecs.umich.edu */
335680Sgblack@eecs.umich.edu#include <cstdio>
345680Sgblack@eecs.umich.edu#include <deque>
355856Sgblack@eecs.umich.edu#include <string>
365680Sgblack@eecs.umich.edu
375680Sgblack@eecs.umich.edu#include "base/inet.hh"
385680Sgblack@eecs.umich.edu#include "cpu/exec_context.hh"
395680Sgblack@eecs.umich.edu#include "cpu/intr_control.hh"
405680Sgblack@eecs.umich.edu#include "dev/dma.hh"
415680Sgblack@eecs.umich.edu#include "dev/ns_gige.hh"
425680Sgblack@eecs.umich.edu#include "dev/etherlink.hh"
435913Sgblack@eecs.umich.edu#include "mem/bus/bus.hh"
445913Sgblack@eecs.umich.edu#include "mem/bus/dma_interface.hh"
455680Sgblack@eecs.umich.edu#include "mem/bus/pio_interface.hh"
465853Sgblack@eecs.umich.edu#include "mem/bus/pio_interface_impl.hh"
475856Sgblack@eecs.umich.edu#include "mem/functional_mem/memory_control.hh"
485680Sgblack@eecs.umich.edu#include "mem/functional_mem/physical_memory.hh"
495680Sgblack@eecs.umich.edu#include "sim/builder.hh"
505680Sgblack@eecs.umich.edu#include "sim/host.hh"
515680Sgblack@eecs.umich.edu#include "sim/sim_stats.hh"
525680Sgblack@eecs.umich.edu#include "targetarch/vtophys.hh"
535852Sgblack@eecs.umich.edu#include "dev/pciconfigall.hh"
545852Sgblack@eecs.umich.edu#include "dev/tsunami_cchip.hh"
555852Sgblack@eecs.umich.edu
565856Sgblack@eecs.umich.educonst char *NsRxStateStrings[] =
575913Sgblack@eecs.umich.edu{
585856Sgblack@eecs.umich.edu    "rxIdle",
595856Sgblack@eecs.umich.edu    "rxDescRefr",
605913Sgblack@eecs.umich.edu    "rxDescRead",
615856Sgblack@eecs.umich.edu    "rxFifoBlock",
625852Sgblack@eecs.umich.edu    "rxFragWrite",
635852Sgblack@eecs.umich.edu    "rxDescWrite",
645680Sgblack@eecs.umich.edu    "rxAdvance"
655852Sgblack@eecs.umich.edu};
665852Sgblack@eecs.umich.edu
675680Sgblack@eecs.umich.educonst char *NsTxStateStrings[] =
685680Sgblack@eecs.umich.edu{
695680Sgblack@eecs.umich.edu    "txIdle",
705680Sgblack@eecs.umich.edu    "txDescRefr",
715680Sgblack@eecs.umich.edu    "txDescRead",
725680Sgblack@eecs.umich.edu    "txFifoBlock",
735680Sgblack@eecs.umich.edu    "txFragRead",
745852Sgblack@eecs.umich.edu    "txDescWrite",
755680Sgblack@eecs.umich.edu    "txAdvance"
765680Sgblack@eecs.umich.edu};
775680Sgblack@eecs.umich.edu
785852Sgblack@eecs.umich.educonst char *NsDmaState[] =
795852Sgblack@eecs.umich.edu{
805852Sgblack@eecs.umich.edu    "dmaIdle",
815680Sgblack@eecs.umich.edu    "dmaReading",
825680Sgblack@eecs.umich.edu    "dmaWriting",
835903Sgblack@eecs.umich.edu    "dmaReadWaiting",
845903Sgblack@eecs.umich.edu    "dmaWriteWaiting"
855680Sgblack@eecs.umich.edu};
865680Sgblack@eecs.umich.edu
875852Sgblack@eecs.umich.eduusing namespace std;
885680Sgblack@eecs.umich.edu
895680Sgblack@eecs.umich.edu///////////////////////////////////////////////////////////////////////
905903Sgblack@eecs.umich.edu//
915903Sgblack@eecs.umich.edu// NSGigE PCI Device
925903Sgblack@eecs.umich.edu//
935856Sgblack@eecs.umich.eduNSGigE::NSGigE(const std::string &name, IntrControl *i, Tick intr_delay,
945856Sgblack@eecs.umich.edu             PhysicalMemory *pmem, Tick tx_delay, Tick rx_delay,
955680Sgblack@eecs.umich.edu             MemoryController *mmu, HierParams *hier, Bus *header_bus,
965680Sgblack@eecs.umich.edu             Bus *payload_bus, Tick pio_latency, bool dma_desc_free,
975856Sgblack@eecs.umich.edu             bool dma_data_free, Tick dma_read_delay, Tick dma_write_delay,
985858Sgblack@eecs.umich.edu             Tick dma_read_factor, Tick dma_write_factor, PciConfigAll *cf,
995903Sgblack@eecs.umich.edu             PciConfigData *cd, Tsunami *t, uint32_t bus, uint32_t dev,
1005903Sgblack@eecs.umich.edu             uint32_t func, bool rx_filter, const int eaddr[6], Addr addr)
1015903Sgblack@eecs.umich.edu    : PciDev(name, mmu, cf, cd, bus, dev, func), tsunami(t),
1025948Sgblack@eecs.umich.edu      addr(addr), txPacketBufPtr(NULL), rxPacketBufPtr(NULL),
1035903Sgblack@eecs.umich.edu      txXferLen(0), rxXferLen(0), txPktXmitted(0), txState(txIdle), CTDD(false),
1045903Sgblack@eecs.umich.edu      txFifoCnt(0), txFifoAvail(MAX_TX_FIFO_SIZE), txHalt(false),
1055903Sgblack@eecs.umich.edu      txFragPtr(0), txDescCnt(0), txDmaState(dmaIdle), rxState(rxIdle),
1065903Sgblack@eecs.umich.edu      CRDD(false), rxPktBytes(0), rxFifoCnt(0), rxHalt(false),
1075913Sgblack@eecs.umich.edu      rxFragPtr(0), rxDescCnt(0), rxDmaState(dmaIdle), extstsEnable(false),
1085903Sgblack@eecs.umich.edu      rxDmaReadEvent(this), rxDmaWriteEvent(this),
1095903Sgblack@eecs.umich.edu      txDmaReadEvent(this), txDmaWriteEvent(this),
1105903Sgblack@eecs.umich.edu      dmaDescFree(dma_desc_free), dmaDataFree(dma_data_free),
1115680Sgblack@eecs.umich.edu      txDelay(tx_delay), rxDelay(rx_delay), rxKickTick(0), txKickTick(0),
1125856Sgblack@eecs.umich.edu      txEvent(this), rxFilterEnable(rx_filter), acceptBroadcast(false),
1135680Sgblack@eecs.umich.edu      acceptMulticast(false), acceptUnicast(false),
1145680Sgblack@eecs.umich.edu      acceptPerfect(false), acceptArp(false),
1155680Sgblack@eecs.umich.edu      physmem(pmem), intctrl(i), intrTick(0),
1165680Sgblack@eecs.umich.edu      cpuPendingIntr(false), intrEvent(0), interface(0), pioLatency(pio_latency)
1175852Sgblack@eecs.umich.edu{
1185852Sgblack@eecs.umich.edu    mmu->add_child(this, Range<Addr>(addr, addr + size));
1195680Sgblack@eecs.umich.edu    tsunami->ethernet = this;
1205852Sgblack@eecs.umich.edu
1215680Sgblack@eecs.umich.edu    if (header_bus) {
1225911Sgblack@eecs.umich.edu        pioInterface = newPioInterface(name, hier, header_bus, this,
1235911Sgblack@eecs.umich.edu                                       &NSGigE::cacheAccess);
1245911Sgblack@eecs.umich.edu        pioInterface->addAddrRange(addr, addr + size - 1);
1255911Sgblack@eecs.umich.edu        if (payload_bus)
1265911Sgblack@eecs.umich.edu            dmaInterface = new DMAInterface<Bus>(name + ".dma",
1275911Sgblack@eecs.umich.edu                                                 header_bus, payload_bus, 1);
1285911Sgblack@eecs.umich.edu        else
1295911Sgblack@eecs.umich.edu            dmaInterface = new DMAInterface<Bus>(name + ".dma",
1305911Sgblack@eecs.umich.edu                                                 header_bus, header_bus, 1);
1315911Sgblack@eecs.umich.edu    } else if (payload_bus) {
1325911Sgblack@eecs.umich.edu        pioInterface = newPioInterface(name, hier, payload_bus, this,
1335911Sgblack@eecs.umich.edu                                       &NSGigE::cacheAccess);
1345913Sgblack@eecs.umich.edu        pioInterface->addAddrRange(addr, addr + size - 1);
1355913Sgblack@eecs.umich.edu        dmaInterface = new DMAInterface<Bus>(name + ".dma",
1365913Sgblack@eecs.umich.edu                                             payload_bus, payload_bus, 1);
1375913Sgblack@eecs.umich.edu
1385913Sgblack@eecs.umich.edu    }
1395680Sgblack@eecs.umich.edu
1405680Sgblack@eecs.umich.edu
1415680Sgblack@eecs.umich.edu    intrDelay = US2Ticks(intr_delay);
1425680Sgblack@eecs.umich.edu    dmaReadDelay = dma_read_delay;
1435680Sgblack@eecs.umich.edu    dmaWriteDelay = dma_write_delay;
1445852Sgblack@eecs.umich.edu    dmaReadFactor = dma_read_factor;
1455680Sgblack@eecs.umich.edu    dmaWriteFactor = dma_write_factor;
1465856Sgblack@eecs.umich.edu
1475856Sgblack@eecs.umich.edu    memset(&regs, 0, sizeof(regs));
1485911Sgblack@eecs.umich.edu    regsReset();
1495852Sgblack@eecs.umich.edu    rom.perfectMatch[0] = eaddr[0];
1505856Sgblack@eecs.umich.edu    rom.perfectMatch[1] = eaddr[1];
1515856Sgblack@eecs.umich.edu    rom.perfectMatch[2] = eaddr[2];
1525680Sgblack@eecs.umich.edu    rom.perfectMatch[3] = eaddr[3];
1535856Sgblack@eecs.umich.edu    rom.perfectMatch[4] = eaddr[4];
1545680Sgblack@eecs.umich.edu    rom.perfectMatch[5] = eaddr[5];
1555680Sgblack@eecs.umich.edu}
1565680Sgblack@eecs.umich.edu
1575852Sgblack@eecs.umich.eduNSGigE::~NSGigE()
1585680Sgblack@eecs.umich.edu{}
1595680Sgblack@eecs.umich.edu
1605852Sgblack@eecs.umich.eduvoid
1615680Sgblack@eecs.umich.eduNSGigE::regStats()
1625680Sgblack@eecs.umich.edu{
1635680Sgblack@eecs.umich.edu    txBytes
1645680Sgblack@eecs.umich.edu        .name(name() + ".txBytes")
1655680Sgblack@eecs.umich.edu        .desc("Bytes Transmitted")
1665680Sgblack@eecs.umich.edu        .prereq(txBytes)
1675680Sgblack@eecs.umich.edu        ;
1685852Sgblack@eecs.umich.edu
1695852Sgblack@eecs.umich.edu    rxBytes
1705852Sgblack@eecs.umich.edu        .name(name() + ".rxBytes")
1715680Sgblack@eecs.umich.edu        .desc("Bytes Received")
1725680Sgblack@eecs.umich.edu        .prereq(rxBytes)
1735680Sgblack@eecs.umich.edu        ;
1745680Sgblack@eecs.umich.edu
1755680Sgblack@eecs.umich.edu    txPackets
1765680Sgblack@eecs.umich.edu        .name(name() + ".txPackets")
1775852Sgblack@eecs.umich.edu        .desc("Number of Packets Transmitted")
1785680Sgblack@eecs.umich.edu        .prereq(txBytes)
1795680Sgblack@eecs.umich.edu        ;
1805680Sgblack@eecs.umich.edu
1815856Sgblack@eecs.umich.edu    rxPackets
1825680Sgblack@eecs.umich.edu        .name(name() + ".rxPackets")
1835856Sgblack@eecs.umich.edu        .desc("Number of Packets Received")
1845856Sgblack@eecs.umich.edu        .prereq(rxBytes)
1855856Sgblack@eecs.umich.edu        ;
1865856Sgblack@eecs.umich.edu
1875856Sgblack@eecs.umich.edu    txBandwidth
1885856Sgblack@eecs.umich.edu        .name(name() + ".txBandwidth")
1895856Sgblack@eecs.umich.edu        .desc("Transmit Bandwidth (bits/s)")
1905856Sgblack@eecs.umich.edu        .precision(0)
1915856Sgblack@eecs.umich.edu        .prereq(txBytes)
1925856Sgblack@eecs.umich.edu        ;
1935856Sgblack@eecs.umich.edu
1945856Sgblack@eecs.umich.edu    rxBandwidth
1955856Sgblack@eecs.umich.edu        .name(name() + ".rxBandwidth")
1965856Sgblack@eecs.umich.edu        .desc("Receive Bandwidth (bits/s)")
1975856Sgblack@eecs.umich.edu        .precision(0)
1985856Sgblack@eecs.umich.edu        .prereq(rxBytes)
1995856Sgblack@eecs.umich.edu        ;
2005856Sgblack@eecs.umich.edu
2015856Sgblack@eecs.umich.edu    txPacketRate
2025856Sgblack@eecs.umich.edu        .name(name() + ".txPPS")
2035856Sgblack@eecs.umich.edu        .desc("Packet Tranmission Rate (packets/s)")
2045856Sgblack@eecs.umich.edu        .precision(0)
2055680Sgblack@eecs.umich.edu        .prereq(txBytes)
2065680Sgblack@eecs.umich.edu        ;
2075680Sgblack@eecs.umich.edu
2085680Sgblack@eecs.umich.edu    rxPacketRate
2095680Sgblack@eecs.umich.edu        .name(name() + ".rxPPS")
2105680Sgblack@eecs.umich.edu        .desc("Packet Reception Rate (packets/s)")
2115680Sgblack@eecs.umich.edu        .precision(0)
2126048Sgblack@eecs.umich.edu        .prereq(rxBytes)
2136048Sgblack@eecs.umich.edu        ;
2146048Sgblack@eecs.umich.edu
2156048Sgblack@eecs.umich.edu    txBandwidth = txBytes * Stats::constant(8) / simSeconds;
2166048Sgblack@eecs.umich.edu    rxBandwidth = rxBytes * Stats::constant(8) / simSeconds;
2176048Sgblack@eecs.umich.edu    txPacketRate = txPackets / simSeconds;
2186048Sgblack@eecs.umich.edu    rxPacketRate = rxPackets / simSeconds;
2196048Sgblack@eecs.umich.edu}
2206048Sgblack@eecs.umich.edu
2216048Sgblack@eecs.umich.edu/**
2226048Sgblack@eecs.umich.edu * This is to read the PCI general configuration registers
2235680Sgblack@eecs.umich.edu */
224void
225NSGigE::ReadConfig(int offset, int size, uint8_t *data)
226{
227    if (offset < PCI_DEVICE_SPECIFIC)
228        PciDev::ReadConfig(offset, size, data);
229    else {
230        panic("need to do this\n");
231    }
232}
233
234/**
235 * This is to write to the PCI general configuration registers
236 */
237void
238NSGigE::WriteConfig(int offset, int size, uint32_t data)
239{
240    if (offset < PCI_DEVICE_SPECIFIC)
241        PciDev::WriteConfig(offset, size, data);
242    else
243        panic("Need to do that\n");
244}
245
246/**
247 * This reads the device registers, which are detailed in the NS83820
248 * spec sheet
249 */
250Fault
251NSGigE::read(MemReqPtr &req, uint8_t *data)
252{
253    //The mask is to give you only the offset into the device register file
254    Addr daddr = req->paddr & 0xfff;
255    DPRINTF(EthernetPIO, "read  da=%#x pa=%#x va=%#x size=%d\n",
256            daddr, req->paddr, req->vaddr, req->size);
257
258
259    //there are some reserved registers, you can see ns_gige_reg.h and
260    //the spec sheet for details
261    if (daddr > LAST && daddr <=  RESERVED) {
262        panic("Accessing reserved register");
263    } else if (daddr > RESERVED && daddr <= 0x3FC) {
264        ReadConfig(daddr & 0xff, req->size, data);
265        return No_Fault;
266    } else if (daddr >= MIB_START && daddr <= MIB_END) {
267        // don't implement all the MIB's.  hopefully the kernel
268        // doesn't actually DEPEND upon their values
269        // MIB are just hardware stats keepers
270        uint32_t &reg = *(uint32_t *) data;
271        reg = 0;
272        return No_Fault;
273    } else if (daddr > 0x3FC)
274        panic("Something is messed up!\n");
275
276    switch (req->size) {
277      case sizeof(uint32_t):
278        {
279            uint32_t &reg = *(uint32_t *)data;
280
281            switch (daddr) {
282              case CR:
283                reg = regs.command;
284                //these are supposed to be cleared on a read
285                reg &= ~(CR_RXD | CR_TXD | CR_TXR | CR_RXR);
286                break;
287
288              case CFG:
289                reg = regs.config;
290                break;
291
292              case MEAR:
293                reg = regs.mear;
294                break;
295
296              case PTSCR:
297                reg = regs.ptscr;
298                break;
299
300              case ISR:
301                reg = regs.isr;
302                devIntrClear(ISR_ALL);
303                break;
304
305              case IMR:
306                reg = regs.imr;
307                break;
308
309              case IER:
310                reg = regs.ier;
311                break;
312
313              case IHR:
314                reg = regs.ihr;
315                break;
316
317              case TXDP:
318                reg = regs.txdp;
319                break;
320
321              case TXDP_HI:
322                reg = regs.txdp_hi;
323                break;
324
325              case TXCFG:
326                reg = regs.txcfg;
327                break;
328
329              case GPIOR:
330                reg = regs.gpior;
331                break;
332
333              case RXDP:
334                reg = regs.rxdp;
335                break;
336
337              case RXDP_HI:
338                reg = regs.rxdp_hi;
339                break;
340
341              case RXCFG:
342                reg = regs.rxcfg;
343                break;
344
345              case PQCR:
346                reg = regs.pqcr;
347                break;
348
349              case WCSR:
350                reg = regs.wcsr;
351                break;
352
353              case PCR:
354                reg = regs.pcr;
355                break;
356
357                //see the spec sheet for how RFCR and RFDR work
358                //basically, you write to RFCR to tell the machine what you want to do next
359                //then you act upon RFDR, and the device will be prepared b/c
360                //of what you wrote to RFCR
361              case RFCR:
362                reg = regs.rfcr;
363                break;
364
365              case RFDR:
366                DPRINTF(Ethernet, "reading from RFDR\n");
367                switch (regs.rfcr & RFCR_RFADDR) {
368                  case 0x000:
369                    reg = rom.perfectMatch[1];
370                    reg = reg << 8;
371                    reg += rom.perfectMatch[0];
372                    break;
373                  case 0x002:
374                    reg = rom.perfectMatch[3] << 8;
375                    reg += rom.perfectMatch[2];
376                    break;
377                  case 0x004:
378                    reg = rom.perfectMatch[5] << 8;
379                    reg += rom.perfectMatch[4];
380                    break;
381                  default:
382                    panic("reading from RFDR for something for other than PMATCH!\n");
383                    //didn't implement other RFDR functionality b/c driver didn't use
384                }
385                break;
386
387              case SRR:
388                reg = regs.srr;
389                break;
390
391              case MIBC:
392                reg = regs.mibc;
393                reg &= ~(MIBC_MIBS | MIBC_ACLR);
394                break;
395
396              case VRCR:
397                reg = regs.vrcr;
398                break;
399
400              case VTCR:
401                reg = regs.vtcr;
402                break;
403
404              case VDR:
405                reg = regs.vdr;
406                break;
407
408              case CCSR:
409                reg = regs.ccsr;
410                break;
411
412              case TBICR:
413                reg = regs.tbicr;
414                break;
415
416              case TBISR:
417                reg = regs.tbisr;
418                break;
419
420              case TANAR:
421                reg = regs.tanar;
422                break;
423
424              case TANLPAR:
425                reg = regs.tanlpar;
426                break;
427
428              case TANER:
429                reg = regs.taner;
430                break;
431
432              case TESR:
433                reg = regs.tesr;
434                break;
435
436              default:
437                panic("reading unimplemented register: addr = %#x", daddr);
438            }
439
440            DPRINTF(EthernetPIO, "read from %#x: data=%d data=%#x\n", daddr, reg, reg);
441        }
442        break;
443
444      default:
445        panic("accessing register with invalid size: addr=%#x, size=%d",
446              daddr, req->size);
447    }
448
449    return No_Fault;
450}
451
452Fault
453NSGigE::write(MemReqPtr &req, const uint8_t *data)
454{
455    Addr daddr = req->paddr & 0xfff;
456    DPRINTF(EthernetPIO, "write da=%#x pa=%#x va=%#x size=%d\n",
457            daddr, req->paddr, req->vaddr, req->size);
458
459    if (daddr > LAST && daddr <=  RESERVED) {
460        panic("Accessing reserved register");
461    } else if (daddr > RESERVED && daddr <= 0x3FC) {
462        WriteConfig(daddr & 0xff, req->size, *(uint32_t *)data);
463        return No_Fault;
464    } else if (daddr > 0x3FC)
465        panic("Something is messed up!\n");
466
467    if (req->size == sizeof(uint32_t)) {
468        uint32_t reg = *(uint32_t *)data;
469        DPRINTF(EthernetPIO, "write data=%d data=%#x\n", reg, reg);
470
471        switch (daddr) {
472          case CR:
473            regs.command = reg;
474            if ((reg & (CR_TXE | CR_TXD)) == (CR_TXE | CR_TXD)) {
475                txHalt = true;
476            } else if (reg & CR_TXE) {
477                //the kernel is enabling the transmit machine
478                if (txState == txIdle)
479                    txKick();
480            } else if (reg & CR_TXD) {
481                txHalt = true;
482            }
483
484            if ((reg & (CR_RXE | CR_RXD)) == (CR_RXE | CR_RXD)) {
485                rxHalt = true;
486            } else if (reg & CR_RXE) {
487                if (rxState == rxIdle) {
488                    rxKick();
489                }
490            } else if (reg & CR_RXD) {
491                rxHalt = true;
492            }
493
494            if (reg & CR_TXR)
495                txReset();
496
497            if (reg & CR_RXR)
498                rxReset();
499
500            if (reg & CR_SWI)
501                devIntrPost(ISR_SWI);
502
503            if (reg & CR_RST) {
504                txReset();
505                rxReset();
506
507                regsReset();
508            }
509            break;
510
511          case CFG:
512            if (reg & CFG_LNKSTS || reg & CFG_SPDSTS || reg & CFG_DUPSTS
513                || reg & CFG_RESERVED || reg & CFG_T64ADDR
514                || reg & CFG_PCI64_DET)
515                panic("writing to read-only or reserved CFG bits!\n");
516
517            regs.config |= reg & ~(CFG_LNKSTS | CFG_SPDSTS | CFG_DUPSTS | CFG_RESERVED |
518                                  CFG_T64ADDR | CFG_PCI64_DET);
519
520// all these #if 0's are because i don't THINK the kernel needs to have these implemented
521// if there is a problem relating to one of these, you may need to add functionality in
522#if 0
523              if (reg & CFG_TBI_EN) ;
524              if (reg & CFG_MODE_1000) ;
525#endif
526
527            if (reg & CFG_AUTO_1000)
528                panic("CFG_AUTO_1000 not implemented!\n");
529
530#if 0
531            if (reg & CFG_PINT_DUPSTS || reg & CFG_PINT_LNKSTS || reg & CFG_PINT_SPDSTS) ;
532            if (reg & CFG_TMRTEST) ;
533            if (reg & CFG_MRM_DIS) ;
534            if (reg & CFG_MWI_DIS) ;
535
536            if (reg & CFG_T64ADDR)
537                panic("CFG_T64ADDR is read only register!\n");
538
539            if (reg & CFG_PCI64_DET)
540                panic("CFG_PCI64_DET is read only register!\n");
541
542            if (reg & CFG_DATA64_EN) ;
543            if (reg & CFG_M64ADDR) ;
544            if (reg & CFG_PHY_RST) ;
545            if (reg & CFG_PHY_DIS) ;
546#endif
547
548            if (reg & CFG_EXTSTS_EN)
549                extstsEnable = true;
550            else
551                extstsEnable = false;
552
553#if 0
554              if (reg & CFG_REQALG) ;
555              if (reg & CFG_SB) ;
556              if (reg & CFG_POW) ;
557              if (reg & CFG_EXD) ;
558              if (reg & CFG_PESEL) ;
559              if (reg & CFG_BROM_DIS) ;
560              if (reg & CFG_EXT_125) ;
561              if (reg & CFG_BEM) ;
562#endif
563            break;
564
565          case MEAR:
566            regs.mear = reg;
567            /* since phy is completely faked, MEAR_MD* don't matter
568               and since the driver never uses MEAR_EE*, they don't matter */
569#if 0
570            if (reg & MEAR_EEDI) ;
571            if (reg & MEAR_EEDO) ; //this one is read only
572            if (reg & MEAR_EECLK) ;
573            if (reg & MEAR_EESEL) ;
574            if (reg & MEAR_MDIO) ;
575            if (reg & MEAR_MDDIR) ;
576            if (reg & MEAR_MDC) ;
577#endif
578            break;
579
580          case PTSCR:
581            regs.ptscr = reg & ~(PTSCR_RBIST_RDONLY);
582            /* these control BISTs for various parts of chip - we don't care or do
583               just fake that the BIST is done */
584            if (reg & PTSCR_RBIST_EN)
585                regs.ptscr |= PTSCR_RBIST_DONE;
586            if (reg & PTSCR_EEBIST_EN)
587                regs.ptscr &= ~PTSCR_EEBIST_EN;
588            if (reg & PTSCR_EELOAD_EN)
589                regs.ptscr &= ~PTSCR_EELOAD_EN;
590            break;
591
592          case ISR: /* writing to the ISR has no effect */
593            panic("ISR is a read only register!\n");
594
595          case IMR:
596            regs.imr = reg;
597            devIntrChangeMask();
598            break;
599
600          case IER:
601            regs.ier = reg;
602            break;
603
604          case IHR:
605            regs.ihr = reg;
606            /* not going to implement real interrupt holdoff */
607            break;
608
609          case TXDP:
610            regs.txdp = (reg & 0xFFFFFFFC);
611            assert(txState == txIdle);
612            CTDD = false;
613            break;
614
615          case TXDP_HI:
616            regs.txdp_hi = reg;
617            break;
618
619          case TXCFG:
620            regs.txcfg = reg;
621#if 0
622            if (reg & TXCFG_CSI) ;
623            if (reg & TXCFG_HBI) ;
624            if (reg & TXCFG_MLB) ;
625            if (reg & TXCFG_ATP) ;
626            if (reg & TXCFG_ECRETRY) ;  /* this could easily be implemented, but
627                                           considering the network is just a fake
628                                           pipe, wouldn't make sense to do this */
629
630            if (reg & TXCFG_BRST_DIS) ;
631#endif
632
633
634            /* we handle our own DMA, ignore the kernel's exhortations */
635            if (reg & TXCFG_MXDMA) ;
636
637            break;
638
639          case GPIOR:
640            regs.gpior = reg;
641            /* these just control general purpose i/o pins, don't matter */
642            break;
643
644          case RXDP:
645            regs.rxdp = reg;
646            break;
647
648          case RXDP_HI:
649            regs.rxdp_hi = reg;
650            break;
651
652          case RXCFG:
653            regs.rxcfg = reg;
654#if 0
655            if (reg & RXCFG_AEP) ;
656            if (reg & RXCFG_ARP) ;
657            if (reg & RXCFG_STRIPCRC) ;
658            if (reg & RXCFG_RX_RD) ;
659            if (reg & RXCFG_ALP) ;
660            if (reg & RXCFG_AIRL) ;
661#endif
662
663            /* we handle our own DMA, ignore what kernel says about it */
664            if (reg & RXCFG_MXDMA) ;
665
666#if 0
667            if (reg & (RXCFG_DRTH | RXCFG_DRTH0)) ;
668#endif
669            break;
670
671          case PQCR:
672            /* there is no priority queueing used in the linux 2.6 driver */
673            regs.pqcr = reg;
674            break;
675
676          case WCSR:
677            /* not going to implement wake on LAN */
678            regs.wcsr = reg;
679            break;
680
681          case PCR:
682            /* not going to implement pause control */
683            regs.pcr = reg;
684            break;
685
686          case RFCR:
687            regs.rfcr = reg;
688            DPRINTF(Ethernet, "Writing to RFCR, RFADDR is %#x\n", reg & RFCR_RFADDR);
689
690            rxFilterEnable = (reg & RFCR_RFEN) ? true : false;
691
692            acceptBroadcast = (reg & RFCR_AAB) ? true : false;
693
694            acceptMulticast = (reg & RFCR_AAM) ? true : false;
695
696            acceptUnicast = (reg & RFCR_AAU) ? true : false;
697
698            acceptPerfect = (reg & RFCR_APM) ? true : false;
699
700            acceptArp = (reg & RFCR_AARP) ? true : false;
701
702            if (reg & RFCR_APAT) ;
703//                panic("RFCR_APAT not implemented!\n");
704
705            if (reg & RFCR_MHEN || reg & RFCR_UHEN)
706                panic("hash filtering not implemented!\n");
707
708            if (reg & RFCR_ULM)
709                panic("RFCR_ULM not implemented!\n");
710
711            break;
712
713          case RFDR:
714            panic("the driver never writes to RFDR, something is wrong!\n");
715
716          case BRAR:
717            panic("the driver never uses BRAR, something is wrong!\n");
718
719          case BRDR:
720            panic("the driver never uses BRDR, something is wrong!\n");
721
722          case SRR:
723            panic("SRR is read only register!\n");
724
725          case MIBC:
726            panic("the driver never uses MIBC, something is wrong!\n");
727
728          case VRCR:
729            regs.vrcr = reg;
730            break;
731
732          case VTCR:
733            regs.vtcr = reg;
734            break;
735
736          case VDR:
737            panic("the driver never uses VDR, something is wrong!\n");
738            break;
739
740          case CCSR:
741            /* not going to implement clockrun stuff */
742            regs.ccsr = reg;
743            break;
744
745          case TBICR:
746            regs.tbicr = reg;
747            if (reg & TBICR_MR_LOOPBACK)
748                panic("TBICR_MR_LOOPBACK never used, something wrong!\n");
749
750            if (reg & TBICR_MR_AN_ENABLE) {
751                regs.tanlpar = regs.tanar;
752                regs.tbisr |= (TBISR_MR_AN_COMPLETE | TBISR_MR_LINK_STATUS);
753            }
754
755#if 0
756            if (reg & TBICR_MR_RESTART_AN) ;
757#endif
758
759            break;
760
761          case TBISR:
762            panic("TBISR is read only register!\n");
763
764          case TANAR:
765            regs.tanar = reg;
766            if (reg & TANAR_PS2)
767                panic("this isn't used in driver, something wrong!\n");
768
769            if (reg & TANAR_PS1)
770                panic("this isn't used in driver, something wrong!\n");
771            break;
772
773          case TANLPAR:
774            panic("this should only be written to by the fake phy!\n");
775
776          case TANER:
777            panic("TANER is read only register!\n");
778
779          case TESR:
780            regs.tesr = reg;
781            break;
782
783          default:
784            panic("thought i covered all the register, what is this? addr=%#x",
785                  daddr);
786        }
787    } else
788        panic("Invalid Request Size");
789
790    return No_Fault;
791}
792
793void
794NSGigE::devIntrPost(uint32_t interrupts)
795{
796    DPRINTF(Ethernet, "interrupt posted intr=%#x isr=%#x imr=%#x\n",
797            interrupts, regs.isr, regs.imr);
798
799    bool delay = false;
800
801    if (interrupts & ISR_RESERVE)
802        panic("Cannot set a reserved interrupt");
803
804    if (interrupts & ISR_TXRCMP)
805        regs.isr |= ISR_TXRCMP;
806
807    if (interrupts & ISR_RXRCMP)
808        regs.isr |= ISR_RXRCMP;
809
810//ISR_DPERR  not implemented
811//ISR_SSERR not implemented
812//ISR_RMABT not implemented
813//ISR_RXSOVR not implemented
814//ISR_HIBINT not implemented
815//ISR_PHY not implemented
816//ISR_PME not implemented
817
818    if (interrupts & ISR_SWI)
819        regs.isr |= ISR_SWI;
820
821//ISR_MIB not implemented
822//ISR_TXURN not implemented
823
824    if (interrupts & ISR_TXIDLE)
825        regs.isr |= ISR_TXIDLE;
826
827    if (interrupts & ISR_TXERR)
828        regs.isr |= ISR_TXERR;
829
830    if (interrupts & ISR_TXDESC)
831        regs.isr |= ISR_TXDESC;
832
833    if (interrupts & ISR_TXOK) {
834        regs.isr |= ISR_TXOK;
835        delay = true;
836    }
837
838    if (interrupts & ISR_RXORN)
839        regs.isr |= ISR_RXORN;
840
841    if (interrupts & ISR_RXIDLE)
842        regs.isr |= ISR_RXIDLE;
843
844//ISR_RXEARLY not implemented
845
846    if (interrupts & ISR_RXERR)
847        regs.isr |= ISR_RXERR;
848
849    if (interrupts & ISR_RXOK) {
850        delay = true;
851        regs.isr |= ISR_RXOK;
852    }
853
854    if ((regs.isr & regs.imr)) {
855        Tick when = curTick;
856        if (delay)
857            when += intrDelay;
858        cpuIntrPost(when);
859    }
860}
861
862void
863NSGigE::devIntrClear(uint32_t interrupts)
864{
865    DPRINTF(Ethernet, "interrupt cleared intr=%x isr=%x imr=%x\n",
866            interrupts, regs.isr, regs.imr);
867
868    if (interrupts & ISR_RESERVE)
869        panic("Cannot clear a reserved interrupt");
870
871    if (interrupts & ISR_TXRCMP)
872        regs.isr &= ~ISR_TXRCMP;
873
874    if (interrupts & ISR_RXRCMP)
875        regs.isr &= ~ISR_RXRCMP;
876
877//ISR_DPERR  not implemented
878//ISR_SSERR not implemented
879//ISR_RMABT not implemented
880//ISR_RXSOVR not implemented
881//ISR_HIBINT not implemented
882//ISR_PHY not implemented
883//ISR_PME not implemented
884
885    if (interrupts & ISR_SWI)
886        regs.isr &= ~ISR_SWI;
887
888//ISR_MIB not implemented
889//ISR_TXURN not implemented
890
891    if (interrupts & ISR_TXIDLE)
892        regs.isr &= ~ISR_TXIDLE;
893
894    if (interrupts & ISR_TXERR)
895        regs.isr &= ~ISR_TXERR;
896
897    if (interrupts & ISR_TXDESC)
898        regs.isr &= ~ISR_TXDESC;
899
900    if (interrupts & ISR_TXOK)
901        regs.isr &= ~ISR_TXOK;
902
903    if (interrupts & ISR_RXORN)
904        regs.isr &= ~ISR_RXORN;
905
906    if (interrupts & ISR_RXIDLE)
907        regs.isr &= ~ISR_RXIDLE;
908
909//ISR_RXEARLY not implemented
910
911    if (interrupts & ISR_RXERR)
912        regs.isr &= ~ISR_RXERR;
913
914    if (interrupts & ISR_RXOK)
915        regs.isr &= ~ISR_RXOK;
916
917    if (!(regs.isr & regs.imr))
918        cpuIntrClear();
919}
920
921void
922NSGigE::devIntrChangeMask()
923{
924    DPRINTF(Ethernet, "interrupt mask changed\n");
925
926    if (regs.isr & regs.imr)
927        cpuIntrPost(curTick);
928    else
929        cpuIntrClear();
930}
931
932void
933NSGigE::cpuIntrPost(Tick when)
934{
935    if (when > intrTick && intrTick != 0)
936        return;
937
938    intrTick = when;
939
940    if (intrEvent) {
941        intrEvent->squash();
942        intrEvent = 0;
943    }
944
945    if (when < curTick) {
946        cpuInterrupt();
947    } else {
948        intrEvent = new IntrEvent(this, true);
949        intrEvent->schedule(intrTick);
950    }
951}
952
953void
954NSGigE::cpuInterrupt()
955{
956    // Don't send an interrupt if there's already one
957    if (cpuPendingIntr)
958        return;
959
960    // Don't send an interrupt if it's supposed to be delayed
961    if (intrTick > curTick)
962        return;
963
964    // Whether or not there's a pending interrupt, we don't care about
965    // it anymore
966    intrEvent = 0;
967    intrTick = 0;
968
969    // Send interrupt
970    cpuPendingIntr = true;
971    /** @todo rework the intctrl to be tsunami ok */
972    //intctrl->post(TheISA::INTLEVEL_IRQ1, TheISA::INTINDEX_ETHERNET);
973    tsunami->cchip->postDRIR(configData->config.hdr.pci0.interruptLine);
974}
975
976void
977NSGigE::cpuIntrClear()
978{
979    if (cpuPendingIntr) {
980        cpuPendingIntr = false;
981        /** @todo rework the intctrl to be tsunami ok */
982        //intctrl->clear(TheISA::INTLEVEL_IRQ1, TheISA::INTINDEX_ETHERNET);
983        tsunami->cchip->clearDRIR(configData->config.hdr.pci0.interruptLine);
984    }
985}
986
987bool
988NSGigE::cpuIntrPending() const
989{ return cpuPendingIntr; }
990
991void
992NSGigE::txReset()
993{
994
995    DPRINTF(Ethernet, "transmit reset\n");
996
997    CTDD = false;
998    txFifoCnt = 0;
999    txFifoAvail = MAX_TX_FIFO_SIZE;
1000    txHalt = false;
1001    txFragPtr = 0;
1002    assert(txDescCnt == 0);
1003    txFifo.clear();
1004    regs.command &= ~CR_TXE;
1005    txState = txIdle;
1006    assert(txDmaState == dmaIdle);
1007}
1008
1009void
1010NSGigE::rxReset()
1011{
1012    DPRINTF(Ethernet, "receive reset\n");
1013
1014    CRDD = false;
1015    assert(rxPktBytes == 0);
1016    rxFifoCnt = 0;
1017    rxHalt = false;
1018    rxFragPtr = 0;
1019    assert(rxDescCnt == 0);
1020    assert(rxDmaState == dmaIdle);
1021    rxFifo.clear();
1022    regs.command &= ~CR_RXE;
1023    rxState = rxIdle;
1024}
1025
1026void
1027NSGigE::rxDmaReadCopy()
1028{
1029    assert(rxDmaState == dmaReading);
1030
1031    memcpy(rxDmaData, physmem->dma_addr(rxDmaAddr, rxDmaLen), rxDmaLen);
1032    rxDmaState = dmaIdle;
1033
1034    DPRINTF(EthernetDMA, "rx dma read  paddr=%#x len=%d\n",
1035            rxDmaAddr, rxDmaLen);
1036    DDUMP(EthernetDMA, rxDmaData, rxDmaLen);
1037}
1038
1039bool
1040NSGigE::doRxDmaRead()
1041{
1042    assert(rxDmaState == dmaIdle || rxDmaState == dmaReadWaiting);
1043    rxDmaState = dmaReading;
1044
1045    if (dmaInterface && !rxDmaFree) {
1046        if (dmaInterface->busy())
1047            rxDmaState = dmaReadWaiting;
1048        else
1049            dmaInterface->doDMA(Read, rxDmaAddr, rxDmaLen, curTick,
1050                                &rxDmaReadEvent);
1051        return true;
1052    }
1053
1054    if (dmaReadDelay == 0 && dmaReadFactor == 0) {
1055        rxDmaReadCopy();
1056        return false;
1057    }
1058
1059    Tick factor = ((rxDmaLen + ULL(63)) >> ULL(6)) * dmaReadFactor;
1060    Tick start = curTick + dmaReadDelay + factor;
1061    rxDmaReadEvent.schedule(start);
1062    return true;
1063}
1064
1065void
1066NSGigE::rxDmaReadDone()
1067{
1068    assert(rxDmaState == dmaReading);
1069    rxDmaReadCopy();
1070
1071    // If the transmit state machine has a pending DMA, let it go first
1072    if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting)
1073        txKick();
1074
1075    rxKick();
1076}
1077
1078void
1079NSGigE::rxDmaWriteCopy()
1080{
1081    assert(rxDmaState == dmaWriting);
1082
1083    memcpy(physmem->dma_addr(rxDmaAddr, rxDmaLen), rxDmaData, rxDmaLen);
1084    rxDmaState = dmaIdle;
1085
1086    DPRINTF(EthernetDMA, "rx dma write paddr=%#x len=%d\n",
1087            rxDmaAddr, rxDmaLen);
1088    DDUMP(EthernetDMA, rxDmaData, rxDmaLen);
1089}
1090
1091bool
1092NSGigE::doRxDmaWrite()
1093{
1094    assert(rxDmaState == dmaIdle || rxDmaState == dmaWriteWaiting);
1095    rxDmaState = dmaWriting;
1096
1097    if (dmaInterface && !rxDmaFree) {
1098        if (dmaInterface->busy())
1099            rxDmaState = dmaWriteWaiting;
1100        else
1101            dmaInterface->doDMA(WriteInvalidate, rxDmaAddr, rxDmaLen, curTick,
1102                                &rxDmaWriteEvent);
1103        return true;
1104    }
1105
1106    if (dmaWriteDelay == 0 && dmaWriteFactor == 0) {
1107        rxDmaWriteCopy();
1108        return false;
1109    }
1110
1111    Tick factor = ((rxDmaLen + ULL(63)) >> ULL(6)) * dmaWriteFactor;
1112    Tick start = curTick + dmaWriteDelay + factor;
1113    rxDmaWriteEvent.schedule(start);
1114    return true;
1115}
1116
1117void
1118NSGigE::rxDmaWriteDone()
1119{
1120    assert(rxDmaState == dmaWriting);
1121    rxDmaWriteCopy();
1122
1123    // If the transmit state machine has a pending DMA, let it go first
1124    if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting)
1125        txKick();
1126
1127    rxKick();
1128}
1129
1130void
1131NSGigE::rxKick()
1132{
1133    DPRINTF(Ethernet, "receive kick state=%s (rxBuf.size=%d)\n",
1134            NsRxStateStrings[rxState], rxFifo.size());
1135
1136    if (rxKickTick > curTick) {
1137        DPRINTF(Ethernet, "receive kick exiting, can't run till %d\n",
1138                rxKickTick);
1139        return;
1140    }
1141
1142  next:
1143    switch(rxDmaState) {
1144      case dmaReadWaiting:
1145        if (doRxDmaRead())
1146            goto exit;
1147        break;
1148      case dmaWriteWaiting:
1149        if (doRxDmaWrite())
1150            goto exit;
1151        break;
1152      default:
1153        break;
1154    }
1155
1156    // see state machine from spec for details
1157    // the way this works is, if you finish work on one state and can go directly to
1158    // another, you do that through jumping to the label "next".  however, if you have
1159    // intermediate work, like DMA so that you can't go to the next state yet, you go to
1160    // exit and exit the loop.  however, when the DMA is done it will trigger an
1161    // event and come back to this loop.
1162    switch (rxState) {
1163      case rxIdle:
1164        if (!regs.command & CR_RXE) {
1165            DPRINTF(Ethernet, "Receive Disabled! Nothing to do.\n");
1166            goto exit;
1167        }
1168
1169        if (CRDD) {
1170            rxState = rxDescRefr;
1171
1172            rxDmaAddr = regs.rxdp & 0x3fffffff;
1173            rxDmaData = &rxDescCache + offsetof(ns_desc, link);
1174            rxDmaLen = sizeof(rxDescCache.link);
1175            rxDmaFree = dmaDescFree;
1176
1177            if (doRxDmaRead())
1178                goto exit;
1179        } else {
1180            rxState = rxDescRead;
1181
1182            rxDmaAddr = regs.rxdp & 0x3fffffff;
1183            rxDmaData = &rxDescCache;
1184            rxDmaLen = sizeof(ns_desc);
1185            rxDmaFree = dmaDescFree;
1186
1187            if (doRxDmaRead())
1188                goto exit;
1189        }
1190        break;
1191
1192      case rxDescRefr:
1193        if (rxDmaState != dmaIdle)
1194            goto exit;
1195
1196        rxState = rxAdvance;
1197        break;
1198
1199     case rxDescRead:
1200        if (rxDmaState != dmaIdle)
1201            goto exit;
1202
1203        if (rxDescCache.cmdsts & CMDSTS_OWN) {
1204            rxState = rxIdle;
1205        } else {
1206            rxState = rxFifoBlock;
1207            rxFragPtr = rxDescCache.bufptr;
1208            rxDescCnt = rxDescCache.cmdsts & CMDSTS_LEN_MASK;
1209        }
1210        break;
1211
1212      case rxFifoBlock:
1213        if (!rxPacket) {
1214            /**
1215             * @todo in reality, we should be able to start processing
1216             * the packet as it arrives, and not have to wait for the
1217             * full packet ot be in the receive fifo.
1218             */
1219            if (rxFifo.empty())
1220                goto exit;
1221
1222            // If we don't have a packet, grab a new one from the fifo.
1223            rxPacket = rxFifo.front();
1224            rxPktBytes = rxPacket->length;
1225            rxPacketBufPtr = rxPacket->data;
1226
1227            // sanity check - i think the driver behaves like this
1228            assert(rxDescCnt >= rxPktBytes);
1229
1230            // Must clear the value before popping to decrement the
1231            // reference count
1232            rxFifo.front() = NULL;
1233            rxFifo.pop_front();
1234        }
1235
1236
1237        // dont' need the && rxDescCnt > 0 if driver sanity check above holds
1238        if (rxPktBytes > 0) {
1239            rxState = rxFragWrite;
1240            // don't need min<>(rxPktBytes,rxDescCnt) if above sanity check holds
1241            rxXferLen = rxPktBytes;
1242
1243            rxDmaAddr = rxFragPtr & 0x3fffffff;
1244            rxDmaData = rxPacketBufPtr;
1245            rxDmaLen = rxXferLen;
1246            rxDmaFree = dmaDataFree;
1247
1248            if (doRxDmaWrite())
1249                goto exit;
1250
1251        } else {
1252            rxState = rxDescWrite;
1253
1254            //if (rxPktBytes == 0) {  /* packet is done */
1255            assert(rxPktBytes == 0);
1256
1257            rxFifoCnt -= rxPacket->length;
1258            rxPacket = 0;
1259
1260            rxDescCache.cmdsts |= CMDSTS_OWN;
1261            rxDescCache.cmdsts &= ~CMDSTS_MORE;
1262            rxDescCache.cmdsts |= CMDSTS_OK;
1263            rxDescCache.cmdsts += rxPacket->length;   //i.e. set CMDSTS_SIZE
1264
1265#if 0
1266            /* all the driver uses these are for its own stats keeping
1267               which we don't care about, aren't necessary for functionality
1268               and doing this would just slow us down.  if they end up using
1269               this in a later version for functional purposes, just undef
1270            */
1271            if (rxFilterEnable) {
1272                rxDescCache.cmdsts &= ~CMDSTS_DEST_MASK;
1273                if (rxFifo.front()->IsUnicast())
1274                    rxDescCache.cmdsts |= CMDSTS_DEST_SELF;
1275                if (rxFifo.front()->IsMulticast())
1276                    rxDescCache.cmdsts |= CMDSTS_DEST_MULTI;
1277                if (rxFifo.front()->IsBroadcast())
1278                    rxDescCache.cmdsts |= CMDSTS_DEST_MASK;
1279            }
1280#endif
1281
1282            eth_header *eth = (eth_header *) rxPacket->data;
1283            // eth->type 0x800 indicated that it's an ip packet.
1284            if (eth->type == 0x800 && extstsEnable) {
1285                rxDescCache.extsts |= EXTSTS_IPPKT;
1286                if (!ipChecksum(rxPacket, false))
1287                    rxDescCache.extsts |= EXTSTS_IPERR;
1288                ip_header *ip = rxFifo.front()->getIpHdr();
1289
1290                if (ip->protocol == 6) {
1291                    rxDescCache.extsts |= EXTSTS_TCPPKT;
1292                    if (!tcpChecksum(rxPacket, false))
1293                        rxDescCache.extsts |= EXTSTS_TCPERR;
1294                } else if (ip->protocol == 17) {
1295                    rxDescCache.extsts |= EXTSTS_UDPPKT;
1296                    if (!udpChecksum(rxPacket, false))
1297                        rxDescCache.extsts |= EXTSTS_UDPERR;
1298                }
1299            }
1300
1301            /* the driver seems to always receive into desc buffers
1302               of size 1514, so you never have a pkt that is split
1303               into multiple descriptors on the receive side, so
1304               i don't implement that case, hence the assert above.
1305            */
1306
1307            rxDmaAddr = (regs.rxdp + offsetof(ns_desc, cmdsts)) & 0x3fffffff;
1308            rxDmaData = &(rxDescCache.cmdsts);
1309            rxDmaLen = sizeof(rxDescCache.cmdsts) + sizeof(rxDescCache.extsts);
1310            rxDmaFree = dmaDescFree;
1311
1312            if (doRxDmaWrite())
1313                goto exit;
1314        }
1315        break;
1316
1317      case rxFragWrite:
1318        if (rxDmaState != dmaIdle)
1319            goto exit;
1320
1321        rxPacketBufPtr += rxXferLen;
1322        rxFragPtr += rxXferLen;
1323        rxPktBytes -= rxXferLen;
1324
1325        rxState = rxFifoBlock;
1326        break;
1327
1328      case rxDescWrite:
1329        if (rxDmaState != dmaIdle)
1330            goto exit;
1331
1332        assert(rxDescCache.cmdsts & CMDSTS_OWN);
1333
1334        assert(rxPacket == 0);
1335        devIntrPost(ISR_RXOK);
1336
1337        if (rxDescCache.cmdsts & CMDSTS_INTR)
1338            devIntrPost(ISR_RXDESC);
1339
1340        if (rxHalt) {
1341            rxState = rxIdle;
1342            rxHalt = false;
1343        } else
1344            rxState = rxAdvance;
1345        break;
1346
1347      case rxAdvance:
1348        if (rxDescCache.link == 0) {
1349            rxState = rxIdle;
1350            return;
1351        } else {
1352            rxState = rxDescRead;
1353            regs.rxdp = rxDescCache.link;
1354            CRDD = false;
1355
1356            rxDmaAddr = regs.rxdp & 0x3fffffff;
1357            rxDmaData = &rxDescCache;
1358            rxDmaLen = sizeof(ns_desc);
1359            rxDmaFree = dmaDescFree;
1360
1361            if (doRxDmaRead())
1362                goto exit;
1363        }
1364        break;
1365
1366      default:
1367        panic("Invalid rxState!");
1368    }
1369
1370
1371    DPRINTF(Ethernet, "entering next rx state = %s\n",
1372            NsRxStateStrings[rxState]);
1373
1374    if (rxState == rxIdle) {
1375        regs.command &= ~CR_RXE;
1376        devIntrPost(ISR_RXIDLE);
1377        return;
1378    }
1379
1380    goto next;
1381
1382  exit:
1383    /**
1384     * @todo do we want to schedule a future kick?
1385     */
1386    DPRINTF(Ethernet, "rx state machine exited state=%s\n",
1387            NsRxStateStrings[rxState]);
1388}
1389
1390void
1391NSGigE::transmit()
1392{
1393    if (txFifo.empty()) {
1394        DPRINTF(Ethernet, "nothing to transmit\n");
1395        return;
1396    }
1397
1398   if (interface->sendPacket(txFifo.front())) {
1399        DPRINTF(Ethernet, "transmit packet\n");
1400        DDUMP(Ethernet, txFifo.front()->data, txFifo.front()->length);
1401        txBytes += txFifo.front()->length;
1402        txPackets++;
1403
1404        txFifoCnt -= (txFifo.front()->length - txPktXmitted);
1405        txPktXmitted = 0;
1406        txFifo.front() = NULL;
1407        txFifo.pop_front();
1408
1409        /* normally do a writeback of the descriptor here, and ONLY after that is
1410           done, send this interrupt.  but since our stuff never actually fails,
1411           just do this interrupt here, otherwise the code has to stray from this
1412           nice format.  besides, it's functionally the same.
1413        */
1414        devIntrPost(ISR_TXOK);
1415   }
1416
1417   if (!txFifo.empty() && !txEvent.scheduled()) {
1418       DPRINTF(Ethernet, "reschedule transmit\n");
1419       txEvent.schedule(curTick + 1000);
1420   }
1421}
1422
1423void
1424NSGigE::txDmaReadCopy()
1425{
1426    assert(txDmaState == dmaReading);
1427
1428    memcpy(txDmaData, physmem->dma_addr(txDmaAddr, txDmaLen), txDmaLen);
1429    txDmaState = dmaIdle;
1430
1431    DPRINTF(EthernetDMA, "tx dma read  paddr=%#x len=%d\n",
1432            txDmaAddr, txDmaLen);
1433    DDUMP(EthernetDMA, txDmaData, txDmaLen);
1434}
1435
1436bool
1437NSGigE::doTxDmaRead()
1438{
1439    assert(txDmaState == dmaIdle || txDmaState == dmaReadWaiting);
1440    txDmaState = dmaReading;
1441
1442    if (dmaInterface && !txDmaFree) {
1443        if (dmaInterface->busy())
1444            txDmaState = dmaReadWaiting;
1445        else
1446            dmaInterface->doDMA(Read, txDmaAddr, txDmaLen, curTick,
1447                                &txDmaReadEvent);
1448        return true;
1449    }
1450
1451    if (dmaReadDelay == 0 && dmaReadFactor == 0.0) {
1452        txDmaReadCopy();
1453        return false;
1454    }
1455
1456    Tick factor = ((txDmaLen + ULL(63)) >> ULL(6)) * dmaReadFactor;
1457    Tick start = curTick + dmaReadDelay + factor;
1458    txDmaReadEvent.schedule(start);
1459    return true;
1460}
1461
1462void
1463NSGigE::txDmaReadDone()
1464{
1465    assert(txDmaState == dmaReading);
1466    txDmaReadCopy();
1467
1468    // If the receive state machine  has a pending DMA, let it go first
1469    if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting)
1470        rxKick();
1471
1472    txKick();
1473}
1474
1475void
1476NSGigE::txDmaWriteCopy()
1477{
1478    assert(txDmaState == dmaWriting);
1479
1480    memcpy(physmem->dma_addr(txDmaAddr, txDmaLen), txDmaData, txDmaLen);
1481    txDmaState = dmaIdle;
1482
1483    DPRINTF(EthernetDMA, "tx dma write paddr=%#x len=%d\n",
1484            txDmaAddr, txDmaLen);
1485    DDUMP(EthernetDMA, txDmaData, txDmaLen);
1486}
1487
1488bool
1489NSGigE::doTxDmaWrite()
1490{
1491    assert(txDmaState == dmaIdle || txDmaState == dmaWriteWaiting);
1492    txDmaState = dmaWriting;
1493
1494    if (dmaInterface && !txDmaFree) {
1495        if (dmaInterface->busy())
1496            txDmaState = dmaWriteWaiting;
1497        else
1498            dmaInterface->doDMA(WriteInvalidate, txDmaAddr, txDmaLen, curTick,
1499                                &txDmaWriteEvent);
1500        return true;
1501    }
1502
1503    if (dmaWriteDelay == 0 && dmaWriteFactor == 0.0) {
1504        txDmaWriteCopy();
1505        return false;
1506    }
1507
1508    Tick factor = ((txDmaLen + ULL(63)) >> ULL(6)) * dmaWriteFactor;
1509    Tick start = curTick + dmaWriteDelay + factor;
1510    txDmaWriteEvent.schedule(start);
1511    return true;
1512}
1513
1514void
1515NSGigE::txDmaWriteDone()
1516{
1517    assert(txDmaState == dmaWriting);
1518    txDmaWriteCopy();
1519
1520    // If the receive state machine  has a pending DMA, let it go first
1521    if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting)
1522        rxKick();
1523
1524    txKick();
1525}
1526
1527void
1528NSGigE::txKick()
1529{
1530    DPRINTF(Ethernet, "transmit kick state=%s\n", NsTxStateStrings[txState]);
1531
1532    if (rxKickTick > curTick) {
1533        DPRINTF(Ethernet, "receive kick exiting, can't run till %d\n",
1534                rxKickTick);
1535
1536        return;
1537    }
1538
1539  next:
1540    switch(txDmaState) {
1541      case dmaReadWaiting:
1542        if (doTxDmaRead())
1543            goto exit;
1544        break;
1545      case dmaWriteWaiting:
1546        if (doTxDmaWrite())
1547            goto exit;
1548        break;
1549      default:
1550        break;
1551    }
1552
1553    switch (txState) {
1554      case txIdle:
1555        if (!regs.command & CR_TXE) {
1556            DPRINTF(Ethernet, "Transmit disabled.  Nothing to do.\n");
1557            goto exit;
1558        }
1559
1560        if (CTDD) {
1561            txState = txDescRefr;
1562
1563            txDmaAddr = txDescCache.link & 0x3fffffff;
1564            txDmaData = &txDescCache;
1565            txDmaLen = sizeof(txDescCache.link);
1566            txDmaFree = dmaDescFree;
1567
1568            if (doTxDmaRead())
1569                goto exit;
1570
1571        } else {
1572            txState = txDescRead;
1573
1574            txDmaAddr = regs.txdp & 0x3fffffff;
1575            txDmaData = &txDescCache + offsetof(ns_desc, link);
1576            txDmaLen = sizeof(ns_desc);
1577            txDmaFree = dmaDescFree;
1578
1579            if (doTxDmaRead())
1580                goto exit;
1581        }
1582        break;
1583
1584      case txDescRefr:
1585        if (txDmaState != dmaIdle)
1586            goto exit;
1587
1588        txState = txAdvance;
1589        break;
1590
1591      case txDescRead:
1592        if (txDmaState != dmaIdle)
1593            goto exit;
1594
1595        if (txDescCache.cmdsts & CMDSTS_OWN) {
1596            txState = txFifoBlock;
1597            txFragPtr = txDescCache.bufptr;
1598            txDescCnt = txDescCache.cmdsts & CMDSTS_LEN_MASK;
1599        } else {
1600            txState = txIdle;
1601        }
1602        break;
1603
1604      case txFifoBlock:
1605        if (!txPacket) {
1606            DPRINTF(Ethernet, "starting the tx of a new packet\n");
1607            txPacket = new EtherPacket;
1608            txPacket->data = new uint8_t[16384];
1609            txPacketBufPtr = txPacket->data;
1610        }
1611
1612        if (txDescCnt == 0) {
1613            DPRINTF(Ethernet, "the txDescCnt == 0, done with descriptor\n");
1614            if (txDescCache.cmdsts & CMDSTS_MORE) {
1615                DPRINTF(Ethernet, "there are more descriptors to come\n");
1616                txState = txDescWrite;
1617
1618                txDescCache.cmdsts &= ~CMDSTS_OWN;
1619
1620                txDmaAddr = (regs.txdp + offsetof(ns_desc, cmdsts)) & 0x3fffffff;
1621                txDmaData = &(txDescCache.cmdsts);
1622                txDmaLen = sizeof(txDescCache.cmdsts);
1623                txDmaFree = dmaDescFree;
1624
1625                if (doTxDmaWrite())
1626                    goto exit;
1627
1628            } else { /* this packet is totally done */
1629                DPRINTF(Ethernet, "This packet is done, let's wrap it up\n");
1630                /* deal with the the packet that just finished */
1631                if ((regs.vtcr & VTCR_PPCHK) && extstsEnable) {
1632                    if (txDescCache.extsts & EXTSTS_UDPPKT) {
1633                        udpChecksum(txPacket, true);
1634                    } else if (txDescCache.extsts & EXTSTS_TCPPKT) {
1635                        tcpChecksum(txPacket, true);
1636                    } else if (txDescCache.extsts & EXTSTS_IPPKT) {
1637                        ipChecksum(txPacket, true);
1638                    }
1639                }
1640
1641                txPacket->length = txPacketBufPtr - txPacket->data;
1642                /* this is just because the receive can't handle a packet bigger
1643                   want to make sure */
1644                assert(txPacket->length <= 1514);
1645                txFifo.push_back(txPacket);
1646
1647
1648                /* this following section is not to spec, but functionally shouldn't
1649                   be any different.  normally, the chip will wait til the transmit has
1650                   occurred before writing back the descriptor because it has to wait
1651                   to see that it was successfully transmitted to decide whether to set
1652                   CMDSTS_OK or not.  however, in the simulator since it is always
1653                   successfully transmitted, and writing it exactly to spec would
1654                   complicate the code, we just do it here
1655                */
1656                txDescCache.cmdsts &= ~CMDSTS_OWN;
1657                txDescCache.cmdsts |= CMDSTS_OK;
1658
1659                txDmaAddr = regs.txdp & 0x3fffffff;
1660                txDmaData = &txDescCache + offsetof(ns_desc, cmdsts);
1661                txDmaLen = sizeof(txDescCache.cmdsts) + sizeof(txDescCache.extsts);
1662                txDmaFree = dmaDescFree;
1663
1664
1665                if (doTxDmaWrite())
1666                    goto exit;
1667
1668                txPacket = 0;
1669                transmit();
1670
1671                if (txHalt) {
1672                    txState = txIdle;
1673                    txHalt = false;
1674                } else
1675                    txState = txAdvance;
1676            }
1677        } else {
1678            DPRINTF(Ethernet, "this descriptor isn't done yet\n");
1679            /* the fill thresh is in units of 32 bytes, shift right by 8 to get the
1680               value, shift left by 5 to get the real number of bytes */
1681            if (txFifoAvail < ((regs.txcfg & TXCFG_FLTH_MASK) >> 3)) {
1682                DPRINTF(Ethernet, "txFifoAvail=%d, regs.txcfg & TXCFG_FLTH_MASK = %#x\n",
1683                        txFifoAvail, regs.txcfg & TXCFG_FLTH_MASK);
1684                goto exit;
1685            }
1686
1687            txState = txFragRead;
1688
1689            /* The number of bytes transferred is either whatever is left
1690               in the descriptor (txDescCnt), or if there is not enough
1691               room in the fifo, just whatever room is left in the fifo
1692            */
1693            txXferLen = min<uint32_t>(txDescCnt, txFifoAvail);
1694
1695            txDmaAddr = txFragPtr & 0x3fffffff;
1696            txDmaData = txPacketBufPtr;
1697            txDmaLen = txXferLen;
1698            txDmaFree = dmaDataFree;
1699
1700            if (doTxDmaRead())
1701                goto exit;
1702        }
1703        break;
1704
1705      case txFragRead:
1706        if (txDmaState != dmaIdle)
1707            goto exit;
1708
1709        txPacketBufPtr += txXferLen;
1710        txFragPtr += txXferLen;
1711        txFifoCnt += txXferLen;
1712        txDescCnt -= txXferLen;
1713
1714        txState = txFifoBlock;
1715        break;
1716
1717      case txDescWrite:
1718        if (txDmaState != dmaIdle)
1719            goto exit;
1720
1721        if (txFifoCnt >= ((regs.txcfg & TXCFG_DRTH_MASK) << 5)) {
1722            if (txFifo.empty()) {
1723                uint32_t xmitted = (uint32_t) (txPacketBufPtr - txPacket->data - txPktXmitted);
1724                txFifoCnt -= xmitted;
1725                txPktXmitted += xmitted;
1726            } else {
1727                transmit();
1728            }
1729        }
1730
1731        if (txDescCache.cmdsts & CMDSTS_INTR) {
1732            devIntrPost(ISR_TXDESC);
1733        }
1734
1735        txState = txAdvance;
1736        break;
1737
1738      case txAdvance:
1739        if (txDescCache.link == 0) {
1740            txState = txIdle;
1741        } else {
1742            txState = txDescRead;
1743            regs.txdp = txDescCache.link;
1744            CTDD = false;
1745
1746            txDmaAddr = txDescCache.link & 0x3fffffff;
1747            txDmaData = &txDescCache;
1748            txDmaLen = sizeof(ns_desc);
1749            txDmaFree = dmaDescFree;
1750
1751            if (doTxDmaRead())
1752                goto exit;
1753        }
1754        break;
1755
1756      default:
1757        panic("invalid state");
1758    }
1759
1760    DPRINTF(Ethernet, "entering next tx state=%s\n",
1761            NsTxStateStrings[txState]);
1762
1763    if (txState == txIdle) {
1764        regs.command &= ~CR_TXE;
1765        devIntrPost(ISR_TXIDLE);
1766        return;
1767    }
1768
1769    goto next;
1770
1771  exit:
1772    /**
1773     * @todo do we want to schedule a future kick?
1774     */
1775    DPRINTF(Ethernet, "tx state machine exited state=%s\n",
1776            NsTxStateStrings[txState]);
1777}
1778
1779void
1780NSGigE::transferDone()
1781{
1782    if (txFifo.empty())
1783        return;
1784
1785    DPRINTF(Ethernet, "schedule transmit\n");
1786
1787    if (txEvent.scheduled())
1788        txEvent.reschedule(curTick + 1);
1789    else
1790        txEvent.schedule(curTick + 1);
1791}
1792
1793bool
1794NSGigE::rxFilter(PacketPtr packet)
1795{
1796    bool drop = true;
1797    string type;
1798
1799    if (packet->IsUnicast()) {
1800        type = "unicast";
1801
1802        // If we're accepting all unicast addresses
1803        if (acceptUnicast)
1804            drop = false;
1805
1806        // If we make a perfect match
1807        if ((acceptPerfect)
1808            && (memcmp(rom.perfectMatch, packet->data, sizeof(rom.perfectMatch)) == 0))
1809            drop = false;
1810
1811        eth_header *eth = (eth_header *) packet->data;
1812        if ((acceptArp) && (eth->type == 0x806))
1813            drop = false;
1814
1815    } else if (packet->IsBroadcast()) {
1816        type = "broadcast";
1817
1818        // if we're accepting broadcasts
1819        if (acceptBroadcast)
1820            drop = false;
1821
1822    } else if (packet->IsMulticast()) {
1823        type = "multicast";
1824
1825        // if we're accepting all multicasts
1826        if (acceptMulticast)
1827            drop = false;
1828
1829    } else {
1830        type = "unknown";
1831
1832        // oh well, punt on this one
1833    }
1834
1835    if (drop) {
1836        DPRINTF(Ethernet, "rxFilter drop\n");
1837        DDUMP(EthernetData, packet->data, packet->length);
1838    }
1839
1840    return drop;
1841}
1842
1843bool
1844NSGigE::recvPacket(PacketPtr packet)
1845{
1846    rxBytes += packet->length;
1847    rxPackets++;
1848
1849    if (rxState == rxIdle) {
1850        DPRINTF(Ethernet, "receive disabled...packet dropped\n");
1851        interface->recvDone();
1852        return true;
1853    }
1854
1855    if (rxFilterEnable && rxFilter(packet)) {
1856        DPRINTF(Ethernet, "packet filtered...dropped\n");
1857        interface->recvDone();
1858        return true;
1859    }
1860
1861    if (rxFifoCnt + packet->length >= MAX_RX_FIFO_SIZE) {
1862        DPRINTF(Ethernet,
1863                "packet will not fit in receive buffer...packet dropped\n");
1864        devIntrPost(ISR_RXORN);
1865        return false;
1866    }
1867
1868    rxFifo.push_back(packet);
1869    rxFifoCnt += packet->length;
1870    interface->recvDone();
1871
1872    rxKick();
1873    return true;
1874}
1875
1876/**
1877 * does a udp checksum.  if gen is true, then it generates it and puts it in the right place
1878 * else, it just checks what it calculates against the value in the header in packet
1879 */
1880bool
1881NSGigE::udpChecksum(PacketPtr packet, bool gen)
1882{
1883    udp_header *hdr = (udp_header *)  packet->getTransportHdr();
1884
1885    ip_header *ip = packet->getIpHdr();
1886
1887    pseudo_header *pseudo = new pseudo_header;
1888
1889    pseudo->src_ip_addr = ip->src_ip_addr;
1890    pseudo->dest_ip_addr = ip->dest_ip_addr;
1891    pseudo->protocol = ip->protocol;
1892    pseudo->len = hdr->len;
1893
1894    uint16_t cksum = checksumCalc((uint16_t *) pseudo, (uint16_t *) hdr,
1895                                  (uint32_t) hdr->len);
1896
1897    delete pseudo;
1898    if (gen)
1899        hdr->chksum = cksum;
1900    else
1901        if (cksum != 0)
1902            return false;
1903
1904    return true;
1905}
1906
1907bool
1908NSGigE::tcpChecksum(PacketPtr packet, bool gen)
1909{
1910    tcp_header *hdr = (tcp_header *) packet->getTransportHdr();
1911
1912    ip_header *ip = packet->getIpHdr();
1913
1914    pseudo_header *pseudo = new pseudo_header;
1915
1916    pseudo->src_ip_addr = ip->src_ip_addr;
1917    pseudo->dest_ip_addr = ip->dest_ip_addr;
1918    pseudo->protocol = ip->protocol;
1919    pseudo->len = ip->dgram_len - (ip->vers_len & 0xf);
1920
1921    uint16_t cksum = checksumCalc((uint16_t *) pseudo, (uint16_t *) hdr,
1922                                  (uint32_t) pseudo->len);
1923
1924    delete pseudo;
1925    if (gen)
1926        hdr->chksum = cksum;
1927    else
1928        if (cksum != 0)
1929            return false;
1930
1931    return true;
1932}
1933
1934bool
1935NSGigE::ipChecksum(PacketPtr packet, bool gen)
1936{
1937    ip_header *hdr = packet->getIpHdr();
1938
1939    uint16_t cksum = checksumCalc(NULL, (uint16_t *) hdr, (hdr->vers_len & 0xf));
1940
1941    if (gen)
1942        hdr->hdr_chksum = cksum;
1943    else
1944        if (cksum != 0)
1945            return false;
1946
1947    return true;
1948}
1949
1950uint16_t
1951NSGigE::checksumCalc(uint16_t *pseudo, uint16_t *buf, uint32_t len)
1952{
1953    uint32_t sum = 0;
1954
1955    uint16_t last_pad = 0;
1956    if (len & 1) {
1957        last_pad = buf[len/2] & 0xff;
1958        len--;
1959        sum += last_pad;
1960    }
1961
1962    if (pseudo) {
1963        sum = pseudo[0] + pseudo[1] + pseudo[2] +
1964            pseudo[3] + pseudo[4] + pseudo[5];
1965    }
1966
1967    for (int i=0; i < (len/2); ++i) {
1968        sum += buf[i];
1969    }
1970
1971    while (sum >> 16)
1972        sum = (sum >> 16) + (sum & 0xffff);
1973
1974    return ~sum;
1975}
1976
1977//=====================================================================
1978//
1979//
1980void
1981NSGigE::serialize(ostream &os)
1982{
1983    /*
1984     * Finalize any DMA events now.
1985     */
1986    if (rxDmaReadEvent.scheduled())
1987        rxDmaReadCopy();
1988    if (rxDmaWriteEvent.scheduled())
1989        rxDmaWriteCopy();
1990    if (txDmaReadEvent.scheduled())
1991        txDmaReadCopy();
1992    if (txDmaWriteEvent.scheduled())
1993        txDmaWriteCopy();
1994
1995    /*
1996     * Serialize the device registers
1997     */
1998    SERIALIZE_SCALAR(regs.command);
1999    SERIALIZE_SCALAR(regs.config);
2000    SERIALIZE_SCALAR(regs.mear);
2001    SERIALIZE_SCALAR(regs.ptscr);
2002    SERIALIZE_SCALAR(regs.isr);
2003    SERIALIZE_SCALAR(regs.imr);
2004    SERIALIZE_SCALAR(regs.ier);
2005    SERIALIZE_SCALAR(regs.ihr);
2006    SERIALIZE_SCALAR(regs.txdp);
2007    SERIALIZE_SCALAR(regs.txdp_hi);
2008    SERIALIZE_SCALAR(regs.txcfg);
2009    SERIALIZE_SCALAR(regs.gpior);
2010    SERIALIZE_SCALAR(regs.rxdp);
2011    SERIALIZE_SCALAR(regs.rxdp_hi);
2012    SERIALIZE_SCALAR(regs.rxcfg);
2013    SERIALIZE_SCALAR(regs.pqcr);
2014    SERIALIZE_SCALAR(regs.wcsr);
2015    SERIALIZE_SCALAR(regs.pcr);
2016    SERIALIZE_SCALAR(regs.rfcr);
2017    SERIALIZE_SCALAR(regs.rfdr);
2018    SERIALIZE_SCALAR(regs.srr);
2019    SERIALIZE_SCALAR(regs.mibc);
2020    SERIALIZE_SCALAR(regs.vrcr);
2021    SERIALIZE_SCALAR(regs.vtcr);
2022    SERIALIZE_SCALAR(regs.vdr);
2023    SERIALIZE_SCALAR(regs.ccsr);
2024    SERIALIZE_SCALAR(regs.tbicr);
2025    SERIALIZE_SCALAR(regs.tbisr);
2026    SERIALIZE_SCALAR(regs.tanar);
2027    SERIALIZE_SCALAR(regs.tanlpar);
2028    SERIALIZE_SCALAR(regs.taner);
2029    SERIALIZE_SCALAR(regs.tesr);
2030
2031    SERIALIZE_ARRAY(rom.perfectMatch, EADDR_LEN);
2032
2033    /*
2034     * Serialize the various helper variables
2035     */
2036    uint32_t txPktBufPtr = (uint32_t) txPacketBufPtr;
2037    SERIALIZE_SCALAR(txPktBufPtr);
2038    uint32_t rxPktBufPtr = (uint32_t) rxPktBufPtr;
2039    SERIALIZE_SCALAR(rxPktBufPtr);
2040    SERIALIZE_SCALAR(txXferLen);
2041    SERIALIZE_SCALAR(rxXferLen);
2042    SERIALIZE_SCALAR(txPktXmitted);
2043
2044    bool txPacketExists = txPacket;
2045    SERIALIZE_SCALAR(txPacketExists);
2046    bool rxPacketExists = rxPacket;
2047    SERIALIZE_SCALAR(rxPacketExists);
2048
2049    /*
2050     * Serialize DescCaches
2051     */
2052    SERIALIZE_SCALAR(txDescCache.link);
2053    SERIALIZE_SCALAR(txDescCache.bufptr);
2054    SERIALIZE_SCALAR(txDescCache.cmdsts);
2055    SERIALIZE_SCALAR(txDescCache.extsts);
2056    SERIALIZE_SCALAR(rxDescCache.link);
2057    SERIALIZE_SCALAR(rxDescCache.bufptr);
2058    SERIALIZE_SCALAR(rxDescCache.cmdsts);
2059    SERIALIZE_SCALAR(rxDescCache.extsts);
2060
2061    /*
2062     * Serialize tx state machine
2063     */
2064    int txNumPkts = txFifo.size();
2065    SERIALIZE_SCALAR(txNumPkts);
2066    int txState = this->txState;
2067    SERIALIZE_SCALAR(txState);
2068    SERIALIZE_SCALAR(CTDD);
2069    SERIALIZE_SCALAR(txFifoCnt);
2070    SERIALIZE_SCALAR(txFifoAvail);
2071    SERIALIZE_SCALAR(txHalt);
2072    SERIALIZE_SCALAR(txFragPtr);
2073    SERIALIZE_SCALAR(txDescCnt);
2074    int txDmaState = this->txDmaState;
2075    SERIALIZE_SCALAR(txDmaState);
2076
2077    /*
2078     * Serialize rx state machine
2079     */
2080    int rxNumPkts = rxFifo.size();
2081    SERIALIZE_SCALAR(rxNumPkts);
2082    int rxState = this->rxState;
2083    SERIALIZE_SCALAR(rxState);
2084    SERIALIZE_SCALAR(CRDD);
2085    SERIALIZE_SCALAR(rxPktBytes);
2086    SERIALIZE_SCALAR(rxFifoCnt);
2087    SERIALIZE_SCALAR(rxHalt);
2088    SERIALIZE_SCALAR(rxDescCnt);
2089    int rxDmaState = this->rxDmaState;
2090    SERIALIZE_SCALAR(rxDmaState);
2091
2092    SERIALIZE_SCALAR(extstsEnable);
2093
2094   /*
2095     * If there's a pending transmit, store the time so we can
2096     * reschedule it later
2097     */
2098    Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick : 0;
2099    SERIALIZE_SCALAR(transmitTick);
2100
2101    /*
2102     * Keep track of pending interrupt status.
2103     */
2104    SERIALIZE_SCALAR(intrTick);
2105    SERIALIZE_SCALAR(cpuPendingIntr);
2106    Tick intrEventTick = 0;
2107    if (intrEvent)
2108        intrEventTick = intrEvent->when();
2109    SERIALIZE_SCALAR(intrEventTick);
2110
2111    int i = 0;
2112    for (pktiter_t p = rxFifo.begin(); p != rxFifo.end(); ++p) {
2113        nameOut(os, csprintf("%s.rxFifo%d", name(), i++));
2114        (*p)->serialize(os);
2115    }
2116    if (rxPacketExists) {
2117        nameOut(os, csprintf("%s.rxPacket", name()));
2118        rxPacket->serialize(os);
2119    }
2120    i = 0;
2121    for (pktiter_t p = txFifo.begin(); p != txFifo.end(); ++p) {
2122        nameOut(os, csprintf("%s.txFifo%d", name(), i++));
2123        (*p)->serialize(os);
2124    }
2125    if (txPacketExists) {
2126        nameOut(os, csprintf("%s.txPacket", name()));
2127        txPacket->serialize(os);
2128    }
2129}
2130
2131void
2132NSGigE::unserialize(Checkpoint *cp, const std::string &section)
2133{
2134    UNSERIALIZE_SCALAR(regs.command);
2135    UNSERIALIZE_SCALAR(regs.config);
2136    UNSERIALIZE_SCALAR(regs.mear);
2137    UNSERIALIZE_SCALAR(regs.ptscr);
2138    UNSERIALIZE_SCALAR(regs.isr);
2139    UNSERIALIZE_SCALAR(regs.imr);
2140    UNSERIALIZE_SCALAR(regs.ier);
2141    UNSERIALIZE_SCALAR(regs.ihr);
2142    UNSERIALIZE_SCALAR(regs.txdp);
2143    UNSERIALIZE_SCALAR(regs.txdp_hi);
2144    UNSERIALIZE_SCALAR(regs.txcfg);
2145    UNSERIALIZE_SCALAR(regs.gpior);
2146    UNSERIALIZE_SCALAR(regs.rxdp);
2147    UNSERIALIZE_SCALAR(regs.rxdp_hi);
2148    UNSERIALIZE_SCALAR(regs.rxcfg);
2149    UNSERIALIZE_SCALAR(regs.pqcr);
2150    UNSERIALIZE_SCALAR(regs.wcsr);
2151    UNSERIALIZE_SCALAR(regs.pcr);
2152    UNSERIALIZE_SCALAR(regs.rfcr);
2153    UNSERIALIZE_SCALAR(regs.rfdr);
2154    UNSERIALIZE_SCALAR(regs.srr);
2155    UNSERIALIZE_SCALAR(regs.mibc);
2156    UNSERIALIZE_SCALAR(regs.vrcr);
2157    UNSERIALIZE_SCALAR(regs.vtcr);
2158    UNSERIALIZE_SCALAR(regs.vdr);
2159    UNSERIALIZE_SCALAR(regs.ccsr);
2160    UNSERIALIZE_SCALAR(regs.tbicr);
2161    UNSERIALIZE_SCALAR(regs.tbisr);
2162    UNSERIALIZE_SCALAR(regs.tanar);
2163    UNSERIALIZE_SCALAR(regs.tanlpar);
2164    UNSERIALIZE_SCALAR(regs.taner);
2165    UNSERIALIZE_SCALAR(regs.tesr);
2166
2167    UNSERIALIZE_ARRAY(rom.perfectMatch, EADDR_LEN);
2168
2169    /*
2170     * unserialize the various helper variables
2171     */
2172    uint32_t txPktBufPtr;
2173    UNSERIALIZE_SCALAR(txPktBufPtr);
2174    txPacketBufPtr = (uint8_t *) txPktBufPtr;
2175    uint32_t rxPktBufPtr;
2176    UNSERIALIZE_SCALAR(rxPktBufPtr);
2177    rxPacketBufPtr = (uint8_t *) rxPktBufPtr;
2178    UNSERIALIZE_SCALAR(txXferLen);
2179    UNSERIALIZE_SCALAR(rxXferLen);
2180    UNSERIALIZE_SCALAR(txPktXmitted);
2181
2182    bool txPacketExists;
2183    UNSERIALIZE_SCALAR(txPacketExists);
2184    bool rxPacketExists;
2185    UNSERIALIZE_SCALAR(rxPacketExists);
2186
2187    /*
2188     * Unserialize DescCaches
2189     */
2190    UNSERIALIZE_SCALAR(txDescCache.link);
2191    UNSERIALIZE_SCALAR(txDescCache.bufptr);
2192    UNSERIALIZE_SCALAR(txDescCache.cmdsts);
2193    UNSERIALIZE_SCALAR(txDescCache.extsts);
2194    UNSERIALIZE_SCALAR(rxDescCache.link);
2195    UNSERIALIZE_SCALAR(rxDescCache.bufptr);
2196    UNSERIALIZE_SCALAR(rxDescCache.cmdsts);
2197    UNSERIALIZE_SCALAR(rxDescCache.extsts);
2198
2199    /*
2200     * unserialize tx state machine
2201     */
2202    int txNumPkts;
2203    UNSERIALIZE_SCALAR(txNumPkts);
2204    int txState;
2205    UNSERIALIZE_SCALAR(txState);
2206    this->txState = (TxState) txState;
2207    UNSERIALIZE_SCALAR(CTDD);
2208    UNSERIALIZE_SCALAR(txFifoCnt);
2209    UNSERIALIZE_SCALAR(txFifoAvail);
2210    UNSERIALIZE_SCALAR(txHalt);
2211    UNSERIALIZE_SCALAR(txFragPtr);
2212    UNSERIALIZE_SCALAR(txDescCnt);
2213    int txDmaState;
2214    UNSERIALIZE_SCALAR(txDmaState);
2215    this->txDmaState = (DmaState) txDmaState;
2216
2217    /*
2218     * unserialize rx state machine
2219     */
2220    int rxNumPkts;
2221    UNSERIALIZE_SCALAR(rxNumPkts);
2222    int rxState;
2223    UNSERIALIZE_SCALAR(rxState);
2224    this->rxState = (RxState) rxState;
2225    UNSERIALIZE_SCALAR(CRDD);
2226    UNSERIALIZE_SCALAR(rxPktBytes);
2227    UNSERIALIZE_SCALAR(rxFifoCnt);
2228    UNSERIALIZE_SCALAR(rxHalt);
2229    UNSERIALIZE_SCALAR(rxDescCnt);
2230    int rxDmaState;
2231    UNSERIALIZE_SCALAR(rxDmaState);
2232    this->rxDmaState = (DmaState) rxDmaState;
2233
2234    UNSERIALIZE_SCALAR(extstsEnable);
2235
2236     /*
2237     * If there's a pending transmit, store the time so we can
2238     * reschedule it later
2239     */
2240    Tick transmitTick;
2241    UNSERIALIZE_SCALAR(transmitTick);
2242    if (transmitTick)
2243        txEvent.schedule(curTick + transmitTick);
2244
2245    /*
2246     * Keep track of pending interrupt status.
2247     */
2248    UNSERIALIZE_SCALAR(intrTick);
2249    UNSERIALIZE_SCALAR(cpuPendingIntr);
2250    Tick intrEventTick;
2251    UNSERIALIZE_SCALAR(intrEventTick);
2252    if (intrEventTick) {
2253        intrEvent = new IntrEvent(this, true);
2254        intrEvent->schedule(intrEventTick);
2255    }
2256
2257    for (int i = 0; i < rxNumPkts; ++i) {
2258        PacketPtr p = new EtherPacket;
2259        p->unserialize(cp, csprintf("%s.rxFifo%d", section, i));
2260        rxFifo.push_back(p);
2261    }
2262    rxPacket = NULL;
2263    if (rxPacketExists) {
2264        rxPacket = new EtherPacket;
2265        rxPacket->unserialize(cp, csprintf("%s.rxPacket", section));
2266    }
2267    for (int i = 0; i < txNumPkts; ++i) {
2268        PacketPtr p = new EtherPacket;
2269        p->unserialize(cp, csprintf("%s.rxFifo%d", section, i));
2270        txFifo.push_back(p);
2271    }
2272    if (txPacketExists) {
2273        txPacket = new EtherPacket;
2274        txPacket->unserialize(cp, csprintf("%s.txPacket", section));
2275    }
2276}
2277
2278
2279Tick
2280NSGigE::cacheAccess(MemReqPtr &req)
2281{
2282    DPRINTF(EthernetPIO, "timing access to paddr=%#x (daddr=%#x)\n",
2283            req->paddr, req->paddr - addr);
2284    return curTick + pioLatency;
2285}
2286//=====================================================================
2287
2288
2289BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigEInt)
2290
2291    SimObjectParam<EtherInt *> peer;
2292    SimObjectParam<NSGigE *> device;
2293
2294END_DECLARE_SIM_OBJECT_PARAMS(NSGigEInt)
2295
2296BEGIN_INIT_SIM_OBJECT_PARAMS(NSGigEInt)
2297
2298    INIT_PARAM_DFLT(peer, "peer interface", NULL),
2299    INIT_PARAM(device, "Ethernet device of this interface")
2300
2301END_INIT_SIM_OBJECT_PARAMS(NSGigEInt)
2302
2303CREATE_SIM_OBJECT(NSGigEInt)
2304{
2305    NSGigEInt *dev_int = new NSGigEInt(getInstanceName(), device);
2306
2307    EtherInt *p = (EtherInt *)peer;
2308    if (p) {
2309        dev_int->setPeer(p);
2310        p->setPeer(dev_int);
2311    }
2312
2313    return dev_int;
2314}
2315
2316REGISTER_SIM_OBJECT("NSGigEInt", NSGigEInt)
2317
2318
2319BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigE)
2320
2321    Param<Tick> tx_delay;
2322    Param<Tick> rx_delay;
2323    SimObjectParam<IntrControl *> intr_ctrl;
2324    Param<Tick> intr_delay;
2325    SimObjectParam<MemoryController *> mmu;
2326    SimObjectParam<PhysicalMemory *> physmem;
2327    Param<Addr> addr;
2328    Param<bool> rx_filter;
2329    Param<string> hardware_address;
2330    SimObjectParam<Bus*> header_bus;
2331    SimObjectParam<Bus*> payload_bus;
2332    SimObjectParam<HierParams *> hier;
2333    Param<Tick> pio_latency;
2334    Param<bool> dma_desc_free;
2335    Param<bool> dma_data_free;
2336    Param<Tick> dma_read_delay;
2337    Param<Tick> dma_write_delay;
2338    Param<Tick> dma_read_factor;
2339    Param<Tick> dma_write_factor;
2340    SimObjectParam<PciConfigAll *> configspace;
2341    SimObjectParam<PciConfigData *> configdata;
2342    SimObjectParam<Tsunami *> tsunami;
2343    Param<uint32_t> pci_bus;
2344    Param<uint32_t> pci_dev;
2345    Param<uint32_t> pci_func;
2346
2347END_DECLARE_SIM_OBJECT_PARAMS(NSGigE)
2348
2349BEGIN_INIT_SIM_OBJECT_PARAMS(NSGigE)
2350
2351    INIT_PARAM_DFLT(tx_delay, "Transmit Delay", 1000),
2352    INIT_PARAM_DFLT(rx_delay, "Receive Delay", 1000),
2353    INIT_PARAM(intr_ctrl, "Interrupt Controller"),
2354    INIT_PARAM_DFLT(intr_delay, "Interrupt Delay in microseconds", 0),
2355    INIT_PARAM(mmu, "Memory Controller"),
2356    INIT_PARAM(physmem, "Physical Memory"),
2357    INIT_PARAM(addr, "Device Address"),
2358    INIT_PARAM_DFLT(rx_filter, "Enable Receive Filter", true),
2359    INIT_PARAM_DFLT(hardware_address, "Ethernet Hardware Address",
2360                    "00:99:00:00:00:01"),
2361    INIT_PARAM_DFLT(header_bus, "The IO Bus to attach to for headers", NULL),
2362    INIT_PARAM_DFLT(payload_bus, "The IO Bus to attach to for payload", NULL),
2363    INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams),
2364    INIT_PARAM_DFLT(pio_latency, "Programmed IO latency", 1000),
2365    INIT_PARAM_DFLT(dma_desc_free, "DMA of Descriptors is free", false),
2366    INIT_PARAM_DFLT(dma_data_free, "DMA of Data is free", false),
2367    INIT_PARAM_DFLT(dma_read_delay, "fixed delay for dma reads", 0),
2368    INIT_PARAM_DFLT(dma_write_delay, "fixed delay for dma writes", 0),
2369    INIT_PARAM_DFLT(dma_read_factor, "multiplier for dma reads", 0),
2370    INIT_PARAM_DFLT(dma_write_factor, "multiplier for dma writes", 0),
2371    INIT_PARAM(configspace, "PCI Configspace"),
2372    INIT_PARAM(configdata, "PCI Config data"),
2373    INIT_PARAM(tsunami, "Tsunami"),
2374    INIT_PARAM(pci_bus, "PCI bus"),
2375    INIT_PARAM(pci_dev, "PCI device number"),
2376    INIT_PARAM(pci_func, "PCI function code")
2377
2378END_INIT_SIM_OBJECT_PARAMS(NSGigE)
2379
2380
2381CREATE_SIM_OBJECT(NSGigE)
2382{
2383    int eaddr[6];
2384    sscanf(((string)hardware_address).c_str(), "%x:%x:%x:%x:%x:%x",
2385           &eaddr[0], &eaddr[1], &eaddr[2], &eaddr[3], &eaddr[4], &eaddr[5]);
2386
2387    return new NSGigE(getInstanceName(), intr_ctrl, intr_delay,
2388                        physmem, tx_delay, rx_delay, mmu, hier, header_bus,
2389                        payload_bus, pio_latency, dma_desc_free, dma_data_free,
2390                        dma_read_delay, dma_write_delay, dma_read_factor,
2391                        dma_write_factor, configspace, configdata,
2392                        tsunami, pci_bus, pci_dev, pci_func, rx_filter, eaddr,
2393                        addr);
2394}
2395
2396REGISTER_SIM_OBJECT("NSGigE", NSGigE)
2397