i8254xGBe.cc revision 5071
1/*
2 * Copyright (c) 2006 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 * Authors: Ali Saidi
29 */
30
31/* @file
32 * Device model for Intel's 8254x line of gigabit ethernet controllers.
33 * In particular an 82547 revision 2 (82547GI) MAC because it seems to have the
34 * fewest workarounds in the driver. It will probably work with most of the
35 * other MACs with slight modifications.
36 */
37
38
39/*
40 * @todo really there are multiple dma engines.. we should implement them.
41 */
42
43#include <algorithm>
44
45#include "base/inet.hh"
46#include "base/trace.hh"
47#include "dev/i8254xGBe.hh"
48#include "mem/packet.hh"
49#include "mem/packet_access.hh"
50#include "params/IGbE.hh"
51#include "sim/stats.hh"
52#include "sim/system.hh"
53
54using namespace iGbReg;
55using namespace Net;
56
57IGbE::IGbE(const Params *p)
58    : EtherDevice(p), etherInt(NULL),  drainEvent(NULL), useFlowControl(p->use_flow_control),
59      rxFifo(p->rx_fifo_size), txFifo(p->tx_fifo_size), rxTick(false),
60      txTick(false), txFifoTick(false), rxDmaPacket(false), rdtrEvent(this), radvEvent(this),
61      tadvEvent(this), tidvEvent(this), tickEvent(this), interEvent(this),
62      rxDescCache(this, name()+".RxDesc", p->rx_desc_cache_size),
63      txDescCache(this, name()+".TxDesc", p->tx_desc_cache_size), clock(p->clock)
64{
65    etherInt = new IGbEInt(name() + ".int", this);
66
67    // Initialized internal registers per Intel documentation
68    // All registers intialized to 0 by per register constructor
69    regs.ctrl.fd(1);
70    regs.ctrl.lrst(1);
71    regs.ctrl.speed(2);
72    regs.ctrl.frcspd(1);
73    regs.sts.speed(3); // Say we're 1000Mbps
74    regs.sts.fd(1); // full duplex
75    regs.sts.lu(1); // link up
76    regs.eecd.fwe(1);
77    regs.eecd.ee_type(1);
78    regs.imr = 0;
79    regs.iam = 0;
80    regs.rxdctl.gran(1);
81    regs.rxdctl.wthresh(1);
82    regs.fcrth(1);
83
84    regs.pba.rxa(0x30);
85    regs.pba.txa(0x10);
86
87    eeOpBits            = 0;
88    eeAddrBits          = 0;
89    eeDataBits          = 0;
90    eeOpcode            = 0;
91
92    // clear all 64 16 bit words of the eeprom
93    memset(&flash, 0, EEPROM_SIZE*2);
94
95    // Set the MAC address
96    memcpy(flash, p->hardware_address.bytes(), ETH_ADDR_LEN);
97    for (int x = 0; x < ETH_ADDR_LEN/2; x++)
98        flash[x] = htobe(flash[x]);
99
100    uint16_t csum = 0;
101    for (int x = 0; x < EEPROM_SIZE; x++)
102        csum += htobe(flash[x]);
103
104
105    // Magic happy checksum value
106    flash[EEPROM_SIZE-1] = htobe((uint16_t)(EEPROM_CSUM - csum));
107
108    rxFifo.clear();
109    txFifo.clear();
110}
111
112EtherInt*
113IGbE::getEthPort(const std::string &if_name, int idx)
114{
115
116    if (if_name == "interface") {
117        if (etherInt->getPeer())
118            panic("Port already connected to\n");
119        return etherInt;
120    }
121    return NULL;
122}
123
124Tick
125IGbE::writeConfig(PacketPtr pkt)
126{
127    int offset = pkt->getAddr() & PCI_CONFIG_SIZE;
128    if (offset < PCI_DEVICE_SPECIFIC)
129        PciDev::writeConfig(pkt);
130    else
131        panic("Device specific PCI config space not implemented.\n");
132
133    ///
134    /// Some work may need to be done here based for the pci COMMAND bits.
135    ///
136
137    return pioDelay;
138}
139
140Tick
141IGbE::read(PacketPtr pkt)
142{
143    int bar;
144    Addr daddr;
145
146    if (!getBAR(pkt->getAddr(), bar, daddr))
147        panic("Invalid PCI memory access to unmapped memory.\n");
148
149    // Only Memory register BAR is allowed
150    assert(bar == 0);
151
152    // Only 32bit accesses allowed
153    assert(pkt->getSize() == 4);
154
155    DPRINTF(Ethernet, "Read device register %#X\n", daddr);
156
157    pkt->allocate();
158
159    ///
160    /// Handle read of register here
161    ///
162
163
164    switch (daddr) {
165      case REG_CTRL:
166        pkt->set<uint32_t>(regs.ctrl());
167        break;
168      case REG_STATUS:
169        pkt->set<uint32_t>(regs.sts());
170        break;
171      case REG_EECD:
172        pkt->set<uint32_t>(regs.eecd());
173        break;
174      case REG_EERD:
175        pkt->set<uint32_t>(regs.eerd());
176        break;
177      case REG_CTRL_EXT:
178        pkt->set<uint32_t>(regs.ctrl_ext());
179        break;
180      case REG_MDIC:
181        pkt->set<uint32_t>(regs.mdic());
182        break;
183      case REG_ICR:
184        DPRINTF(Ethernet, "Reading ICR. ICR=%#x IMR=%#x IAM=%#x IAME=%d\n", regs.icr(),
185                regs.imr, regs.iam, regs.ctrl_ext.iame());
186        pkt->set<uint32_t>(regs.icr());
187        if (regs.icr.int_assert() || regs.imr == 0) {
188            regs.icr = regs.icr() & ~mask(30);
189            DPRINTF(Ethernet, "Cleared ICR. ICR=%#x\n", regs.icr());
190        }
191        if (regs.ctrl_ext.iame() && regs.icr.int_assert())
192            regs.imr &= ~regs.iam;
193        chkInterrupt();
194        break;
195      case REG_ITR:
196        pkt->set<uint32_t>(regs.itr());
197        break;
198      case REG_RCTL:
199        pkt->set<uint32_t>(regs.rctl());
200        break;
201      case REG_FCTTV:
202        pkt->set<uint32_t>(regs.fcttv());
203        break;
204      case REG_TCTL:
205        pkt->set<uint32_t>(regs.tctl());
206        break;
207      case REG_PBA:
208        pkt->set<uint32_t>(regs.pba());
209        break;
210      case REG_WUC:
211      case REG_LEDCTL:
212        pkt->set<uint32_t>(0); // We don't care, so just return 0
213        break;
214      case REG_FCRTL:
215        pkt->set<uint32_t>(regs.fcrtl());
216        break;
217      case REG_FCRTH:
218        pkt->set<uint32_t>(regs.fcrth());
219        break;
220      case REG_RDBAL:
221        pkt->set<uint32_t>(regs.rdba.rdbal());
222        break;
223      case REG_RDBAH:
224        pkt->set<uint32_t>(regs.rdba.rdbah());
225        break;
226      case REG_RDLEN:
227        pkt->set<uint32_t>(regs.rdlen());
228        break;
229      case REG_RDH:
230        pkt->set<uint32_t>(regs.rdh());
231        break;
232      case REG_RDT:
233        pkt->set<uint32_t>(regs.rdt());
234        break;
235      case REG_RDTR:
236        pkt->set<uint32_t>(regs.rdtr());
237        if (regs.rdtr.fpd()) {
238            rxDescCache.writeback(0);
239            DPRINTF(EthernetIntr, "Posting interrupt because of RDTR.FPD write\n");
240            postInterrupt(IT_RXT);
241            regs.rdtr.fpd(0);
242        }
243        break;
244      case REG_RADV:
245        pkt->set<uint32_t>(regs.radv());
246        break;
247      case REG_TDBAL:
248        pkt->set<uint32_t>(regs.tdba.tdbal());
249        break;
250      case REG_TDBAH:
251        pkt->set<uint32_t>(regs.tdba.tdbah());
252        break;
253      case REG_TDLEN:
254        pkt->set<uint32_t>(regs.tdlen());
255        break;
256      case REG_TDH:
257        pkt->set<uint32_t>(regs.tdh());
258        break;
259      case REG_TDT:
260        pkt->set<uint32_t>(regs.tdt());
261        break;
262      case REG_TIDV:
263        pkt->set<uint32_t>(regs.tidv());
264        break;
265      case REG_TXDCTL:
266        pkt->set<uint32_t>(regs.txdctl());
267        break;
268      case REG_TADV:
269        pkt->set<uint32_t>(regs.tadv());
270        break;
271      case REG_RXCSUM:
272        pkt->set<uint32_t>(regs.rxcsum());
273        break;
274      case REG_MANC:
275        pkt->set<uint32_t>(regs.manc());
276        break;
277      default:
278        if (!(daddr >= REG_VFTA && daddr < (REG_VFTA + VLAN_FILTER_TABLE_SIZE*4)) &&
279            !(daddr >= REG_RAL && daddr < (REG_RAL + RCV_ADDRESS_TABLE_SIZE*8)) &&
280            !(daddr >= REG_MTA && daddr < (REG_MTA + MULTICAST_TABLE_SIZE*4)) &&
281            !(daddr >= REG_CRCERRS && daddr < (REG_CRCERRS + STATS_REGS_SIZE)))
282            panic("Read request to unknown register number: %#x\n", daddr);
283        else
284            pkt->set<uint32_t>(0);
285    };
286
287    pkt->makeAtomicResponse();
288    return pioDelay;
289}
290
291Tick
292IGbE::write(PacketPtr pkt)
293{
294    int bar;
295    Addr daddr;
296
297
298    if (!getBAR(pkt->getAddr(), bar, daddr))
299        panic("Invalid PCI memory access to unmapped memory.\n");
300
301    // Only Memory register BAR is allowed
302    assert(bar == 0);
303
304    // Only 32bit accesses allowed
305    assert(pkt->getSize() == sizeof(uint32_t));
306
307    DPRINTF(Ethernet, "Wrote device register %#X value %#X\n", daddr, pkt->get<uint32_t>());
308
309    ///
310    /// Handle write of register here
311    ///
312    uint32_t val = pkt->get<uint32_t>();
313
314    Regs::RCTL oldrctl;
315    Regs::TCTL oldtctl;
316
317    switch (daddr) {
318      case REG_CTRL:
319        regs.ctrl = val;
320        if (regs.ctrl.tfce())
321            warn("TX Flow control enabled, should implement\n");
322        if (regs.ctrl.rfce())
323            warn("RX Flow control enabled, should implement\n");
324        break;
325      case REG_CTRL_EXT:
326        regs.ctrl_ext = val;
327        break;
328      case REG_STATUS:
329        regs.sts = val;
330        break;
331      case REG_EECD:
332        int oldClk;
333        oldClk = regs.eecd.sk();
334        regs.eecd = val;
335        // See if this is a eeprom access and emulate accordingly
336        if (!oldClk && regs.eecd.sk()) {
337            if (eeOpBits < 8) {
338                eeOpcode = eeOpcode << 1 | regs.eecd.din();
339                eeOpBits++;
340            } else if (eeAddrBits < 8 && eeOpcode == EEPROM_READ_OPCODE_SPI) {
341                eeAddr = eeAddr << 1 | regs.eecd.din();
342                eeAddrBits++;
343            } else if (eeDataBits < 16 && eeOpcode == EEPROM_READ_OPCODE_SPI) {
344                assert(eeAddr>>1 < EEPROM_SIZE);
345                DPRINTF(EthernetEEPROM, "EEPROM bit read: %d word: %#X\n",
346                        flash[eeAddr>>1] >> eeDataBits & 0x1, flash[eeAddr>>1]);
347                regs.eecd.dout((flash[eeAddr>>1] >> (15-eeDataBits)) & 0x1);
348                eeDataBits++;
349            } else if (eeDataBits < 8 && eeOpcode == EEPROM_RDSR_OPCODE_SPI) {
350                regs.eecd.dout(0);
351                eeDataBits++;
352            } else
353                panic("What's going on with eeprom interface? opcode:"
354                       " %#x:%d addr: %#x:%d, data: %d\n", (uint32_t)eeOpcode,
355                       (uint32_t)eeOpBits, (uint32_t)eeAddr,
356                       (uint32_t)eeAddrBits, (uint32_t)eeDataBits);
357
358            // Reset everything for the next command
359            if ((eeDataBits == 16 && eeOpcode == EEPROM_READ_OPCODE_SPI) ||
360               (eeDataBits == 8 && eeOpcode == EEPROM_RDSR_OPCODE_SPI)) {
361                eeOpBits = 0;
362                eeAddrBits = 0;
363                eeDataBits = 0;
364               eeOpcode = 0;
365                eeAddr = 0;
366            }
367
368           DPRINTF(EthernetEEPROM, "EEPROM: opcode: %#X:%d addr: %#X:%d\n",
369                    (uint32_t)eeOpcode, (uint32_t) eeOpBits,
370                    (uint32_t)eeAddr>>1, (uint32_t)eeAddrBits);
371           if (eeOpBits == 8 && !(eeOpcode == EEPROM_READ_OPCODE_SPI ||
372                                   eeOpcode == EEPROM_RDSR_OPCODE_SPI ))
373                panic("Unknown eeprom opcode: %#X:%d\n", (uint32_t)eeOpcode,
374                        (uint32_t)eeOpBits);
375
376
377        }
378        // If driver requests eeprom access, immediately give it to it
379        regs.eecd.ee_gnt(regs.eecd.ee_req());
380        break;
381      case REG_EERD:
382        regs.eerd = val;
383        break;
384      case REG_MDIC:
385        regs.mdic = val;
386        if (regs.mdic.i())
387            panic("No support for interrupt on mdic complete\n");
388        if (regs.mdic.phyadd() != 1)
389            panic("No support for reading anything but phy\n");
390        DPRINTF(Ethernet, "%s phy address %x\n", regs.mdic.op() == 1 ? "Writing"
391                : "Reading", regs.mdic.regadd());
392        switch (regs.mdic.regadd()) {
393            case PHY_PSTATUS:
394                regs.mdic.data(0x796D); // link up
395                break;
396            case PHY_PID:
397                regs.mdic.data(0x02A8);
398                break;
399            case PHY_EPID:
400                regs.mdic.data(0x0380);
401                break;
402            case PHY_GSTATUS:
403                regs.mdic.data(0x7C00);
404                break;
405            case PHY_EPSTATUS:
406                regs.mdic.data(0x3000);
407                break;
408            case PHY_AGC:
409                regs.mdic.data(0x180); // some random length
410                break;
411            default:
412                regs.mdic.data(0);
413        }
414        regs.mdic.r(1);
415        break;
416      case REG_ICR:
417        DPRINTF(Ethernet, "Writing ICR. ICR=%#x IMR=%#x IAM=%#x IAME=%d\n", regs.icr(),
418                regs.imr, regs.iam, regs.ctrl_ext.iame());
419        if (regs.ctrl_ext.iame())
420            regs.imr &= ~regs.iam;
421        regs.icr = ~bits(val,30,0) & regs.icr();
422        chkInterrupt();
423        break;
424      case REG_ITR:
425        regs.itr = val;
426        break;
427      case REG_ICS:
428        DPRINTF(EthernetIntr, "Posting interrupt because of ICS write\n");
429        postInterrupt((IntTypes)val);
430        break;
431       case REG_IMS:
432        regs.imr |= val;
433        chkInterrupt();
434        break;
435      case REG_IMC:
436        regs.imr &= ~val;
437        chkInterrupt();
438        break;
439      case REG_IAM:
440        regs.iam = val;
441        break;
442      case REG_RCTL:
443        oldrctl = regs.rctl;
444        regs.rctl = val;
445        if (regs.rctl.rst()) {
446            rxDescCache.reset();
447            DPRINTF(EthernetSM, "RXS: Got RESET!\n");
448            rxFifo.clear();
449            regs.rctl.rst(0);
450        }
451        if (regs.rctl.en())
452            rxTick = true;
453        restartClock();
454        break;
455      case REG_FCTTV:
456        regs.fcttv = val;
457        break;
458      case REG_TCTL:
459        regs.tctl = val;
460        oldtctl = regs.tctl;
461        regs.tctl = val;
462        if (regs.tctl.en())
463           txTick = true;
464        restartClock();
465        if (regs.tctl.en() && !oldtctl.en()) {
466            txDescCache.reset();
467        }
468         break;
469      case REG_PBA:
470        regs.pba.rxa(val);
471        regs.pba.txa(64 - regs.pba.rxa());
472        break;
473      case REG_WUC:
474      case REG_LEDCTL:
475      case REG_FCAL:
476      case REG_FCAH:
477      case REG_FCT:
478      case REG_VET:
479      case REG_AIFS:
480      case REG_TIPG:
481        ; // We don't care, so don't store anything
482        break;
483      case REG_FCRTL:
484        regs.fcrtl = val;
485        break;
486      case REG_FCRTH:
487        regs.fcrth = val;
488        break;
489      case REG_RDBAL:
490        regs.rdba.rdbal( val & ~mask(4));
491        rxDescCache.areaChanged();
492        break;
493      case REG_RDBAH:
494        regs.rdba.rdbah(val);
495        rxDescCache.areaChanged();
496        break;
497      case REG_RDLEN:
498        regs.rdlen = val & ~mask(7);
499        rxDescCache.areaChanged();
500        break;
501      case REG_RDH:
502        regs.rdh = val;
503        rxDescCache.areaChanged();
504        break;
505      case REG_RDT:
506        regs.rdt = val;
507        DPRINTF(EthernetSM, "RXS: RDT Updated.\n");
508        if (getState() == SimObject::Running) {
509            DPRINTF(EthernetSM, "RXS: RDT Fetching Descriptors!\n");
510            rxDescCache.fetchDescriptors();
511        } else {
512            DPRINTF(EthernetSM, "RXS: RDT NOT Fetching Desc b/c draining!\n");
513        }
514        break;
515      case REG_RDTR:
516        regs.rdtr = val;
517        break;
518      case REG_RADV:
519        regs.radv = val;
520        break;
521      case REG_TDBAL:
522        regs.tdba.tdbal( val & ~mask(4));
523        txDescCache.areaChanged();
524        break;
525      case REG_TDBAH:
526        regs.tdba.tdbah(val);
527        txDescCache.areaChanged();
528        break;
529      case REG_TDLEN:
530        regs.tdlen = val & ~mask(7);
531        txDescCache.areaChanged();
532        break;
533      case REG_TDH:
534        regs.tdh = val;
535        txDescCache.areaChanged();
536        break;
537      case REG_TDT:
538        regs.tdt = val;
539        DPRINTF(EthernetSM, "TXS: TX Tail pointer updated\n");
540        if (getState() == SimObject::Running) {
541            DPRINTF(EthernetSM, "TXS: TDT Fetching Descriptors!\n");
542            txDescCache.fetchDescriptors();
543        } else {
544            DPRINTF(EthernetSM, "TXS: TDT NOT Fetching Desc b/c draining!\n");
545        }
546        break;
547      case REG_TIDV:
548        regs.tidv = val;
549        break;
550      case REG_TXDCTL:
551        regs.txdctl = val;
552        break;
553      case REG_TADV:
554        regs.tadv = val;
555        break;
556      case REG_RXCSUM:
557        regs.rxcsum = val;
558        break;
559      case REG_MANC:
560        regs.manc = val;
561        break;
562      default:
563       if (!(daddr >= REG_VFTA && daddr < (REG_VFTA + VLAN_FILTER_TABLE_SIZE*4)) &&
564           !(daddr >= REG_RAL && daddr < (REG_RAL + RCV_ADDRESS_TABLE_SIZE*8)) &&
565           !(daddr >= REG_MTA && daddr < (REG_MTA + MULTICAST_TABLE_SIZE*4)))
566           panic("Write request to unknown register number: %#x\n", daddr);
567    };
568
569    pkt->makeAtomicResponse();
570    return pioDelay;
571}
572
573void
574IGbE::postInterrupt(IntTypes t, bool now)
575{
576    assert(t);
577
578    // Interrupt is already pending
579    if (t & regs.icr() && !now)
580        return;
581
582    regs.icr = regs.icr() | t;
583    if (regs.itr.interval() == 0 || now) {
584        if (interEvent.scheduled()) {
585            interEvent.deschedule();
586        }
587        cpuPostInt();
588    } else {
589       DPRINTF(EthernetIntr, "EINT: Scheduling timer interrupt for %d ticks\n",
590                Clock::Int::ns * 256 * regs.itr.interval());
591       if (!interEvent.scheduled()) {
592           interEvent.schedule(curTick + Clock::Int::ns * 256 * regs.itr.interval());
593       }
594    }
595}
596
597void
598IGbE::delayIntEvent()
599{
600    cpuPostInt();
601}
602
603
604void
605IGbE::cpuPostInt()
606{
607
608    if (!(regs.icr() & regs.imr)) {
609        DPRINTF(Ethernet, "Interrupt Masked. Not Posting\n");
610        return;
611    }
612
613    DPRINTF(Ethernet, "Posting Interrupt\n");
614
615
616    if (interEvent.scheduled()) {
617        interEvent.deschedule();
618    }
619
620    if (rdtrEvent.scheduled()) {
621        regs.icr.rxt0(1);
622        rdtrEvent.deschedule();
623    }
624    if (radvEvent.scheduled()) {
625        regs.icr.rxt0(1);
626        radvEvent.deschedule();
627    }
628    if (tadvEvent.scheduled()) {
629        regs.icr.txdw(1);
630        tadvEvent.deschedule();
631    }
632    if (tidvEvent.scheduled()) {
633        regs.icr.txdw(1);
634        tidvEvent.deschedule();
635    }
636
637    regs.icr.int_assert(1);
638    DPRINTF(EthernetIntr, "EINT: Posting interrupt to CPU now. Vector %#x\n",
639            regs.icr());
640
641    intrPost();
642
643}
644
645void
646IGbE::cpuClearInt()
647{
648    if (regs.icr.int_assert()) {
649        regs.icr.int_assert(0);
650        DPRINTF(EthernetIntr, "EINT: Clearing interrupt to CPU now. Vector %#x\n",
651                regs.icr());
652        intrClear();
653    }
654}
655
656void
657IGbE::chkInterrupt()
658{
659    DPRINTF(Ethernet, "Checking interrupts icr: %#x imr: %#x\n", regs.icr(),
660            regs.imr);
661    // Check if we need to clear the cpu interrupt
662    if (!(regs.icr() & regs.imr)) {
663        DPRINTF(Ethernet, "Mask cleaned all interrupts\n");
664        if (interEvent.scheduled())
665           interEvent.deschedule();
666        if (regs.icr.int_assert())
667            cpuClearInt();
668    }
669    DPRINTF(Ethernet, "ITR = %#X itr.interval = %#X\n", regs.itr(), regs.itr.interval());
670
671    if (regs.icr() & regs.imr) {
672        if (regs.itr.interval() == 0)  {
673            cpuPostInt();
674        } else {
675            DPRINTF(Ethernet, "Possibly scheduling interrupt because of imr write\n");
676            if (!interEvent.scheduled()) {
677               DPRINTF(Ethernet, "Scheduling for %d\n", curTick + Clock::Int::ns
678                       * 256 * regs.itr.interval());
679               interEvent.schedule(curTick + Clock::Int::ns * 256 * regs.itr.interval());
680            }
681        }
682    }
683
684
685}
686
687
688IGbE::RxDescCache::RxDescCache(IGbE *i, const std::string n, int s)
689    : DescCache<RxDesc>(i, n, s), pktDone(false), pktEvent(this)
690
691{
692}
693
694bool
695IGbE::RxDescCache::writePacket(EthPacketPtr packet)
696{
697    // We shouldn't have to deal with any of these yet
698    DPRINTF(EthernetDesc, "Packet Length: %d Desc Size: %d\n",
699            packet->length, igbe->regs.rctl.descSize());
700    assert(packet->length < igbe->regs.rctl.descSize());
701
702    assert(unusedCache.size());
703    //if (!unusedCache.size())
704    //    return false;
705
706    pktPtr = packet;
707    pktDone = false;
708    igbe->dmaWrite(igbe->platform->pciToDma(unusedCache.front()->buf),
709            packet->length, &pktEvent, packet->data);
710    return true;
711}
712
713void
714IGbE::RxDescCache::pktComplete()
715{
716    assert(unusedCache.size());
717    RxDesc *desc;
718    desc = unusedCache.front();
719
720
721    uint16_t crcfixup = igbe->regs.rctl.secrc() ? 0 : 4 ;
722    desc->len = htole((uint16_t)(pktPtr->length + crcfixup));
723    DPRINTF(EthernetDesc, "pktPtr->length: %d stripcrc offset: %d value written: %d %d\n",
724            pktPtr->length, crcfixup,
725            htole((uint16_t)(pktPtr->length + crcfixup)),
726            (uint16_t)(pktPtr->length + crcfixup));
727
728    // no support for anything but starting at 0
729    assert(igbe->regs.rxcsum.pcss() == 0);
730
731    DPRINTF(EthernetDesc, "Packet written to memory updating Descriptor\n");
732
733    uint8_t status = RXDS_DD | RXDS_EOP;
734    uint8_t err = 0;
735
736    IpPtr ip(pktPtr);
737
738    if (ip) {
739        DPRINTF(EthernetDesc, "Proccesing Ip packet with Id=%d\n", ip->id());
740
741        if (igbe->regs.rxcsum.ipofld()) {
742            DPRINTF(EthernetDesc, "Checking IP checksum\n");
743            status |= RXDS_IPCS;
744            desc->csum = htole(cksum(ip));
745            if (cksum(ip) != 0) {
746                err |= RXDE_IPE;
747                DPRINTF(EthernetDesc, "Checksum is bad!!\n");
748            }
749        }
750        TcpPtr tcp(ip);
751        if (tcp && igbe->regs.rxcsum.tuofld()) {
752            DPRINTF(EthernetDesc, "Checking TCP checksum\n");
753            status |= RXDS_TCPCS;
754            desc->csum = htole(cksum(tcp));
755            if (cksum(tcp) != 0) {
756                DPRINTF(EthernetDesc, "Checksum is bad!!\n");
757                err |= RXDE_TCPE;
758            }
759        }
760
761        UdpPtr udp(ip);
762        if (udp && igbe->regs.rxcsum.tuofld()) {
763            DPRINTF(EthernetDesc, "Checking UDP checksum\n");
764            status |= RXDS_UDPCS;
765            desc->csum = htole(cksum(udp));
766            if (cksum(udp) != 0) {
767                DPRINTF(EthernetDesc, "Checksum is bad!!\n");
768                err |= RXDE_TCPE;
769            }
770        }
771    } else { // if ip
772        DPRINTF(EthernetSM, "Proccesing Non-Ip packet\n");
773    }
774
775
776    desc->status = htole(status);
777    desc->errors = htole(err);
778
779    // No vlan support at this point... just set it to 0
780    desc->vlan = 0;
781
782    // Deal with the rx timer interrupts
783    if (igbe->regs.rdtr.delay()) {
784        DPRINTF(EthernetSM, "RXS: Scheduling DTR for %d\n",
785                igbe->regs.rdtr.delay() * igbe->intClock());
786        igbe->rdtrEvent.reschedule(curTick + igbe->regs.rdtr.delay() *
787                    igbe->intClock(),true);
788    }
789
790    if (igbe->regs.radv.idv() && igbe->regs.rdtr.delay()) {
791        DPRINTF(EthernetSM, "RXS: Scheduling ADV for %d\n",
792                igbe->regs.radv.idv() * igbe->intClock());
793        if (!igbe->radvEvent.scheduled()) {
794            igbe->radvEvent.schedule(curTick + igbe->regs.radv.idv() *
795                    igbe->intClock());
796        }
797    }
798
799    // if neither radv or rdtr, maybe itr is set...
800    if (!igbe->regs.rdtr.delay()) {
801        DPRINTF(EthernetSM, "RXS: Receive interrupt delay disabled, posting IT_RXT\n");
802        igbe->postInterrupt(IT_RXT);
803    }
804
805    // If the packet is small enough, interrupt appropriately
806    // I wonder if this is delayed or not?!
807    if (pktPtr->length <= igbe->regs.rsrpd.idv()) {
808        DPRINTF(EthernetSM, "RXS: Posting IT_SRPD beacuse small packet received\n");
809        igbe->postInterrupt(IT_SRPD);
810    }
811
812    DPRINTF(EthernetDesc, "Processing of this descriptor complete\n");
813    unusedCache.pop_front();
814    usedCache.push_back(desc);
815
816
817    pktPtr = NULL;
818    enableSm();
819    pktDone = true;
820    igbe->checkDrain();
821
822}
823
824void
825IGbE::RxDescCache::enableSm()
826{
827    if (!igbe->drainEvent) {
828        igbe->rxTick = true;
829        igbe->restartClock();
830    }
831}
832
833bool
834IGbE::RxDescCache::packetDone()
835{
836    if (pktDone) {
837        pktDone = false;
838        return true;
839    }
840    return false;
841}
842
843bool
844IGbE::RxDescCache::hasOutstandingEvents()
845{
846    return pktEvent.scheduled() || wbEvent.scheduled() ||
847        fetchEvent.scheduled();
848}
849
850void
851IGbE::RxDescCache::serialize(std::ostream &os)
852{
853    DescCache<RxDesc>::serialize(os);
854    SERIALIZE_SCALAR(pktDone);
855}
856
857void
858IGbE::RxDescCache::unserialize(Checkpoint *cp, const std::string &section)
859{
860    DescCache<RxDesc>::unserialize(cp, section);
861    UNSERIALIZE_SCALAR(pktDone);
862}
863
864
865///////////////////////////////////// IGbE::TxDesc /////////////////////////////////
866
867IGbE::TxDescCache::TxDescCache(IGbE *i, const std::string n, int s)
868    : DescCache<TxDesc>(i,n, s), pktDone(false), isTcp(false), pktWaiting(false),
869       pktEvent(this)
870
871{
872}
873
874int
875IGbE::TxDescCache::getPacketSize()
876{
877    assert(unusedCache.size());
878
879    TxDesc *desc;
880
881    DPRINTF(EthernetDesc, "Starting processing of descriptor\n");
882
883    while (unusedCache.size() && TxdOp::isContext(unusedCache.front())) {
884        DPRINTF(EthernetDesc, "Got context descriptor type... skipping\n");
885
886        // I think we can just ignore these for now?
887        desc = unusedCache.front();
888        DPRINTF(EthernetDesc, "Descriptor upper: %#x lower: %#X\n", desc->d1,
889                desc->d2);
890        // is this going to be a tcp or udp packet?
891        isTcp = TxdOp::tcp(desc) ? true : false;
892
893        // make sure it's ipv4
894        //assert(TxdOp::ip(desc));
895
896        TxdOp::setDd(desc);
897        unusedCache.pop_front();
898        usedCache.push_back(desc);
899    }
900
901    if (!unusedCache.size())
902        return -1;
903
904    DPRINTF(EthernetDesc, "Next TX packet is %d bytes\n",
905            TxdOp::getLen(unusedCache.front()));
906
907    return TxdOp::getLen(unusedCache.front());
908}
909
910void
911IGbE::TxDescCache::getPacketData(EthPacketPtr p)
912{
913    assert(unusedCache.size());
914
915    TxDesc *desc;
916    desc = unusedCache.front();
917
918    assert((TxdOp::isLegacy(desc) || TxdOp::isData(desc)) && TxdOp::getLen(desc));
919
920    pktPtr = p;
921
922    pktWaiting = true;
923
924    DPRINTF(EthernetDesc, "Starting DMA of packet\n");
925    igbe->dmaRead(igbe->platform->pciToDma(TxdOp::getBuf(desc)),
926            TxdOp::getLen(desc), &pktEvent, p->data + p->length);
927
928
929}
930
931void
932IGbE::TxDescCache::pktComplete()
933{
934
935    TxDesc *desc;
936    assert(unusedCache.size());
937    assert(pktPtr);
938
939    DPRINTF(EthernetDesc, "DMA of packet complete\n");
940
941    desc = unusedCache.front();
942    assert((TxdOp::isLegacy(desc) || TxdOp::isData(desc)) && TxdOp::getLen(desc));
943
944    DPRINTF(EthernetDesc, "TxDescriptor data d1: %#llx d2: %#llx\n", desc->d1, desc->d2);
945
946    if (!TxdOp::eop(desc)) {
947        // This only supports two descriptors per tx packet
948        assert(pktPtr->length == 0);
949        pktPtr->length = TxdOp::getLen(desc);
950        unusedCache.pop_front();
951        usedCache.push_back(desc);
952        pktDone = true;
953        pktWaiting = false;
954        pktPtr = NULL;
955
956        DPRINTF(EthernetDesc, "Partial Packet Descriptor Done\n");
957        enableSm();
958        igbe->checkDrain();
959        return;
960    }
961
962    // Set the length of the data in the EtherPacket
963    pktPtr->length += TxdOp::getLen(desc);
964
965    // no support for vlans
966    assert(!TxdOp::vle(desc));
967
968    // we alway report status
969    assert(TxdOp::rs(desc));
970
971    // we only support single packet descriptors at this point
972    assert(TxdOp::eop(desc));
973
974    // set that this packet is done
975    TxdOp::setDd(desc);
976
977    DPRINTF(EthernetDesc, "TxDescriptor data d1: %#llx d2: %#llx\n", desc->d1, desc->d2);
978
979    if (DTRACE(EthernetDesc)) {
980        IpPtr ip(pktPtr);
981        if (ip)
982            DPRINTF(EthernetDesc, "Proccesing Ip packet with Id=%d\n",
983                    ip->id());
984        else
985            DPRINTF(EthernetSM, "Proccesing Non-Ip packet\n");
986    }
987
988    // Checksums are only ofloaded for new descriptor types
989    if (TxdOp::isData(desc) && ( TxdOp::ixsm(desc) || TxdOp::txsm(desc)) ) {
990        DPRINTF(EthernetDesc, "Calculating checksums for packet\n");
991        IpPtr ip(pktPtr);
992
993        if (TxdOp::ixsm(desc)) {
994            ip->sum(0);
995            ip->sum(cksum(ip));
996            DPRINTF(EthernetDesc, "Calculated IP checksum\n");
997        }
998        if (TxdOp::txsm(desc)) {
999            TcpPtr tcp(ip);
1000            UdpPtr udp(ip);
1001            if (tcp) {
1002                 tcp->sum(0);
1003                 tcp->sum(cksum(tcp));
1004                 DPRINTF(EthernetDesc, "Calculated TCP checksum\n");
1005            } else if (udp) {
1006                 assert(udp);
1007                 udp->sum(0);
1008                 udp->sum(cksum(udp));
1009                 DPRINTF(EthernetDesc, "Calculated UDP checksum\n");
1010            } else {
1011                panic("Told to checksum, but don't know how\n");
1012            }
1013        }
1014    }
1015
1016    if (TxdOp::ide(desc)) {
1017        // Deal with the rx timer interrupts
1018        DPRINTF(EthernetDesc, "Descriptor had IDE set\n");
1019        if (igbe->regs.tidv.idv()) {
1020            DPRINTF(EthernetDesc, "setting tidv\n");
1021            igbe->tidvEvent.reschedule(curTick + igbe->regs.tidv.idv() *
1022                        igbe->intClock(), true);
1023        }
1024
1025        if (igbe->regs.tadv.idv() && igbe->regs.tidv.idv()) {
1026            DPRINTF(EthernetDesc, "setting tadv\n");
1027            if (!igbe->tadvEvent.scheduled()) {
1028                igbe->tadvEvent.schedule(curTick + igbe->regs.tadv.idv() *
1029                        igbe->intClock());
1030            }
1031        }
1032    }
1033
1034
1035
1036    unusedCache.pop_front();
1037    usedCache.push_back(desc);
1038    pktDone = true;
1039    pktWaiting = false;
1040    pktPtr = NULL;
1041
1042    DPRINTF(EthernetDesc, "Descriptor Done\n");
1043
1044    if (igbe->regs.txdctl.wthresh() == 0) {
1045        DPRINTF(EthernetDesc, "WTHRESH == 0, writing back descriptor\n");
1046        writeback(0);
1047    } else if (igbe->regs.txdctl.wthresh() >= usedCache.size()) {
1048        DPRINTF(EthernetDesc, "used > WTHRESH, writing back descriptor\n");
1049        writeback((igbe->cacheBlockSize()-1)>>4);
1050    }
1051    enableSm();
1052    igbe->checkDrain();
1053}
1054
1055void
1056IGbE::TxDescCache::serialize(std::ostream &os)
1057{
1058    DescCache<TxDesc>::serialize(os);
1059    SERIALIZE_SCALAR(pktDone);
1060    SERIALIZE_SCALAR(isTcp);
1061    SERIALIZE_SCALAR(pktWaiting);
1062}
1063
1064void
1065IGbE::TxDescCache::unserialize(Checkpoint *cp, const std::string &section)
1066{
1067    DescCache<TxDesc>::unserialize(cp, section);
1068    UNSERIALIZE_SCALAR(pktDone);
1069    UNSERIALIZE_SCALAR(isTcp);
1070    UNSERIALIZE_SCALAR(pktWaiting);
1071}
1072
1073bool
1074IGbE::TxDescCache::packetAvailable()
1075{
1076    if (pktDone) {
1077        pktDone = false;
1078        return true;
1079    }
1080    return false;
1081}
1082
1083void
1084IGbE::TxDescCache::enableSm()
1085{
1086    if (!igbe->drainEvent) {
1087        igbe->txTick = true;
1088        igbe->restartClock();
1089    }
1090}
1091
1092bool
1093IGbE::TxDescCache::hasOutstandingEvents()
1094{
1095    return pktEvent.scheduled() || wbEvent.scheduled() ||
1096        fetchEvent.scheduled();
1097}
1098
1099
1100///////////////////////////////////// IGbE /////////////////////////////////
1101
1102void
1103IGbE::restartClock()
1104{
1105    if (!tickEvent.scheduled() && (rxTick || txTick || txFifoTick) && getState() ==
1106            SimObject::Running)
1107        tickEvent.schedule((curTick/cycles(1)) * cycles(1) + cycles(1));
1108}
1109
1110unsigned int
1111IGbE::drain(Event *de)
1112{
1113    unsigned int count;
1114    count = pioPort->drain(de) + dmaPort->drain(de);
1115    if (rxDescCache.hasOutstandingEvents() ||
1116            txDescCache.hasOutstandingEvents()) {
1117        count++;
1118        drainEvent = de;
1119    }
1120
1121    txFifoTick = false;
1122    txTick = false;
1123    rxTick = false;
1124
1125    if (tickEvent.scheduled())
1126        tickEvent.deschedule();
1127
1128    if (count)
1129        changeState(Draining);
1130    else
1131        changeState(Drained);
1132
1133    return count;
1134}
1135
1136void
1137IGbE::resume()
1138{
1139    SimObject::resume();
1140
1141    txFifoTick = true;
1142    txTick = true;
1143    rxTick = true;
1144
1145    restartClock();
1146}
1147
1148void
1149IGbE::checkDrain()
1150{
1151    if (!drainEvent)
1152        return;
1153
1154    txFifoTick = false;
1155    txTick = false;
1156    rxTick = false;
1157    if (!rxDescCache.hasOutstandingEvents() &&
1158            !txDescCache.hasOutstandingEvents()) {
1159        drainEvent->process();
1160        drainEvent = NULL;
1161    }
1162}
1163
1164void
1165IGbE::txStateMachine()
1166{
1167    if (!regs.tctl.en()) {
1168        txTick = false;
1169        DPRINTF(EthernetSM, "TXS: TX disabled, stopping ticking\n");
1170        return;
1171    }
1172
1173    // If we have a packet available and it's length is not 0 (meaning it's not
1174    // a multidescriptor packet) put it in the fifo, otherwise an the next
1175    // iteration we'll get the rest of the data
1176    if (txPacket && txDescCache.packetAvailable() && txPacket->length) {
1177        bool success;
1178
1179        DPRINTF(EthernetSM, "TXS: packet placed in TX FIFO\n");
1180        success = txFifo.push(txPacket);
1181        txFifoTick = true && !drainEvent;
1182        assert(success);
1183        txPacket = NULL;
1184        txDescCache.writeback((cacheBlockSize()-1)>>4);
1185        return;
1186    }
1187
1188    // Only support descriptor granularity
1189    assert(regs.txdctl.gran());
1190    if (regs.txdctl.lwthresh() && txDescCache.descLeft() < (regs.txdctl.lwthresh() * 8)) {
1191        DPRINTF(EthernetSM, "TXS: LWTHRESH caused posting of TXDLOW\n");
1192        postInterrupt(IT_TXDLOW);
1193    }
1194
1195    if (!txPacket) {
1196        txPacket = new EthPacketData(16384);
1197    }
1198
1199    if (!txDescCache.packetWaiting()) {
1200        if (txDescCache.descLeft() == 0) {
1201            postInterrupt(IT_TXQE);
1202            txDescCache.writeback(0);
1203            txDescCache.fetchDescriptors();
1204            DPRINTF(EthernetSM, "TXS: No descriptors left in ring, forcing "
1205                    "writeback stopping ticking and posting TXQE\n");
1206            txTick = false;
1207            return;
1208        }
1209
1210
1211        if (!(txDescCache.descUnused())) {
1212            txDescCache.fetchDescriptors();
1213            DPRINTF(EthernetSM, "TXS: No descriptors available in cache, fetching and stopping ticking\n");
1214            txTick = false;
1215            return;
1216        }
1217
1218        int size;
1219        size = txDescCache.getPacketSize();
1220        if (size > 0 && txFifo.avail() > size) {
1221            DPRINTF(EthernetSM, "TXS: Reserving %d bytes in FIFO and begining "
1222                    "DMA of next packet\n", size);
1223            txFifo.reserve(size);
1224            txDescCache.getPacketData(txPacket);
1225        } else if (size <= 0) {
1226            DPRINTF(EthernetSM, "TXS: getPacketSize returned: %d\n", size);
1227            DPRINTF(EthernetSM, "TXS: No packets to get, writing back used descriptors\n");
1228            txDescCache.writeback(0);
1229        } else {
1230            DPRINTF(EthernetSM, "TXS: FIFO full, stopping ticking until space "
1231                    "available in FIFO\n");
1232            txTick = false;
1233        }
1234
1235
1236        return;
1237    }
1238    DPRINTF(EthernetSM, "TXS: Nothing to do, stopping ticking\n");
1239    txTick = false;
1240}
1241
1242bool
1243IGbE::ethRxPkt(EthPacketPtr pkt)
1244{
1245    DPRINTF(Ethernet, "RxFIFO: Receiving pcakte from wire\n");
1246
1247    if (!regs.rctl.en()) {
1248        DPRINTF(Ethernet, "RxFIFO: RX not enabled, dropping\n");
1249        return true;
1250    }
1251
1252    // restart the state machines if they are stopped
1253    rxTick = true && !drainEvent;
1254    if ((rxTick || txTick) && !tickEvent.scheduled()) {
1255        DPRINTF(EthernetSM, "RXS: received packet into fifo, starting ticking\n");
1256        restartClock();
1257    }
1258
1259    if (!rxFifo.push(pkt)) {
1260        DPRINTF(Ethernet, "RxFIFO: Packet won't fit in fifo... dropped\n");
1261        postInterrupt(IT_RXO, true);
1262        return false;
1263    }
1264    return true;
1265}
1266
1267
1268void
1269IGbE::rxStateMachine()
1270{
1271    if (!regs.rctl.en()) {
1272        rxTick = false;
1273        DPRINTF(EthernetSM, "RXS: RX disabled, stopping ticking\n");
1274        return;
1275    }
1276
1277    // If the packet is done check for interrupts/descriptors/etc
1278    if (rxDescCache.packetDone()) {
1279        rxDmaPacket = false;
1280        DPRINTF(EthernetSM, "RXS: Packet completed DMA to memory\n");
1281        int descLeft = rxDescCache.descLeft();
1282        switch (regs.rctl.rdmts()) {
1283            case 2: if (descLeft > .125 * regs.rdlen()) break;
1284            case 1: if (descLeft > .250 * regs.rdlen()) break;
1285            case 0: if (descLeft > .500 * regs.rdlen())  break;
1286                DPRINTF(Ethernet, "RXS: Interrupting (RXDMT) because of descriptors left\n");
1287                postInterrupt(IT_RXDMT);
1288                break;
1289        }
1290
1291        if (descLeft == 0) {
1292            rxDescCache.writeback(0);
1293            rxTick = false;
1294        }
1295
1296        // only support descriptor granulaties
1297        assert(regs.rxdctl.gran());
1298
1299        if (regs.rxdctl.wthresh() >= rxDescCache.descUsed()) {
1300            DPRINTF(EthernetSM, "RXS: Writing back because WTHRESH >= descUsed\n");
1301            if (regs.rxdctl.wthresh() < (cacheBlockSize()>>4))
1302                rxDescCache.writeback(regs.rxdctl.wthresh()-1);
1303            else
1304                rxDescCache.writeback((cacheBlockSize()-1)>>4);
1305        }
1306
1307        if ((rxDescCache.descUnused() < regs.rxdctl.pthresh()) &&
1308             ((rxDescCache.descLeft() - rxDescCache.descUnused()) > regs.rxdctl.hthresh())) {
1309            DPRINTF(EthernetSM, "RXS: Fetching descriptors because descUnused < PTHRESH\n");
1310            rxDescCache.fetchDescriptors();
1311        }
1312
1313        if (rxDescCache.descUnused() == 0) {
1314            rxDescCache.fetchDescriptors();
1315            DPRINTF(EthernetSM, "RXS: No descriptors available in cache, "
1316                    "fetching descriptors and stopping ticking\n");
1317            rxTick = false;
1318        }
1319        return;
1320    }
1321
1322    if (rxDmaPacket) {
1323        DPRINTF(EthernetSM, "RXS: stopping ticking until packet DMA completes\n");
1324        rxTick = false;
1325        return;
1326    }
1327
1328    if (!rxDescCache.descUnused()) {
1329        rxDescCache.fetchDescriptors();
1330        DPRINTF(EthernetSM, "RXS: No descriptors available in cache, stopping ticking\n");
1331        rxTick = false;
1332        DPRINTF(EthernetSM, "RXS: No descriptors available, fetching\n");
1333        return;
1334    }
1335
1336    if (rxFifo.empty()) {
1337        DPRINTF(EthernetSM, "RXS: RxFIFO empty, stopping ticking\n");
1338        rxTick = false;
1339        return;
1340    }
1341
1342    EthPacketPtr pkt;
1343    pkt = rxFifo.front();
1344
1345    DPRINTF(EthernetSM, "RXS: Writing packet into memory\n");
1346    if (rxDescCache.writePacket(pkt)) {
1347        DPRINTF(EthernetSM, "RXS: Removing packet from FIFO\n");
1348        rxFifo.pop();
1349        DPRINTF(EthernetSM, "RXS: stopping ticking until packet DMA completes\n");
1350        rxTick = false;
1351        rxDmaPacket = true;
1352        return;
1353    }
1354
1355}
1356
1357void
1358IGbE::txWire()
1359{
1360    if (txFifo.empty()) {
1361        txFifoTick = false;
1362        return;
1363    }
1364
1365    if (etherInt->askBusy()) {
1366        // We'll get woken up when the packet ethTxDone() gets called
1367        txFifoTick = false;
1368    } else {
1369        if (DTRACE(EthernetSM)) {
1370            IpPtr ip(txFifo.front());
1371            if (ip)
1372                DPRINTF(EthernetSM, "Transmitting Ip packet with Id=%d\n",
1373                        ip->id());
1374            else
1375                DPRINTF(EthernetSM, "Transmitting Non-Ip packet\n");
1376        }
1377
1378        bool r = etherInt->sendPacket(txFifo.front());
1379        assert(r);
1380        r += 1;
1381        DPRINTF(EthernetSM, "TxFIFO: Successful transmit, bytes available in fifo: %d\n",
1382                txFifo.avail());
1383        txFifo.pop();
1384    }
1385}
1386
1387void
1388IGbE::tick()
1389{
1390    DPRINTF(EthernetSM, "IGbE: -------------- Cycle --------------\n");
1391
1392    if (rxTick)
1393        rxStateMachine();
1394
1395    if (txTick)
1396        txStateMachine();
1397
1398    if (txFifoTick)
1399        txWire();
1400
1401
1402    if (rxTick || txTick || txFifoTick)
1403        tickEvent.schedule(curTick + cycles(1));
1404}
1405
1406void
1407IGbE::ethTxDone()
1408{
1409    // restart the tx state machines if they are stopped
1410    // fifo to send another packet
1411    // tx sm to put more data into the fifo
1412    txFifoTick = true && !drainEvent;
1413    if (txDescCache.descLeft() != 0 && !drainEvent)
1414        txTick = true;
1415
1416    restartClock();
1417    DPRINTF(EthernetSM, "TxFIFO: Transmission complete\n");
1418}
1419
1420void
1421IGbE::serialize(std::ostream &os)
1422{
1423    PciDev::serialize(os);
1424
1425    regs.serialize(os);
1426    SERIALIZE_SCALAR(eeOpBits);
1427    SERIALIZE_SCALAR(eeAddrBits);
1428    SERIALIZE_SCALAR(eeDataBits);
1429    SERIALIZE_SCALAR(eeOpcode);
1430    SERIALIZE_SCALAR(eeAddr);
1431    SERIALIZE_ARRAY(flash,iGbReg::EEPROM_SIZE);
1432
1433    rxFifo.serialize("rxfifo", os);
1434    txFifo.serialize("txfifo", os);
1435
1436    bool txPktExists = txPacket;
1437    SERIALIZE_SCALAR(txPktExists);
1438    if (txPktExists)
1439        txPacket->serialize("txpacket", os);
1440
1441    Tick rdtr_time = 0, radv_time = 0, tidv_time = 0, tadv_time = 0,
1442         inter_time = 0;
1443
1444    if (rdtrEvent.scheduled())
1445       rdtr_time = rdtrEvent.when();
1446    SERIALIZE_SCALAR(rdtr_time);
1447
1448    if (radvEvent.scheduled())
1449       radv_time = radvEvent.when();
1450    SERIALIZE_SCALAR(radv_time);
1451
1452    if (tidvEvent.scheduled())
1453       tidv_time = tidvEvent.when();
1454    SERIALIZE_SCALAR(tidv_time);
1455
1456    if (tadvEvent.scheduled())
1457       tadv_time = tadvEvent.when();
1458    SERIALIZE_SCALAR(tadv_time);
1459
1460    if (interEvent.scheduled())
1461       inter_time = interEvent.when();
1462    SERIALIZE_SCALAR(inter_time);
1463
1464    nameOut(os, csprintf("%s.TxDescCache", name()));
1465    txDescCache.serialize(os);
1466
1467    nameOut(os, csprintf("%s.RxDescCache", name()));
1468    rxDescCache.serialize(os);
1469}
1470
1471void
1472IGbE::unserialize(Checkpoint *cp, const std::string &section)
1473{
1474    PciDev::unserialize(cp, section);
1475
1476    regs.unserialize(cp, section);
1477    UNSERIALIZE_SCALAR(eeOpBits);
1478    UNSERIALIZE_SCALAR(eeAddrBits);
1479    UNSERIALIZE_SCALAR(eeDataBits);
1480    UNSERIALIZE_SCALAR(eeOpcode);
1481    UNSERIALIZE_SCALAR(eeAddr);
1482    UNSERIALIZE_ARRAY(flash,iGbReg::EEPROM_SIZE);
1483
1484    rxFifo.unserialize("rxfifo", cp, section);
1485    txFifo.unserialize("txfifo", cp, section);
1486
1487    bool txPktExists;
1488    UNSERIALIZE_SCALAR(txPktExists);
1489    if (txPktExists) {
1490        txPacket = new EthPacketData(16384);
1491        txPacket->unserialize("txpacket", cp, section);
1492    }
1493
1494    rxTick = true;
1495    txTick = true;
1496    txFifoTick = true;
1497
1498    Tick rdtr_time, radv_time, tidv_time, tadv_time, inter_time;
1499    UNSERIALIZE_SCALAR(rdtr_time);
1500    UNSERIALIZE_SCALAR(radv_time);
1501    UNSERIALIZE_SCALAR(tidv_time);
1502    UNSERIALIZE_SCALAR(tadv_time);
1503    UNSERIALIZE_SCALAR(inter_time);
1504
1505    if (rdtr_time)
1506        rdtrEvent.schedule(rdtr_time);
1507
1508    if (radv_time)
1509        radvEvent.schedule(radv_time);
1510
1511    if (tidv_time)
1512        tidvEvent.schedule(tidv_time);
1513
1514    if (tadv_time)
1515        tadvEvent.schedule(tadv_time);
1516
1517    if (inter_time)
1518        interEvent.schedule(inter_time);
1519
1520    txDescCache.unserialize(cp, csprintf("%s.TxDescCache", section));
1521
1522    rxDescCache.unserialize(cp, csprintf("%s.RxDescCache", section));
1523}
1524
1525IGbE *
1526IGbEParams::create()
1527{
1528    return new IGbE(this);
1529}
1530