ns_gige.cc revision 837
1/*
2 * Copyright (c) 2003 The Regents of The University of Michigan
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/* @file
30 * Device module for modelling the National Semiconductor
31 * DP83820 ethernet controller.  Does not support priority queueing
32 */
33#include <cstdio>
34#include <deque>
35#include <string>
36
37#include "base/inet.hh"
38#include "cpu/exec_context.hh"
39#include "cpu/intr_control.hh"
40#include "dev/dma.hh"
41#include "dev/ns_gige.hh"
42#include "dev/etherlink.hh"
43#include "mem/functional_mem/memory_control.hh"
44#include "mem/functional_mem/physical_memory.hh"
45#include "sim/builder.hh"
46#include "sim/host.hh"
47#include "sim/sim_stats.hh"
48#include "targetarch/vtophys.hh"
49
50using namespace std;
51
52///////////////////////////////////////////////////////////////////////
53//
54// EtherDev PCI Device
55//
56EtherDev::EtherDev(const string &_name, DmaEngine *de, bool use_interface,
57                   IntrControl *i, MemoryController *mmu, PhysicalMemory *pmem,
58                   PCIConfigAll *cf, PciConfigData *cd, Tsunami *t, uint32_t bus,
59                   uint32_t dev, uint32_t func, bool rx_filter,
60                   const int eaddr[6], Tick tx_delay, Tick rx_delay, Addr addr,
61                   Addr mask)
62    : PciDev(_name, mmu, cf, cd, bus, dev, func), tsunami(t),
63      addr(addr), mask(mask), txPacketLen(0),
64      txPacketBufPtr(NULL), rxPacketBufPtr(NULL), rxDescBufPtr(NULL),
65      fragLen(0), rxCopied(0), txState(txIdle), CTDD(false), txFifoCnt(0),
66      txFifoAvail(MAX_TX_FIFO_SIZE), txHalt(false), txPacketFlag(false),
67      txFragPtr(0), txDescCnt(0), rxState(rxIdle), CRDD(false),
68      rxPktBytes(0), rxFifoCnt(0), rxHalt(false), rxPacketFlag(false),
69      rxFragPtr(0), rxDescCnt(0), extstsEnable(false), maxTxBurst(0),
70      maxRxBurst(0), physmem(pmem),
71      rxDescDoneCB(this), rxDoneCB(this), txDescDoneCB(this), txDoneCB(this),
72      dma(de), readRequest(use_interface), writeRequest(use_interface),
73      readDescRequest(use_interface), writeDescRequest(use_interface),
74      interface(NULL), intctrl(i), txDelay(tx_delay), rxDelay(rx_delay),
75      txEvent(this), cpuPendingIntr(false), rxFilterEnable(rx_filter),
76      acceptBroadcast(false), acceptMulticast(false), acceptUnicast(false),
77      acceptPerfect(false), acceptArp(false)
78{
79    tsunami->ethernet = this;
80
81    memset(&regs, 0, sizeof(regs));
82    regsReset();
83    regs.perfectMatch[0] = eaddr[0];
84    regs.perfectMatch[1] = eaddr[1];
85    regs.perfectMatch[2] = eaddr[2];
86    regs.perfectMatch[3] = eaddr[3];
87    regs.perfectMatch[4] = eaddr[4];
88    regs.perfectMatch[5] = eaddr[5];
89
90}
91
92EtherDev::~EtherDev()
93{}
94
95void
96EtherDev::regStats()
97{
98    txBytes
99        .name(name() + ".txBytes")
100        .desc("Bytes Transmitted")
101        .prereq(txBytes)
102        ;
103
104    rxBytes
105        .name(name() + ".rxBytes")
106        .desc("Bytes Received")
107        .prereq(rxBytes)
108        ;
109
110    txPackets
111        .name(name() + ".txPackets")
112        .desc("Number of Packets Transmitted")
113        .prereq(txBytes)
114        ;
115
116    rxPackets
117        .name(name() + ".rxPackets")
118        .desc("Number of Packets Received")
119        .prereq(rxBytes)
120        ;
121
122    txBandwidth
123        .name(name() + ".txBandwidth")
124        .desc("Transmit Bandwidth (bits/s)")
125        .precision(0)
126        .prereq(txBytes)
127        ;
128
129    rxBandwidth
130        .name(name() + ".rxBandwidth")
131        .desc("Receive Bandwidth (bits/s)")
132        .precision(0)
133        .prereq(rxBytes)
134        ;
135
136    txPacketRate
137        .name(name() + ".txPPS")
138        .desc("Packet Tranmission Rate (packets/s)")
139        .precision(0)
140        .prereq(txBytes)
141        ;
142
143    rxPacketRate
144        .name(name() + ".rxPPS")
145        .desc("Packet Reception Rate (packets/s)")
146        .precision(0)
147        .prereq(rxBytes)
148        ;
149
150    txBandwidth = txBytes * Statistics::constant(8) / simSeconds;
151    rxBandwidth = rxBytes * Statistics::constant(8) / simSeconds;
152    txPacketRate = txPackets / simSeconds;
153    rxPacketRate = rxPackets / simSeconds;
154}
155
156void
157EtherDev::ReadConfig(int offset, int size, uint8_t *data)
158{
159    if (offset < PCI_DEVICE_SPECIFIC)
160        PciDev::ReadConfig(offset, size, data);
161    else {
162        panic("need to do this\n");
163    }
164}
165
166void
167EtherDev::WriteConfig(int offset, int size, uint32_t data)
168{
169    if (offset < PCI_DEVICE_SPECIFIC)
170        PciDev::WriteConfig(offset, size, data);
171    else
172        panic("Need to do that\n");
173}
174
175Fault
176EtherDev::read(MemReqPtr req, uint8_t *data)
177{
178    DPRINTF(Ethernet, "read  va=%#x size=%d\n", req->vaddr, req->size);
179
180    Addr daddr = req->paddr - addr;
181
182    if (daddr > LAST)
183        panic("Accessing reserved register");
184
185    switch (req->size) {
186      case sizeof(uint32_t):
187        {
188            uint32_t &reg = *(uint32_t *)data;
189
190            switch (daddr) {
191              case CR:
192                reg = regs.command;
193                reg &= ~(CR_RXD | CR_TXD | CR_TXR | CR_RXR);
194                break;
195
196              case CFG:
197                reg = regs.config;
198                break;
199
200              case MEAR:
201                reg = regs.mear;
202                break;
203
204              case PTSCR:
205                reg = regs.ptscr;
206                break;
207
208              case ISR:
209                reg = regs.isr;
210                regs.isr = 0;
211                break;
212
213              case IMR:
214                reg = regs.imr;
215                break;
216
217              case IER:
218                reg = regs.ier;
219                break;
220
221              case IHR:
222                reg = regs.ihr;
223                break;
224
225              case TXDP:
226                reg = regs.txdp;
227                break;
228
229              case TXDP_HI:
230                reg = regs.txdp_hi;
231                break;
232
233              case TXCFG:
234                reg = regs.txcfg;
235                break;
236
237              case GPIOR:
238                reg = regs.gpior;
239                break;
240
241              case RXDP:
242                reg = regs.rxdp;
243                break;
244
245              case RXDP_HI:
246                reg = regs.rxdp_hi;
247                break;
248
249              case RXCFG:
250                reg = regs.rxcfg;
251                break;
252
253              case PQCR:
254                reg = regs.pqcr;
255                break;
256
257              case WCSR:
258                reg = regs.wcsr;
259                break;
260
261              case PCR:
262                reg = regs.pcr;
263                break;
264
265              case RFCR:
266                reg = regs.rfcr;
267                break;
268
269              case RFDR:
270
271                switch (regs.rfcr & RFCR_RFADDR) {
272                  case 0x000:
273                    reg = regs.perfectMatch[1] << 8;
274                    reg += regs.perfectMatch[0];
275                    break;
276                  case 0x002:
277                    reg = regs.perfectMatch[3] << 8;
278                    reg += regs.perfectMatch[2];
279                    break;
280                  case 0x004:
281                    reg = regs.perfectMatch[5] << 8;
282                    reg += regs.perfectMatch[4];
283                    break;
284                  default:
285                    panic("reading from RFDR for something for other than PMATCH!\n");
286                    //didn't implement other RFDR functionality b/c driver didn't use
287                }
288                break;
289
290              case SRR:
291                reg = regs.srr;
292                break;
293
294              case MIBC:
295                reg = regs.mibc;
296                reg &= ~(MIBC_MIBS | MIBC_ACLR);
297                break;
298
299              case VRCR:
300                reg = regs.vrcr;
301                break;
302
303              case VTCR:
304                reg = regs.vtcr;
305                break;
306
307              case VDR:
308                reg = regs.vdr;
309                break;
310
311              case CCSR:
312                reg = regs.ccsr;
313                break;
314
315              case TBICR:
316                reg = regs.tbicr;
317                break;
318
319              case TBISR:
320                reg = regs.tbisr;
321                break;
322
323              case TANAR:
324                reg = regs.tanar;
325                break;
326
327              case TANLPAR:
328                reg = regs.tanlpar;
329                break;
330
331              case TANER:
332                reg = regs.taner;
333                break;
334
335              case TESR:
336                reg = regs.tesr;
337                break;
338
339              default:
340                panic("reading unimplemented register: addr = %#x", daddr);
341            }
342
343            DPRINTF(Ethernet, "read from %#x: data=%d data=%#x\n", daddr, reg, reg);
344        }
345        break;
346
347      default:
348        panic("accessing register with invalid size: addr=%#x, size=%d",
349              daddr, req->size);
350    }
351
352    return No_Fault;
353}
354
355Fault
356EtherDev::write(MemReqPtr req, const uint8_t *data)
357{
358    DPRINTF(Ethernet, "write va=%#x size=%d\n", req->vaddr, req->size);
359
360    Addr daddr = req->paddr - addr;
361
362    if (daddr > LAST && daddr <= RESERVED)
363        panic("Accessing reserved register");
364
365    if (daddr > RESERVED)
366        panic("higher memory accesses not implemented!\n");
367
368    if (req->size == sizeof(uint32_t)) {
369        uint32_t reg = *(uint32_t *)data;
370        DPRINTF(Ethernet, "write data=%d data=%#x\n", reg, reg);
371
372        switch (daddr) {
373          case CR:
374            regs.command = reg;
375            if ((reg & (CR_TXE | CR_TXD)) == (CR_TXE | CR_TXD)) {
376                txHalt = true;
377            } else if (reg & CR_TXE) {
378                if (txState == txIdle)
379                    txKick();
380            } else if (reg & CR_TXD) {
381                txHalt = true;
382            }
383
384            if ((reg & (CR_RXE | CR_RXD)) == (CR_RXE | CR_RXD)) {
385                rxHalt = true;
386            } else if (reg & CR_RXE) {
387                if (rxState == rxIdle) {
388                    rxKick();
389                }
390            } else if (reg & CR_RXD) {
391                rxHalt = true;
392            }
393
394            if (reg & CR_TXR)
395                txReset();
396
397            if (reg & CR_RXR)
398                rxReset();
399
400            if (reg & CR_SWI)
401                devIntrPost(ISR_SWI);
402
403            if (reg & CR_RST) {
404                txReset();
405                rxReset();
406                regsReset();
407            }
408            break;
409
410          case CFG:
411            regs.config = reg;
412            if (reg & CFG_LNKSTS || reg & CFG_SPDSTS || reg & CFG_DUPSTS
413                || reg & CFG_RESERVED || reg & CFG_T64ADDR
414                || reg & CFG_PCI64_DET)
415                panic("writing to read-only or reserved CFG bits!\n");
416
417#if 0
418              if (reg & CFG_TBI_EN) ;
419              if (reg & CFG_MODE_1000) ;
420#endif
421
422            if (reg & CFG_AUTO_1000)
423                panic("CFG_AUTO_1000 not implemented!\n");
424
425#if 0
426            if (reg & CFG_PINT_DUPSTS || reg & CFG_PINT_LNKSTS || reg & CFG_PINT_SPDSTS) ;
427            if (reg & CFG_TMRTEST) ;
428            if (reg & CFG_MRM_DIS) ;
429            if (reg & CFG_MWI_DIS) ;
430#endif
431
432            if (reg & CFG_T64ADDR)
433                panic("CFG_T64ADDR is read only register!\n");
434
435            if (reg & CFG_PCI64_DET)
436                panic("CFG_PCI64_DET is read only register!\n");
437
438#if 0
439              if (reg & CFG_DATA64_EN) ;
440              if (reg & CFG_M64ADDR) ;
441              if (reg & CFG_PHY_RST) ;
442              if (reg & CFG_PHY_DIS) ;
443#endif
444
445            if (reg & CFG_EXTSTS_EN)
446                extstsEnable = true;
447            else
448                extstsEnable = false;
449
450#if 0
451              if (reg & CFG_REQALG) ;
452              if (reg & CFG_SB) ;
453              if (reg & CFG_POW) ;
454              if (reg & CFG_EXD) ;
455              if (reg & CFG_PESEL) ;
456              if (reg & CFG_BROM_DIS) ;
457              if (reg & CFG_EXT_125) ;
458              if (reg & CFG_BEM) ;
459#endif
460            break;
461
462          case MEAR:
463            regs.mear = reg;
464            /* since phy is completely faked, MEAR_MD* don't matter
465               and since the driver never uses MEAR_EE*, they don't matter */
466#if 0
467            if (reg & MEAR_EEDI) ;
468            if (reg & MEAR_EEDO) ; //this one is read only
469            if (reg & MEAR_EECLK) ;
470            if (reg & MEAR_EESEL) ;
471            if (reg & MEAR_MDIO) ;
472            if (reg & MEAR_MDDIR) ;
473            if (reg & MEAR_MDC) ;
474#endif
475            break;
476
477          case PTSCR:
478            regs.ptscr = reg;
479            /* these control BISTs for various parts of chip - we don't care or do */
480            break;
481
482          case ISR: /* writing to the ISR has no effect */
483            panic("ISR is a read only register!\n");
484
485          case IMR:
486            regs.imr = reg;
487            devIntrChangeMask();
488            break;
489
490          case IER:
491            regs.ier = reg;
492            break;
493
494          case IHR:
495            regs.ihr = reg;
496            /* not going to implement real interrupt holdoff */
497            break;
498
499          case TXDP:
500            regs.txdp = (reg & 0xFFFFFFFC);
501            assert(txState == txIdle);
502            CTDD = false;
503            break;
504
505          case TXDP_HI:
506            regs.txdp_hi = reg;
507            break;
508
509          case TXCFG:
510            regs.txcfg = reg;
511#if 0
512            if (reg & TXCFG_CSI) ;
513            if (reg & TXCFG_HBI) ;
514            if (reg & TXCFG_MLB) ;
515            if (reg & TXCFG_ATP) ;
516            if (reg & TXCFG_ECRETRY) ;  /* this could easily be implemented, but
517                                           considering the network is just a fake
518                                           pipe, wouldn't make sense to do this */
519
520            if (reg & TXCFG_BRST_DIS) ;
521#endif
522
523#if 0 /* current 2.6 driver doesn't use these.  if we upgrade, may need these */
524            if (reg & TXCFG_MXDMA1024)
525                maxTxBurst = 1024;
526
527            if (reg & TXCFG_MXDMA8)
528                maxTxBurst = 8;
529
530            if (reg & TXCFG_MXDMA16)
531                maxTxBurst = 16;
532
533            if (reg & TXCFG_MXDMA32)
534                maxTxBurst = 32;
535
536            if (reg & TXCFG_MXDMA64)
537                maxTxBurst = 64;
538
539            if (reg & TXCFG_MXDMA128)
540                maxTxBurst = 128;
541
542            if (reg & TXCFG_MXDMA256)
543                maxTxBurst = 256;
544#endif
545
546            if (reg & TXCFG_MXDMA512)
547                maxTxBurst = 512;
548
549            break;
550
551          case GPIOR:
552            regs.gpior = reg;
553            /* these just control general purpose i/o pins, don't matter */
554            break;
555
556          case RXCFG:
557            regs.rxcfg = reg;
558#if 0
559            if (reg & RXCFG_AEP) ;
560            if (reg & RXCFG_ARP) ;
561            if (reg & RXCFG_STRIPCRC) ;
562            if (reg & RXCFG_RX_RD) ;
563            if (reg & RXCFG_ALP) ;
564            if (reg & RXCFG_AIRL) ;
565#endif
566
567            if (reg & RXCFG_MXDMA512)
568                maxRxBurst = 512;
569
570#if 0
571            if (reg & (RXCFG_DRTH | RXCFG_DRTH0)) ;
572#endif
573            break;
574
575          case PQCR:
576            /* there is no priority queueing used in the linux 2.6 driver */
577            regs.pqcr = reg;
578            break;
579
580          case WCSR:
581            /* not going to implement wake on LAN */
582            regs.wcsr = reg;
583            break;
584
585          case PCR:
586            /* not going to implement pause control */
587            regs.pcr = reg;
588            break;
589
590          case RFCR:
591            regs.rfcr = reg;
592            rxFilterEnable = (reg & RFCR_RFEN) ? true : false;
593
594            acceptBroadcast = (reg & RFCR_AAB) ? true : false;
595
596            acceptMulticast = (reg & RFCR_AAM) ? true : false;
597
598            acceptUnicast = (reg & RFCR_AAU) ? true : false;
599
600            acceptPerfect = (reg & RFCR_APM) ? true : false;
601
602            acceptArp = (reg & RFCR_AARP) ? true : false;
603
604            if (reg & RFCR_APAT)
605                panic("RFCR_APAT not implemented!\n");
606
607            if (reg & RFCR_MHEN || reg & RFCR_UHEN)
608                panic("hash filtering not implemented!\n");
609
610            if (reg & RFCR_ULM)
611                panic("RFCR_ULM not implemented!\n");
612
613            break;
614
615          case RFDR:
616            panic("the driver never writes to RFDR, something is wrong!\n");
617
618          case BRAR:
619            panic("the driver never uses BRAR, something is wrong!\n");
620
621          case BRDR:
622            panic("the driver never uses BRDR, something is wrong!\n");
623
624          case SRR:
625            panic("SRR is read only register!\n");
626
627          case MIBC:
628            panic("the driver never uses MIBC, something is wrong!\n");
629
630          case VRCR:
631            regs.vrcr = reg;
632            break;
633
634          case VTCR:
635            regs.vtcr = reg;
636            break;
637
638          case VDR:
639            panic("the driver never uses VDR, something is wrong!\n");
640            break;
641
642          case CCSR:
643            /* not going to implement clockrun stuff */
644            regs.ccsr = reg;
645            break;
646
647          case TBICR:
648            regs.tbicr = reg;
649            if (reg & TBICR_MR_LOOPBACK)
650                panic("TBICR_MR_LOOPBACK never used, something wrong!\n");
651
652            if (reg & TBICR_MR_AN_ENABLE) {
653                regs.tanlpar = regs.tanar;
654                regs.tbisr |= (TBISR_MR_AN_COMPLETE | TBISR_MR_LINK_STATUS);
655            }
656
657#if 0
658            if (reg & TBICR_MR_RESTART_AN) ;
659#endif
660
661            break;
662
663          case TBISR:
664            panic("TBISR is read only register!\n");
665
666          case TANAR:
667            regs.tanar = reg;
668            if (reg & TANAR_PS2)
669                panic("this isn't used in driver, something wrong!\n");
670
671            if (reg & TANAR_PS1)
672                panic("this isn't used in driver, something wrong!\n");
673            break;
674
675          case TANLPAR:
676            panic("this should only be written to by the fake phy!\n");
677
678          case TANER:
679            panic("TANER is read only register!\n");
680
681          case TESR:
682            regs.tesr = reg;
683            break;
684
685          default:
686            panic("thought i covered all the register, what is this? addr=%#x",
687                  daddr);
688        }
689    } else
690        panic("Invalid Request Size");
691
692    return No_Fault;
693}
694
695void
696EtherDev::devIntrPost(uint32_t interrupts)
697{
698DPRINTF(Ethernet, "interrupt posted intr=%x isr=%x imr=%x\n",
699    interrupts, regs.isr, regs.imr);
700
701if (interrupts & ISR_RESERVE)
702    panic("Cannot set a reserved interrupt");
703
704if (interrupts & ISR_TXRCMP)
705    regs.isr |= ISR_TXRCMP;
706
707if (interrupts & ISR_RXRCMP)
708    regs.isr |= ISR_RXRCMP;
709
710//ISR_DPERR  not implemented
711//ISR_SSERR not implemented
712//ISR_RMABT not implemented
713//ISR_RXSOVR not implemented
714//ISR_HIBINT not implemented
715//ISR_PHY not implemented
716//ISR_PME not implemented
717
718if (interrupts & ISR_SWI)
719    regs.isr |= ISR_SWI;
720
721//ISR_MIB not implemented
722//ISR_TXURN not implemented
723
724 if (interrupts & ISR_TXIDLE)
725     regs.isr |= ISR_TXIDLE;
726
727 if (interrupts & ISR_TXERR)
728     regs.isr |= ISR_TXERR;
729
730 if (interrupts & ISR_TXDESC)
731     regs.isr |= ISR_TXDESC;
732
733 if (interrupts & ISR_TXOK)
734     regs.isr |= ISR_TXOK;
735
736 if (interrupts & ISR_RXORN)
737     regs.isr |= ISR_RXORN;
738
739 if (interrupts & ISR_RXIDLE)
740     regs.isr |= ISR_RXIDLE;
741
742//ISR_RXEARLY not implemented
743
744 if (interrupts & ISR_RXERR)
745     regs.isr |= ISR_RXERR;
746
747 if (interrupts & ISR_RXOK)
748     regs.isr |= ISR_RXOK;
749
750 if ((regs.isr & regs.imr))
751        cpuIntrPost();
752}
753
754void
755EtherDev::devIntrClear(uint32_t interrupts)
756{
757    DPRINTF(Ethernet, "interrupt cleared intr=%x isr=%x imr=%x\n",
758            interrupts, regs.isr, regs.imr);
759
760    if (interrupts & ISR_RESERVE)
761        panic("Cannot clear a reserved interrupt");
762
763    if (interrupts & ISR_TXRCMP)
764        regs.isr &= ~ISR_TXRCMP;
765
766    if (interrupts & ISR_RXRCMP)
767        regs.isr &= ~ISR_RXRCMP;
768
769//ISR_DPERR  not implemented
770//ISR_SSERR not implemented
771//ISR_RMABT not implemented
772//ISR_RXSOVR not implemented
773//ISR_HIBINT not implemented
774//ISR_PHY not implemented
775//ISR_PME not implemented
776
777    if (interrupts & ISR_SWI)
778        regs.isr &= ~ISR_SWI;
779
780//ISR_MIB not implemented
781//ISR_TXURN not implemented
782
783    if (interrupts & ISR_TXIDLE)
784        regs.isr &= ~ISR_TXIDLE;
785
786    if (interrupts & ISR_TXERR)
787        regs.isr &= ~ISR_TXERR;
788
789    if (interrupts & ISR_TXDESC)
790        regs.isr &= ~ISR_TXDESC;
791
792    if (interrupts & ISR_TXOK)
793        regs.isr &= ~ISR_TXOK;
794
795    if (interrupts & ISR_RXORN)
796        regs.isr &= ~ISR_RXORN;
797
798    if (interrupts & ISR_RXIDLE)
799        regs.isr &= ~ISR_RXIDLE;
800
801//ISR_RXEARLY not implemented
802
803    if (interrupts & ISR_RXERR)
804        regs.isr &= ~ISR_RXERR;
805
806    if (interrupts & ISR_RXOK)
807        regs.isr &= ~ISR_RXOK;
808
809    if ((regs.isr & regs.imr))
810        cpuIntrPost();
811
812    if (!(regs.isr & regs.imr))
813        cpuIntrClear();
814}
815
816void
817EtherDev::devIntrChangeMask()
818{
819    DPRINTF(Ethernet, "iterrupt mask changed\n");
820
821    if (regs.isr & regs.imr)
822        cpuIntrPost();
823    else
824        cpuIntrClear();
825}
826
827void
828EtherDev::cpuIntrPost()
829{
830    if (!cpuPendingIntr) {
831        if (regs.ier) {
832            cpuPendingIntr = true;
833            intctrl->post(TheISA::INTLEVEL_IRQ1, TheISA::INTINDEX_ETHERNET);
834        }
835    }
836}
837
838void
839EtherDev::cpuIntrClear()
840{
841    if (cpuPendingIntr) {
842        cpuPendingIntr = false;
843        intctrl->clear(TheISA::INTLEVEL_IRQ1, TheISA::INTINDEX_ETHERNET);
844    }
845}
846
847bool
848EtherDev::cpuIntrPending() const
849{ return cpuPendingIntr; }
850
851void
852EtherDev::txReset()
853{
854
855    DPRINTF(Ethernet, "transmit reset\n");
856
857    txPacketFlag = false;
858    CTDD = false;
859    txFifoCnt = 0;
860    txFifoAvail = 0;
861    txHalt = false;
862    txFifo.clear();
863    descAddrFifo.clear();
864    regs.command &= ~CR_TXE;
865    txState = txIdle;
866}
867
868void
869EtherDev::rxReset()
870{
871    DPRINTF(Ethernet, "receive reset\n");
872
873    rxPacketFlag = false;
874    CRDD = false;
875    fragLen = 0;
876    rxFifoCnt = 0;
877    rxHalt = false;
878    rxFifo.clear();
879    regs.command &= ~CR_RXE;
880    rxState = rxIdle;
881}
882
883/**
884 * This sets up a DMA transfer to read one data segment from the rxFifo into
885 * the buffer indicated by rxDescCache.bufptr. Assumes the value of rxFragPtr
886 * is already correctly set.
887 */
888void
889EtherDev::writeOneFrag()
890{
891    /* i think there is no need for an "in use" warning here like in old */
892    fragLen = rxFifo.front()->length; //length of whole packet
893    fragLen = (fragLen < rxDescCnt) ? fragLen : rxDescCnt;
894
895    writePhys.addr = rxFragPtr;
896    writePhys.length = fragLen;
897
898    // Set up DMA request area
899    writeRequest.init(&rxDoneCB, 0, false, &writePhys, 1, fragLen,
900                     rxDescBufPtr, fragLen, curTick);
901
902    dma->doTransfer(&readRequest);
903}
904
905void
906EtherDev::rxKick()
907{
908    DPRINTF(Ethernet, "receive state machine activated!\n");
909
910    if (CRDD) {
911        rxState = rxDescRefr;
912        readOneDesc(rx, LINK_LEN);
913    } else {
914        rxState = rxDescRead;
915        readOneDesc(rx);
916    }
917}
918
919EtherDev::RxDescDone::RxDescDone(EtherDev *e)
920    : ethernet(e)
921{
922}
923
924std::string
925EtherDev::RxDescDone::name() const
926{
927    return ethernet->name() + ".rxDescDoneCB";
928}
929
930void
931EtherDev::RxDescDone::process()
932{
933    DPRINTF(Ethernet, "receive descriptor done callback\n");
934    ethernet->rxDescDone();
935}
936
937void
938EtherDev::rxDescDone()
939{
940    if (rxState == rxDescRefr) {
941        if (rxDescCache.link == 0) {
942            rxState = rxIdle;
943            regs.command &= ~CR_RXE;
944            devIntrPost(ISR_RXIDLE);
945            return;
946        } else {
947            rxState = rxDescRead;
948            regs.rxdp = rxDescCache.link;
949            CRDD = false;
950            readOneDesc(rx);
951        }
952    } else if (rxState == rxDescRead) {
953        if (rxDescCache.cmdsts & CMDSTS_OWN) {
954            rxState = rxIdle;
955            regs.command &= ~CR_RXE;
956            devIntrPost(ISR_RXIDLE);
957        } else {
958            rxState = rxFifoBlock;
959            rxFragPtr = rxDescCache.bufptr;
960            rxDescCnt = rxDescCache.cmdsts & CMDSTS_LEN_MASK;
961
962            if (!rxFifo.empty()) {
963                rxState = rxFragWrite;
964                if (!rxPacketFlag) { // reading a new packet
965                    rxPacketBufPtr = rxFifo.front()->data;
966                    rxPacketBufPtr -= rxDescCnt;
967                    rxDescBufPtr = rxPacketBufPtr;
968                    rxCopied = 0;
969                } else {
970                    rxDescBufPtr = rxPacketBufPtr - rxDescCnt;
971                }
972                writeOneFrag();
973            }
974        }
975    } else if (rxState == rxDescWrite) {
976        devIntrPost(ISR_RXOK);
977
978        if (rxDescCache.cmdsts & CMDSTS_INTR)
979            devIntrPost(ISR_RXDESC);
980
981        if (rxDescCache.link == 0 || ((rxPktBytes != 0) && rxHalt)) {
982            rxState = rxIdle;
983            regs.command &= ~CR_RXE;
984            devIntrPost(ISR_RXIDLE);
985            rxHalt = false;
986        } else {
987            rxState = rxDescRead;
988            regs.rxdp = rxDescCache.link;
989            CRDD = false;
990            readOneDesc(rx);
991        }
992    }
993}
994
995EtherDev::RxDone::RxDone(EtherDev *e)
996    : ethernet(e)
997{
998}
999
1000std::string
1001EtherDev::RxDone::name() const
1002{
1003    return ethernet->name() + ".rxDoneCB";
1004}
1005
1006void
1007EtherDev::RxDone::process()
1008{
1009    DPRINTF(Ethernet, "receive done callback\n");
1010    ethernet->rxDone();
1011}
1012
1013void
1014EtherDev::rxDone()
1015{
1016    DPRINTF(Ethernet, "packet received to host memory\n");
1017
1018    if (!rxDescCache.cmdsts & CMDSTS_OWN)
1019        panic("This descriptor is already owned by the driver!\n");
1020
1021    rxState = rxFifoBlock;
1022    rxCopied += fragLen;
1023    rxFifoCnt -= fragLen;
1024
1025    if (rxDescCnt) { /* there is still data left in the descriptor */
1026        rxState = rxFragWrite;
1027        rxDescBufPtr += fragLen;
1028        writeOneFrag();
1029    } else {
1030        rxState = rxDescWrite;
1031        if (rxPktBytes == 0) {  /* packet is done */
1032            rxDescCache.cmdsts |= CMDSTS_OWN;
1033            rxDescCache.cmdsts &= ~CMDSTS_MORE;
1034            rxDescCache.cmdsts |= CMDSTS_OK;
1035            rxDescCache.cmdsts += rxCopied;   //i.e. set CMDSTS_SIZE
1036
1037            rxPacketFlag = false;
1038            if (rxFilterEnable) {
1039                rxDescCache.cmdsts &= ~CMDSTS_DEST_MASK;
1040                if (rxFifo.front()->IsUnicast())
1041                    rxDescCache.cmdsts |= CMDSTS_DEST_SELF;
1042                if (rxFifo.front()->IsMulticast())
1043                    rxDescCache.cmdsts |= CMDSTS_DEST_MULTI;
1044                if (rxFifo.front()->IsBroadcast())
1045                    rxDescCache.cmdsts |= CMDSTS_DEST_MASK;
1046            }
1047
1048            PacketPtr &pkt = rxFifo.front();
1049            eth_header *eth = (eth_header *) pkt->data;
1050            if (eth->type == 0x800 && extstsEnable) {
1051                rxDescCache.extsts |= EXTSTS_IPPKT;
1052                if (!ipChecksum(pkt, false))
1053                    rxDescCache.extsts |= EXTSTS_IPERR;
1054                ip_header *ip = rxFifo.front()->getIpHdr();
1055
1056                if (ip->protocol == 6) {
1057                    rxDescCache.extsts |= EXTSTS_TCPPKT;
1058                    if (!tcpChecksum(pkt, false))
1059                        rxDescCache.extsts |= EXTSTS_TCPERR;
1060                } else if (ip->protocol == 17) {
1061                    rxDescCache.extsts |= EXTSTS_UDPPKT;
1062                    if (!udpChecksum(pkt, false))
1063                        rxDescCache.extsts |= EXTSTS_UDPERR;
1064                }
1065            }
1066
1067            rxFifo.front() = NULL;
1068            rxFifo.pop_front();
1069        } else { /* just the descriptor is done */
1070            rxDescCache.cmdsts |= CMDSTS_OWN;
1071            rxDescCache.cmdsts |= CMDSTS_MORE;
1072        }
1073        writeDescPhys.addr = regs.rxdp + LINK_LEN + BUFPTR_LEN;
1074        writeDescPhys.length = CMDSTS_LEN;
1075
1076        writeDescRequest.init(&rxDescDoneCB, 0, true, &writeDescPhys, 1,
1077                              CMDSTS_LEN, (uint8_t *) &rxDescCache.cmdsts,
1078                              CMDSTS_LEN, curTick);
1079    }
1080}
1081
1082/**
1083 * This sets up a DMA transfer to read one descriptor into the network device.
1084 */
1085void
1086EtherDev::readOneDesc(dir_t dir, uint32_t len) {
1087    readDescPhys.addr = (dir == tx) ? regs.txdp : regs.rxdp;
1088    readDescPhys.length = len;
1089
1090    ns_desc *cache = (dir == tx) ? &txDescCache : &rxDescCache;
1091
1092    /* THIS ASSUMES THAT DESC_LEN < regs.txcfg's maxdma value,
1093       which is 512 bytes in the driver, so i'll just hard code it here */
1094    readDescRequest.init(&txDescDoneCB, 0, false, &readDescPhys, 1,
1095                         len, (uint8_t *) cache , len, curTick);
1096
1097    dma->doTransfer(&readDescRequest);
1098}
1099
1100/**
1101 * This sets up a DMA transfer to read one data segment of the descriptor in
1102 * txDescCache.  Assumes the value of txFragPtr is already correctly set
1103 */
1104void
1105EtherDev::readOneFrag()
1106{
1107    /* i think there is no need for an "in use" warning here like in old */
1108    fragLen = (txDescCnt < txFifoAvail) ? txDescCnt : txFifoAvail;
1109    readPhys.addr = txFragPtr;
1110    readPhys.length = fragLen;
1111
1112    // Set up DMA request area
1113    readRequest.init(&txDoneCB, 0, false, &readPhys, 1, fragLen,
1114                     txPacketBufPtr, fragLen, curTick);
1115
1116    dma->doTransfer(&readRequest);
1117}
1118
1119void
1120EtherDev::transmit()
1121{
1122    if (txFifo.empty()) {
1123        DPRINTF(Ethernet, "nothing to transmit\n");
1124        return;
1125    }
1126
1127   if (interface->sendPacket(txFifo.front())) {
1128        DPRINTF(Ethernet, "transmit packet\n");
1129        txBytes += txFifo.front()->length;
1130        txPackets++;
1131
1132        txFifoCnt -= txFifo.front()->length;
1133
1134        txFifo.front() = NULL;
1135        txFifo.pop_front();
1136
1137        txDescCache.cmdsts &= ~CMDSTS_OK;
1138    } else {
1139        txDescCache.cmdsts &= ~CMDSTS_ERR;
1140    }
1141
1142    txDescCache.cmdsts &= ~CMDSTS_OWN;
1143
1144    writeDescPhys.addr = descAddrFifo.front() + LINK_LEN + BUFPTR_LEN;
1145    writeDescPhys.length = CMDSTS_LEN;
1146
1147    descAddrFifo.front() = 0;
1148    descAddrFifo.pop_front();
1149
1150    writeDescRequest.init(&txDescDoneCB, 0, true, &writeDescPhys, 1,
1151                          writeDescPhys.length,
1152                          (uint8_t *) &(txDescCache.cmdsts),
1153                          writeDescPhys.length, curTick);
1154
1155    dma->doTransfer(&writeDescRequest);
1156
1157    transmit();
1158}
1159
1160void
1161EtherDev::txKick()
1162{
1163    DPRINTF(Ethernet, "transmit state machine activated\n");
1164#if 0
1165    if (DTRACE(Ethernet))
1166        txDump();
1167#endif
1168
1169    if (CTDD) {
1170        txState = txDescRefr;
1171        readOneDesc(tx, LINK_LEN);
1172    } else {
1173        txState = txDescRead;
1174        readOneDesc(tx);
1175    }
1176}
1177
1178EtherDev::TxDescDone::TxDescDone(EtherDev *e)
1179    : ethernet(e)
1180{
1181}
1182
1183std::string
1184EtherDev::TxDescDone::name() const
1185{
1186    return ethernet->name() + ".txDescDoneCB";
1187}
1188
1189void
1190EtherDev::TxDescDone::process()
1191{
1192    DPRINTF(Ethernet, "transmit descriptor done callback\n");
1193    ethernet->txDescDone();
1194
1195}
1196
1197void
1198EtherDev::txDescDone()
1199{
1200    if (txState == txFifoBlock) {
1201        if (txDescCache.cmdsts & CMDSTS_OK) {
1202            devIntrPost(ISR_TXOK);
1203        } else if (txDescCache.cmdsts & CMDSTS_ERR) {
1204            devIntrPost(ISR_TXERR);
1205        }
1206    } else if (txState == txDescRefr || txState == txDescWrite) {
1207
1208        if (txState == txDescWrite) {
1209            if (txDescCache.cmdsts & CMDSTS_INTR) {
1210                devIntrPost(ISR_TXDESC);
1211            }
1212        }
1213
1214        if (txDescCache.link == 0) {
1215            txState = txIdle;
1216            regs.command &= ~CR_TXE;
1217            devIntrPost(ISR_TXIDLE);
1218            return;
1219        } else {
1220            txState = txDescRead;
1221            regs.txdp = txDescCache.link;
1222            CTDD = false;
1223            readOneDesc(tx);
1224        }
1225    } else if (txState == txDescRead) {
1226        if (txDescCache.cmdsts & CMDSTS_OWN) {
1227            txState = txFifoBlock;
1228            txFragPtr = txDescCache.bufptr;
1229            txDescCnt = txDescCache.cmdsts & CMDSTS_LEN_MASK;
1230
1231            if (txFifoAvail >= ((regs.txcfg & TXCFG_FLTH_MASK) >> 8)) {
1232                txState = txFragRead;
1233                if (!txPacketFlag) {
1234                    txPacketFlag = true;
1235                    /* find the total length of this packet */
1236                    txPacketLen = txDescCnt;
1237                    bool more = txDescCache.cmdsts & CMDSTS_MORE;
1238                    uint8_t *addr = (uint8_t *) regs.txdp;
1239                    while (more) {
1240                        addr = physmem->dma_addr(((ns_desc *) addr)->link, sizeof(ns_desc));
1241                        /* !!!!!!mask needed? */
1242                        txPacketLen += ((ns_desc *)addr)->cmdsts & CMDSTS_LEN_MASK;
1243                        more = ((ns_desc *) addr)->cmdsts & CMDSTS_MORE;
1244                    }
1245                    PacketPtr &packet = txDoneCB.packet;
1246                    packet = new EtherPacket;
1247                    packet->length = txPacketLen;
1248                    packet->data = new uint8_t[txPacketLen];
1249                    txPacketBufPtr = packet->data;
1250                }
1251                readOneFrag();
1252            }
1253        } else {
1254            txState = txIdle;
1255            regs.command &= ~CR_TXE;
1256            devIntrPost(ISR_TXIDLE);
1257        }
1258    }
1259}
1260
1261EtherDev::TxDone::TxDone(EtherDev *e)
1262    : ethernet(e)
1263{
1264}
1265
1266std::string
1267EtherDev::TxDone::name() const
1268{
1269    return ethernet->name() + ".txDoneCB";
1270}
1271
1272
1273void
1274EtherDev::TxDone::process()
1275{
1276    DPRINTF(Ethernet, "transmit done callback\n");
1277    ethernet->txDone(packet);
1278}
1279
1280void
1281EtherDev::txDone(PacketPtr packet)
1282{
1283    DPRINTF(Ethernet, "transmit done\n");
1284
1285    if (!txDescCache.cmdsts & CMDSTS_OWN)
1286        panic("This descriptor is already owned by the driver!\n");
1287
1288    txState = txFifoBlock;
1289
1290    txPacketBufPtr += fragLen;  /* hope this ptr manipulation is right! */
1291    txDescCnt -= fragLen;
1292    txFifoCnt += fragLen;
1293
1294    if (txFifoCnt >= (regs.txcfg & TXCFG_DRTH_MASK)) {
1295        if (txFifo.empty()) {
1296            txFifoCnt -= (uint32_t) (txPacketBufPtr - packet->data);
1297        } else {
1298            transmit();
1299        }
1300    }
1301
1302    if (txDescCnt) { /* if there is still more data to go in this desc */
1303        if (txFifoAvail >= regs.txcfg & TXCFG_FLTH_MASK) {
1304            txState = txFragRead;
1305            readOneFrag();
1306        }
1307    } else { /* this descriptor is done */
1308        /* but there is more descriptors for this packet */
1309        if (txDescCache.cmdsts & CMDSTS_MORE) {
1310            txState = txDescWrite;
1311            txDescCache.cmdsts &= ~CMDSTS_OWN;
1312            writeDescPhys.addr = regs.txdp + LINK_LEN + BUFPTR_LEN;
1313            writeDescPhys.length = CMDSTS_LEN;
1314
1315            writeDescRequest.init(&txDescDoneCB, 0, true, &writeDescPhys, 1,
1316                                  writeDescPhys.length,
1317                                  (uint8_t*) &txDescCache.cmdsts,
1318                                  writeDescPhys.length, curTick);
1319        } else { /* this packet is totally done */
1320            /* deal with the the packet that just finished */
1321            if (regs.vtcr & VTCR_PPCHK && extstsEnable) {
1322                if (txDescCache.extsts & EXTSTS_UDPPKT) {
1323                    udpChecksum(packet, true);
1324                } else if (txDescCache.extsts & EXTSTS_TCPPKT) {
1325                    tcpChecksum(packet, true);
1326                } else if (txDescCache.extsts & EXTSTS_IPPKT) {
1327                    ipChecksum(packet, true);
1328                }
1329            }
1330
1331            txFifo.push_back(packet);
1332            transmit();
1333            txPacketFlag = false;
1334            descAddrFifo.push_back(regs.txdp);
1335
1336            /* if there is not another descriptor ready for reading, go idle */
1337            if (txDescCache.link == 0 || txHalt) {
1338                txState = txIdle;
1339                devIntrPost(ISR_TXIDLE);
1340                txHalt = false;
1341            } else { /* else go read next descriptor */
1342                txState = txDescRead;
1343                regs.txdp = txDescCache.link;
1344                CTDD = false;
1345                readOneDesc(tx);
1346            }
1347        }
1348    }
1349}
1350
1351void
1352EtherDev::transferDone()
1353{
1354    if (txFifo.empty())
1355        return;
1356
1357    DPRINTF(Ethernet, "schedule transmit\n");
1358
1359    if (txEvent.scheduled())
1360        txEvent.reschedule(curTick + 1);
1361    else
1362        txEvent.schedule(curTick + 1);
1363}
1364
1365void
1366EtherDev::txDump() const
1367{
1368#if 0
1369    int i = tx_ptr;
1370    for (int loop = 0; loop < tx_ring_len; loop++) {
1371        es_desc *desc = &tx_ring[i];
1372
1373        if (desc->addr)
1374            cprintf("desc[%d]: addr=%#x, len=%d, flags=%#x\n",
1375                    i, desc->addr, desc->length, desc->flags);
1376
1377        if (++i >= tx_ring_len)
1378            i = 0;
1379    }
1380#endif
1381}
1382
1383void
1384EtherDev::rxDump() const
1385{
1386#if 0
1387    int i = rx_ptr;
1388    for (int loop = 0; loop < rx_ring_len; loop++) {
1389        es_desc *desc = &rx_ring[i];
1390
1391        if (desc->addr)
1392            cprintf("desc[%d]: addr=%#x, len=%d, flags=%#x\n",
1393                    i, desc->addr, desc->length, desc->flags);
1394
1395        if (++i >= rx_ring_len)
1396            i = 0;
1397    }
1398#endif
1399}
1400
1401bool
1402EtherDev::rxFilter(PacketPtr packet)
1403{
1404    bool drop = true;
1405    string type;
1406
1407    if (packet->IsUnicast()) {
1408        type = "unicast";
1409
1410        // If we're accepting all unicast addresses
1411        if (acceptUnicast)
1412            drop = false;
1413
1414        // If we make a perfect match
1415        if ((acceptPerfect)
1416            && (memcmp(regs.perfectMatch, packet->data, sizeof(regs.perfectMatch)) == 0))
1417            drop = false;
1418
1419        eth_header *eth = (eth_header *) packet->data;
1420        if ((acceptArp) && (eth->type == 0x806))
1421            drop = false;
1422
1423    } else if (packet->IsBroadcast()) {
1424        type = "broadcast";
1425
1426        // if we're accepting broadcasts
1427        if (acceptBroadcast)
1428            drop = false;
1429
1430    } else if (packet->IsMulticast()) {
1431        type = "multicast";
1432
1433        // if we're accepting all multicasts
1434        if (acceptMulticast)
1435            drop = false;
1436
1437    } else {
1438        type = "unknown";
1439
1440        // oh well, punt on this one
1441    }
1442
1443    if (drop) {
1444        DPRINTF(Ethernet, "rxFilter drop\n");
1445        DDUMP(EthernetData, packet->data, packet->length);
1446    }
1447
1448    return drop;
1449}
1450
1451bool
1452EtherDev::recvPacket(PacketPtr packet)
1453{
1454    rxBytes += packet->length;
1455    rxPackets++;
1456
1457    if (rxState == rxIdle) {
1458        DPRINTF(Ethernet, "receive disabled...packet dropped\n");
1459        interface->recvDone();
1460        return true;
1461    }
1462
1463    if (rxFilterEnable && rxFilter(packet)) {
1464        DPRINTF(Ethernet, "packet filtered...dropped\n");
1465        interface->recvDone();
1466        return true;
1467    }
1468
1469    if (rxFifoCnt + packet->length >= MAX_RX_FIFO_SIZE) {
1470        DPRINTF(Ethernet,
1471                "packet will not fit in receive buffer...packet dropped\n");
1472        devIntrPost(ISR_RXORN);
1473        return false;
1474    }
1475
1476    rxFifo.push_back(packet);
1477    rxPktBytes = packet->length;
1478    rxFifoCnt += packet->length;
1479    interface->recvDone();
1480
1481    return true;
1482}
1483
1484bool
1485EtherDev::udpChecksum(PacketPtr packet, bool gen)
1486{
1487    udp_header *hdr = (udp_header *)  packet->getTransportHdr();
1488
1489    ip_header *ip = packet->getIpHdr();
1490
1491    pseudo_header *pseudo = new pseudo_header;
1492
1493    pseudo->src_ip_addr = ip->src_ip_addr;
1494    pseudo->dest_ip_addr = ip->dest_ip_addr;
1495    pseudo->protocol = ip->protocol;
1496    pseudo->len = hdr->len;
1497
1498    uint16_t cksum = checksumCalc((uint16_t *) pseudo, (uint16_t *) hdr,
1499                                  (uint32_t) hdr->len);
1500
1501    delete pseudo;
1502    if (gen)
1503        hdr->chksum = cksum;
1504    else
1505        if (cksum != 0)
1506            return false;
1507
1508    return true;
1509}
1510
1511bool
1512EtherDev::tcpChecksum(PacketPtr packet, bool gen)
1513{
1514    tcp_header *hdr = (tcp_header *) packet->getTransportHdr();
1515
1516    ip_header *ip = packet->getIpHdr();
1517
1518    pseudo_header *pseudo = new pseudo_header;
1519
1520    pseudo->src_ip_addr = ip->src_ip_addr;
1521    pseudo->dest_ip_addr = ip->dest_ip_addr;
1522    pseudo->protocol = ip->protocol;
1523    pseudo->len = ip->dgram_len - (ip->vers_len & 0xf);
1524
1525    uint16_t cksum = checksumCalc((uint16_t *) pseudo, (uint16_t *) hdr,
1526                                  (uint32_t) pseudo->len);
1527
1528    delete pseudo;
1529    if (gen)
1530        hdr->chksum = cksum;
1531    else
1532        if (cksum != 0)
1533            return false;
1534
1535    return true;
1536}
1537
1538bool
1539EtherDev::ipChecksum(PacketPtr packet, bool gen)
1540{
1541    ip_header *hdr = packet->getIpHdr();
1542
1543    uint16_t cksum = checksumCalc(NULL, (uint16_t *) hdr, (hdr->vers_len & 0xf));
1544
1545    if (gen)
1546        hdr->hdr_chksum = cksum;
1547    else
1548        if (cksum != 0)
1549            return false;
1550
1551    return true;
1552}
1553
1554uint16_t
1555EtherDev::checksumCalc(uint16_t *pseudo, uint16_t *buf, uint32_t len)
1556{
1557    uint32_t sum = 0;
1558
1559    uint16_t last_pad = 0;
1560    if (len & 1) {
1561        last_pad = buf[len/2] & 0xff;
1562        len--;
1563        sum += last_pad;
1564    }
1565
1566    if (pseudo) {
1567        sum = pseudo[0] + pseudo[1] + pseudo[2] +
1568            pseudo[3] + pseudo[4] + pseudo[5];
1569    }
1570
1571    for (int i=0; i < (len/2); ++i) {
1572        sum += buf[i];
1573    }
1574
1575    while (sum >> 16)
1576        sum = (sum >> 16) + (sum & 0xffff);
1577
1578    return ~sum;
1579}
1580
1581//=====================================================================
1582//
1583//
1584void
1585dp_regs::serialize(ostream &os)
1586{
1587    SERIALIZE_SCALAR(command);
1588    SERIALIZE_SCALAR(config);
1589    SERIALIZE_SCALAR(isr);
1590    SERIALIZE_SCALAR(imr);
1591}
1592
1593void
1594dp_regs::unserialize(Checkpoint *cp, const std::string &section)
1595{
1596    UNSERIALIZE_SCALAR(command);
1597    UNSERIALIZE_SCALAR(config);
1598    UNSERIALIZE_SCALAR(isr);
1599    UNSERIALIZE_SCALAR(imr);
1600#if 0
1601    UNSERIALIZE_SCALAR(tx_ring);
1602    UNSERIALIZE_SCALAR(rx_ring);
1603    UNSERIALIZE_SCALAR(tx_ring_len);
1604    UNSERIALIZE_SCALAR(rx_ring_len);
1605    UNSERIALIZE_SCALAR(rom_addr);
1606    UNSERIALIZE_SCALAR(rom_data);
1607    UNSERIALIZE_SCALAR(rxfilt_ctl);
1608    UNSERIALIZE_SCALAR(rxfilt_data);
1609
1610    UNSERIALIZE_ARRAY(perfect,EADDR_LEN);
1611    UNSERIALIZE_ARRAY(hash_table,ES_HASH_SIZE);
1612
1613    UNSERIALIZE_SCALAR(tx_ring_ptr);
1614    UNSERIALIZE_SCALAR(rx_ring_ptr);
1615#endif
1616}
1617
1618//---------------------------------------
1619
1620void
1621EtherPacket::serialize(ostream &os)
1622{
1623    SERIALIZE_SCALAR(length);
1624    SERIALIZE_ARRAY(data, length);
1625}
1626
1627void
1628EtherPacket::unserialize(Checkpoint *cp, const std::string &section)
1629{
1630    UNSERIALIZE_SCALAR(length);
1631    data = new uint8_t[length];
1632    UNSERIALIZE_ARRAY(data, length);
1633}
1634
1635//---------------------------------------
1636
1637void
1638EtherDev::serialize(ostream &os)
1639{
1640
1641#if 0
1642    regs.serialize(os);
1643
1644    // tx_ring & rx_ring are contained in the physmem...
1645    SERIALIZE_SCALAR(cpuPendingIntr);
1646    SERIALIZE_SCALAR(tx_ptr);
1647    SERIALIZE_SCALAR(rx_ptr);
1648
1649    SERIALIZE_SCALAR(rxDoneCB.ptr);
1650    SERIALIZE_SCALAR(rxDoneCB.ignore);
1651
1652    SERIALIZE_SCALAR(txDoneCB.ptr);
1653    SERIALIZE_SCALAR(txDoneCB.ignore);
1654
1655    for (int i=0; i<ES_MAX_DMA_SEGS; ++i) {
1656        paramOut(os, csprintf("readPhys%d.addr",i),   readPhys[i].addr);
1657        paramOut(os, csprintf("readPhys%d.length",i), readPhys[i].length);
1658        paramOut(os, csprintf("writePhys%d.addr",i),   writePhys[i].addr);
1659        paramOut(os, csprintf("writePhys%d.length",i), writePhys[i].length);
1660    }
1661
1662    SERIALIZE_SCALAR(txEnable);
1663    SERIALIZE_SCALAR(rxEnable);
1664    SERIALIZE_SCALAR(txDelay);
1665    SERIALIZE_SCALAR(rxDelay);
1666
1667    SERIALIZE_SCALAR(txbuf_len);
1668
1669    //Calculate the number here, actually dump them at end
1670    int numTxPkts=0;
1671    for (pktiter_t p=txbuf.begin(); p!=txbuf.end(); ++p) {
1672        numTxPkts++;
1673    }
1674    SERIALIZE_SCALAR(numTxPkts);
1675
1676    SERIALIZE_SCALAR(rxbuf_len);
1677    int numRxPkts=0;
1678    for (pktiter_t p=rxbuf.begin(); p!=rxbuf.end(); ++p) {
1679        numRxPkts++;
1680    }
1681    SERIALIZE_SCALAR(numRxPkts);
1682
1683    // output whether the tx and rx packets exist
1684    bool txPacketExists = false;
1685    if (txDoneCB.packet)
1686        txPacketExists = true;
1687    SERIALIZE_SCALAR(txPacketExists);
1688
1689    bool rxPacketExists = false;
1690    if (rxPacket)
1691        rxPacketExists = true;
1692    SERIALIZE_SCALAR(rxPacketExists);
1693
1694    // output the names (unique by pointer) of the read and write requests
1695    paramOut(os, csprintf("readReqName"), readRequest.name());
1696    paramOut(os, csprintf("writeReqName"), writeRequest.name());
1697
1698    // Serialize txPacket, because its data is needed for readRequest
1699    if (txPacketExists) {
1700        nameOut(os, csprintf("%s.txPacket", name()));
1701        txDoneCB.packet->serialize(os);
1702    }
1703
1704    // Serialize rxPacket, because its data is needed for writeRequest
1705    if (rxPacketExists) {
1706        nameOut(os, csprintf("%s.rxPacket", name()));
1707        rxPacket->serialize(os);
1708    }
1709
1710    // create a section for the readRequest
1711    nameOut(os, readRequest.name());
1712    paramOut(os, csprintf("parent"), name());
1713    paramOut(os, csprintf("id"), 0);
1714    readRequest.serialize(os);
1715
1716    // create a section for the writeRequest
1717    nameOut(os, writeRequest.name());
1718    paramOut(os, csprintf("parent"), name());
1719    paramOut(os, csprintf("id"), 1);
1720    writeRequest.serialize(os);
1721
1722    //Redo the buffers, this time outputing them to the file
1723    numTxPkts = 0;
1724    for (pktiter_t p=txbuf.begin(); p!=txbuf.end(); ++p) {
1725        nameOut(os, csprintf("%s.txbuf%d", name(),numTxPkts++));
1726        (*p)->serialize(os);
1727    }
1728
1729    numRxPkts = 0;
1730    for (pktiter_t p=rxbuf.begin(); p!=rxbuf.end(); ++p) {
1731        nameOut(os, csprintf("%s.rxbuf%d", name(),numRxPkts++));
1732        (*p)->serialize(os);
1733    }
1734#endif
1735}
1736
1737void
1738EtherDev::unserialize(Checkpoint *cp, const std::string &section)
1739{
1740#if 0
1741    regs.unserialize(cp, section);
1742
1743    UNSERIALIZE_SCALAR(cpuPendingIntr);
1744
1745    // initialize the tx_ring
1746    txReset();
1747
1748    // initialize the rx_ring
1749    rxReset();
1750
1751    UNSERIALIZE_SCALAR(tx_ptr);
1752    UNSERIALIZE_SCALAR(rx_ptr);
1753
1754    PacketPtr p;
1755    UNSERIALIZE_SCALAR(txbuf_len);
1756    int numTxPkts;
1757    UNSERIALIZE_SCALAR(numTxPkts);
1758    for (int i=0; i<numTxPkts; ++i) {
1759        p = new EtherPacket;
1760        p->unserialize(cp, csprintf("%s.txbuf%d", section, i));
1761        txbuf.push_back(p);
1762    }
1763
1764    UNSERIALIZE_SCALAR(rxbuf_len);
1765    int numRxPkts;
1766    UNSERIALIZE_SCALAR(numRxPkts);
1767    for (int i=0; i<numRxPkts; ++i) {
1768        p = new EtherPacket;
1769        p->unserialize(cp, csprintf("%s.rxbuf%d", section, i));
1770        rxbuf.push_back(p);
1771    }
1772
1773    UNSERIALIZE_SCALAR(rxDoneCB.ptr);
1774    UNSERIALIZE_SCALAR(rxDoneCB.ignore);
1775
1776    UNSERIALIZE_SCALAR(txDoneCB.ptr);
1777    UNSERIALIZE_SCALAR(txDoneCB.ignore);
1778
1779    for (int i=0; i<ES_MAX_DMA_SEGS; ++i) {
1780        paramIn(cp, section, csprintf("readPhys%d.addr",i),
1781                readPhys[i].addr);
1782        paramIn(cp, section, csprintf("readPhys%d.length",i),
1783                readPhys[i].length);
1784        paramIn(cp, section, csprintf("writePhys%d.addr",i),
1785                writePhys[i].addr);
1786        paramIn(cp, section, csprintf("writePhys%d.length",i),
1787                writePhys[i].length);
1788    }
1789
1790    UNSERIALIZE_SCALAR(txEnable);
1791    UNSERIALIZE_SCALAR(rxEnable);
1792    UNSERIALIZE_SCALAR(txDelay);
1793    UNSERIALIZE_SCALAR(rxDelay);
1794
1795    // Unserialize the current txPacket
1796    bool txPacketExists;
1797    UNSERIALIZE_SCALAR(txPacketExists);
1798
1799    txDoneCB.packet = NULL;
1800    if (txPacketExists) {
1801        txDoneCB.packet = new EtherPacket;
1802        txDoneCB.packet->unserialize(cp, csprintf("%s.txPacket", section));
1803    }
1804
1805    // Unserialize the current rxPacket
1806    bool rxPacketExists;
1807    UNSERIALIZE_SCALAR(rxPacketExists);
1808
1809    rxPacket = NULL;
1810    if (rxPacketExists) {
1811        rxPacket = new EtherPacket;
1812        rxPacket->unserialize(cp, csprintf("%s.rxPacket", section));
1813    }
1814
1815    std::string readReqName, writeReqName;
1816    UNSERIALIZE_SCALAR(readReqName);
1817    UNSERIALIZE_SCALAR(writeReqName);
1818
1819    // Unserialize and fixup the readRequest
1820    readRequest.unserialize(cp, readReqName);
1821    readRequest.phys = readPhys;
1822    readRequest.bufferCB = 0;
1823    readRequest.dmaDoneCB = &txDoneCB;
1824    readRequest.data = NULL;
1825
1826    if (txDoneCB.packet)
1827        readRequest.data = txDoneCB.packet->data;
1828
1829    // Unserialize and fixup the writeRequest
1830    writeRequest.unserialize(cp, writeReqName);
1831    writeRequest.phys = writePhys;
1832    writeRequest.bufferCB = 0;
1833    writeRequest.dmaDoneCB = &rxDoneCB;
1834    writeRequest.data = NULL;
1835
1836    if (rxPacket)
1837        writeRequest.data = rxPacket->data;
1838#endif
1839}
1840
1841
1842//=====================================================================
1843
1844
1845BEGIN_DECLARE_SIM_OBJECT_PARAMS(EtherDevInt)
1846
1847    SimObjectParam<EtherInt *> peer;
1848    SimObjectParam<EtherDev *> device;
1849
1850END_DECLARE_SIM_OBJECT_PARAMS(EtherDevInt)
1851
1852BEGIN_INIT_SIM_OBJECT_PARAMS(EtherDevInt)
1853
1854    INIT_PARAM_DFLT(peer, "peer interface", NULL),
1855    INIT_PARAM(device, "Ethernet device of this interface")
1856
1857END_INIT_SIM_OBJECT_PARAMS(EtherDevInt)
1858
1859CREATE_SIM_OBJECT(EtherDevInt)
1860{
1861    EtherDevInt *dev_int = new EtherDevInt(getInstanceName(), device);
1862
1863    EtherInt *p = (EtherInt *)peer;
1864    if (p) {
1865        dev_int->setPeer(p);
1866        p->setPeer(dev_int);
1867    }
1868
1869    return dev_int;
1870}
1871
1872REGISTER_SIM_OBJECT("EtherDevInt", EtherDevInt)
1873
1874
1875BEGIN_DECLARE_SIM_OBJECT_PARAMS(EtherDev)
1876
1877    Param<Tick> tx_delay;
1878    Param<Tick> rx_delay;
1879    SimObjectParam<DmaEngine *> engine;
1880    Param<bool> use_interface;
1881    SimObjectParam<IntrControl *> intr_ctrl;
1882    SimObjectParam<MemoryController *> mmu;
1883    SimObjectParam<PhysicalMemory *> physmem;
1884    Param<Addr> addr;
1885    Param<Addr> mask;
1886    Param<bool> rx_filter;
1887    Param<string> hardware_address;
1888    SimObjectParam<PCIConfigAll *> configspace;
1889    SimObjectParam<PciConfigData *> configdata;
1890    SimObjectParam<Tsunami *> tsunami;
1891    Param<uint32_t> pci_bus;
1892    Param<uint32_t> pci_dev;
1893    Param<uint32_t> pci_func;
1894
1895END_DECLARE_SIM_OBJECT_PARAMS(EtherDev)
1896
1897BEGIN_INIT_SIM_OBJECT_PARAMS(EtherDev)
1898
1899    INIT_PARAM_DFLT(tx_delay, "Transmit Delay", 1000),
1900    INIT_PARAM_DFLT(rx_delay, "Receive Delay", 1000),
1901    INIT_PARAM(engine, "DMA Engine"),
1902    INIT_PARAM_DFLT(use_interface, "Use DMA Interface", true),
1903    INIT_PARAM(intr_ctrl, "Interrupt Controller"),
1904    INIT_PARAM(mmu, "Memory Controller"),
1905    INIT_PARAM(physmem, "Physical Memory"),
1906    INIT_PARAM(addr, "Device Address"),
1907    INIT_PARAM(mask, "Address Mask"),
1908    INIT_PARAM_DFLT(rx_filter, "Enable Receive Filter", true),
1909    INIT_PARAM_DFLT(hardware_address, "Ethernet Hardware Address",
1910                    "00:99:00:00:00:01"),
1911    INIT_PARAM(configspace, "PCI Configspace"),
1912    INIT_PARAM(configdata, "PCI Config data"),
1913    INIT_PARAM(tsunami, "Tsunami"),
1914    INIT_PARAM(pci_bus, "PCI bus"),
1915    INIT_PARAM(pci_dev, "PCI device number"),
1916    INIT_PARAM(pci_func, "PCI function code")
1917
1918END_INIT_SIM_OBJECT_PARAMS(EtherDev)
1919
1920
1921CREATE_SIM_OBJECT(EtherDev)
1922{
1923    int eaddr[6];
1924    sscanf(((string)hardware_address).c_str(), "%x:%x:%x:%x:%x:%x",
1925           &eaddr[0], &eaddr[1], &eaddr[2], &eaddr[3], &eaddr[4], &eaddr[5]);
1926
1927    return new EtherDev(getInstanceName(), engine, use_interface,
1928                        intr_ctrl, mmu, physmem, configspace, configdata,
1929                        tsunami, pci_bus, pci_dev, pci_func, rx_filter, eaddr,
1930                        tx_delay, rx_delay, addr, mask);
1931}
1932
1933REGISTER_SIM_OBJECT("EtherDev", EtherDev)
1934