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