i8254xGBe.cc revision 4981
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), 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" && !etherInt) {
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        rxTick = true;
508        restartClock();
509        break;
510      case REG_RDTR:
511        regs.rdtr = val;
512        break;
513      case REG_RADV:
514        regs.radv = val;
515        break;
516      case REG_TDBAL:
517        regs.tdba.tdbal( val & ~mask(4));
518        txDescCache.areaChanged();
519        break;
520      case REG_TDBAH:
521        regs.tdba.tdbah(val);
522        txDescCache.areaChanged();
523        break;
524      case REG_TDLEN:
525        regs.tdlen = val & ~mask(7);
526        txDescCache.areaChanged();
527        break;
528      case REG_TDH:
529        regs.tdh = val;
530        txDescCache.areaChanged();
531        break;
532      case REG_TDT:
533        regs.tdt = val;
534        txTick = true;
535        restartClock();
536        break;
537      case REG_TIDV:
538        regs.tidv = val;
539        break;
540      case REG_TXDCTL:
541        regs.txdctl = val;
542        break;
543      case REG_TADV:
544        regs.tadv = val;
545        break;
546      case REG_RXCSUM:
547        regs.rxcsum = val;
548        break;
549      case REG_MANC:
550        regs.manc = val;
551        break;
552      default:
553       if (!(daddr >= REG_VFTA && daddr < (REG_VFTA + VLAN_FILTER_TABLE_SIZE*4)) &&
554           !(daddr >= REG_RAL && daddr < (REG_RAL + RCV_ADDRESS_TABLE_SIZE*8)) &&
555           !(daddr >= REG_MTA && daddr < (REG_MTA + MULTICAST_TABLE_SIZE*4)))
556           panic("Write request to unknown register number: %#x\n", daddr);
557    };
558
559    pkt->makeAtomicResponse();
560    return pioDelay;
561}
562
563void
564IGbE::postInterrupt(IntTypes t, bool now)
565{
566    assert(t);
567
568    // Interrupt is already pending
569    if (t & regs.icr())
570        return;
571
572    if (regs.icr() & regs.imr)
573    {
574        regs.icr = regs.icr() | t;
575        if (!interEvent.scheduled())
576            interEvent.schedule(curTick + Clock::Int::ns * 256 *
577                    regs.itr.interval());
578    } else {
579        regs.icr = regs.icr() | t;
580        if (regs.itr.interval() == 0 || now) {
581            if (interEvent.scheduled())
582                interEvent.deschedule();
583            cpuPostInt();
584        } else {
585           DPRINTF(EthernetIntr, "EINT: Scheduling timer interrupt for %d ticks\n",
586                    Clock::Int::ns * 256 * regs.itr.interval());
587           if (!interEvent.scheduled())
588               interEvent.schedule(curTick + Clock::Int::ns * 256 * regs.itr.interval());
589        }
590    }
591}
592
593void
594IGbE::cpuPostInt()
595{
596    if (rdtrEvent.scheduled()) {
597        regs.icr.rxt0(1);
598        rdtrEvent.deschedule();
599    }
600    if (radvEvent.scheduled()) {
601        regs.icr.rxt0(1);
602        radvEvent.deschedule();
603    }
604    if (tadvEvent.scheduled()) {
605        regs.icr.txdw(1);
606        tadvEvent.deschedule();
607    }
608    if (tidvEvent.scheduled()) {
609        regs.icr.txdw(1);
610        tidvEvent.deschedule();
611    }
612
613    regs.icr.int_assert(1);
614    DPRINTF(EthernetIntr, "EINT: Posting interrupt to CPU now. Vector %#x\n",
615            regs.icr());
616    intrPost();
617}
618
619void
620IGbE::cpuClearInt()
621{
622    if (regs.icr.int_assert()) {
623        regs.icr.int_assert(0);
624        DPRINTF(EthernetIntr, "EINT: Clearing interrupt to CPU now. Vector %#x\n",
625                regs.icr());
626        intrClear();
627    }
628}
629
630void
631IGbE::chkInterrupt()
632{
633    // Check if we need to clear the cpu interrupt
634    if (!(regs.icr() & regs.imr)) {
635        if (interEvent.scheduled())
636           interEvent.deschedule();
637        if (regs.icr.int_assert())
638            cpuClearInt();
639    }
640
641    if (regs.icr() & regs.imr) {
642        if (regs.itr.interval() == 0)  {
643            cpuPostInt();
644        } else {
645            if (!interEvent.scheduled())
646               interEvent.schedule(curTick + Clock::Int::ns * 256 * regs.itr.interval());
647        }
648    }
649
650
651}
652
653
654IGbE::RxDescCache::RxDescCache(IGbE *i, const std::string n, int s)
655    : DescCache<RxDesc>(i, n, s), pktDone(false), pktEvent(this)
656
657{
658}
659
660bool
661IGbE::RxDescCache::writePacket(EthPacketPtr packet)
662{
663    // We shouldn't have to deal with any of these yet
664    DPRINTF(EthernetDesc, "Packet Length: %d Desc Size: %d\n",
665            packet->length, igbe->regs.rctl.descSize());
666    assert(packet->length < igbe->regs.rctl.descSize());
667
668    if (!unusedCache.size())
669        return false;
670
671    pktPtr = packet;
672    pktDone = false;
673    igbe->dmaWrite(igbe->platform->pciToDma(unusedCache.front()->buf),
674            packet->length, &pktEvent, packet->data);
675    return true;
676}
677
678void
679IGbE::RxDescCache::pktComplete()
680{
681    assert(unusedCache.size());
682    RxDesc *desc;
683    desc = unusedCache.front();
684
685    uint16_t crcfixup = igbe->regs.rctl.secrc() ? 0 : 4 ;
686    desc->len = htole((uint16_t)(pktPtr->length + crcfixup));
687    DPRINTF(EthernetDesc, "pktPtr->length: %d stripcrc offset: %d value written: %d %d\n",
688            pktPtr->length, crcfixup,
689            htole((uint16_t)(pktPtr->length + crcfixup)),
690            (uint16_t)(pktPtr->length + crcfixup));
691
692    // no support for anything but starting at 0
693    assert(igbe->regs.rxcsum.pcss() == 0);
694
695    DPRINTF(EthernetDesc, "Packet written to memory updating Descriptor\n");
696
697    uint8_t status = RXDS_DD | RXDS_EOP;
698    uint8_t err = 0;
699
700    IpPtr ip(pktPtr);
701
702    if (ip) {
703        DPRINTF(EthernetDesc, "Proccesing Ip packet with Id=%d\n", ip->id());
704
705        if (igbe->regs.rxcsum.ipofld()) {
706            DPRINTF(EthernetDesc, "Checking IP checksum\n");
707            status |= RXDS_IPCS;
708            desc->csum = htole(cksum(ip));
709            if (cksum(ip) != 0) {
710                err |= RXDE_IPE;
711                DPRINTF(EthernetDesc, "Checksum is bad!!\n");
712            }
713        }
714        TcpPtr tcp(ip);
715        if (tcp && igbe->regs.rxcsum.tuofld()) {
716            DPRINTF(EthernetDesc, "Checking TCP checksum\n");
717            status |= RXDS_TCPCS;
718            desc->csum = htole(cksum(tcp));
719            if (cksum(tcp) != 0) {
720                DPRINTF(EthernetDesc, "Checksum is bad!!\n");
721                err |= RXDE_TCPE;
722            }
723        }
724
725        UdpPtr udp(ip);
726        if (udp && igbe->regs.rxcsum.tuofld()) {
727            DPRINTF(EthernetDesc, "Checking UDP checksum\n");
728            status |= RXDS_UDPCS;
729            desc->csum = htole(cksum(udp));
730            if (cksum(udp) != 0) {
731                DPRINTF(EthernetDesc, "Checksum is bad!!\n");
732                err |= RXDE_TCPE;
733            }
734        }
735    } else { // if ip
736        DPRINTF(EthernetSM, "Proccesing Non-Ip packet\n");
737    }
738
739
740    desc->status = htole(status);
741    desc->errors = htole(err);
742
743    // No vlan support at this point... just set it to 0
744    desc->vlan = 0;
745
746    // Deal with the rx timer interrupts
747    if (igbe->regs.rdtr.delay()) {
748        DPRINTF(EthernetSM, "RXS: Scheduling DTR for %d\n",
749                igbe->regs.rdtr.delay() * igbe->intClock());
750        igbe->rdtrEvent.reschedule(curTick + igbe->regs.rdtr.delay() *
751                    igbe->intClock(),true);
752    }
753
754    if (igbe->regs.radv.idv() && igbe->regs.rdtr.delay()) {
755        DPRINTF(EthernetSM, "RXS: Scheduling ADV for %d\n",
756                igbe->regs.radv.idv() * igbe->intClock());
757        if (!igbe->radvEvent.scheduled())
758            igbe->radvEvent.schedule(curTick + igbe->regs.radv.idv() *
759                    igbe->intClock());
760    }
761
762    // if neither radv or rdtr, maybe itr is set...
763    if (!igbe->regs.rdtr.delay()) {
764        DPRINTF(EthernetSM, "RXS: Receive interrupt delay disabled, posting IT_RXT\n");
765        igbe->postInterrupt(IT_RXT);
766    }
767
768    // If the packet is small enough, interrupt appropriately
769    // I wonder if this is delayed or not?!
770    if (pktPtr->length <= igbe->regs.rsrpd.idv()) {
771        DPRINTF(EthernetSM, "RXS: Posting IT_SRPD beacuse small packet received\n");
772        igbe->postInterrupt(IT_SRPD);
773    }
774
775    DPRINTF(EthernetDesc, "Processing of this descriptor complete\n");
776    unusedCache.pop_front();
777    usedCache.push_back(desc);
778    pktPtr = NULL;
779    enableSm();
780    pktDone = true;
781    igbe->checkDrain();
782}
783
784void
785IGbE::RxDescCache::enableSm()
786{
787    igbe->rxTick = true;
788    igbe->restartClock();
789}
790
791bool
792IGbE::RxDescCache::packetDone()
793{
794    if (pktDone) {
795        pktDone = false;
796        return true;
797    }
798    return false;
799}
800
801bool
802IGbE::RxDescCache::hasOutstandingEvents()
803{
804    return pktEvent.scheduled() || wbEvent.scheduled() ||
805        fetchEvent.scheduled();
806}
807
808void
809IGbE::RxDescCache::serialize(std::ostream &os)
810{
811    DescCache<RxDesc>::serialize(os);
812    SERIALIZE_SCALAR(pktDone);
813}
814
815void
816IGbE::RxDescCache::unserialize(Checkpoint *cp, const std::string &section)
817{
818    DescCache<RxDesc>::unserialize(cp, section);
819    UNSERIALIZE_SCALAR(pktDone);
820}
821
822
823///////////////////////////////////// IGbE::TxDesc /////////////////////////////////
824
825IGbE::TxDescCache::TxDescCache(IGbE *i, const std::string n, int s)
826    : DescCache<TxDesc>(i,n, s), pktDone(false), isTcp(false), pktWaiting(false),
827       pktEvent(this)
828
829{
830}
831
832int
833IGbE::TxDescCache::getPacketSize()
834{
835    assert(unusedCache.size());
836
837    TxDesc *desc;
838
839    DPRINTF(EthernetDesc, "Starting processing of descriptor\n");
840
841    while (unusedCache.size() && TxdOp::isContext(unusedCache.front())) {
842        DPRINTF(EthernetDesc, "Got context descriptor type... skipping\n");
843
844        // I think we can just ignore these for now?
845        desc = unusedCache.front();
846        // is this going to be a tcp or udp packet?
847        isTcp = TxdOp::tcp(desc) ? true : false;
848
849        // make sure it's ipv4
850        assert(TxdOp::ip(desc));
851
852        TxdOp::setDd(desc);
853        unusedCache.pop_front();
854        usedCache.push_back(desc);
855    }
856
857    if (!unusedCache.size())
858        return -1;
859
860    DPRINTF(EthernetDesc, "Next TX packet is %d bytes\n",
861            TxdOp::getLen(unusedCache.front()));
862
863    return TxdOp::getLen(unusedCache.front());
864}
865
866void
867IGbE::TxDescCache::getPacketData(EthPacketPtr p)
868{
869    assert(unusedCache.size());
870
871    TxDesc *desc;
872    desc = unusedCache.front();
873
874    assert((TxdOp::isLegacy(desc) || TxdOp::isData(desc)) && TxdOp::getLen(desc));
875
876    pktPtr = p;
877
878    pktWaiting = true;
879
880    DPRINTF(EthernetDesc, "Starting DMA of packet\n");
881    igbe->dmaRead(igbe->platform->pciToDma(TxdOp::getBuf(desc)),
882            TxdOp::getLen(desc), &pktEvent, p->data + p->length);
883
884
885}
886
887void
888IGbE::TxDescCache::pktComplete()
889{
890
891    TxDesc *desc;
892    assert(unusedCache.size());
893    assert(pktPtr);
894
895    DPRINTF(EthernetDesc, "DMA of packet complete\n");
896
897
898    desc = unusedCache.front();
899    assert((TxdOp::isLegacy(desc) || TxdOp::isData(desc)) && TxdOp::getLen(desc));
900
901    DPRINTF(EthernetDesc, "TxDescriptor data d1: %#llx d2: %#llx\n", desc->d1, desc->d2);
902
903    if (!TxdOp::eop(desc)) {
904        // This only supports two descriptors per tx packet
905        assert(pktPtr->length == 0);
906        pktPtr->length = TxdOp::getLen(desc);
907        unusedCache.pop_front();
908        usedCache.push_back(desc);
909        pktDone = true;
910        pktWaiting = false;
911        pktPtr = NULL;
912
913        DPRINTF(EthernetDesc, "Partial Packet Descriptor Done\n");
914        enableSm();
915        return;
916    }
917
918    // Set the length of the data in the EtherPacket
919    pktPtr->length += TxdOp::getLen(desc);
920
921    // no support for vlans
922    assert(!TxdOp::vle(desc));
923
924    // we alway report status
925    assert(TxdOp::rs(desc));
926
927    // we only support single packet descriptors at this point
928    assert(TxdOp::eop(desc));
929
930    // set that this packet is done
931    TxdOp::setDd(desc);
932
933    DPRINTF(EthernetDesc, "TxDescriptor data d1: %#llx d2: %#llx\n", desc->d1, desc->d2);
934
935    if (DTRACE(EthernetDesc)) {
936        IpPtr ip(pktPtr);
937        if (ip)
938            DPRINTF(EthernetDesc, "Proccesing Ip packet with Id=%d\n",
939                    ip->id());
940        else
941            DPRINTF(EthernetSM, "Proccesing Non-Ip packet\n");
942    }
943
944    // Checksums are only ofloaded for new descriptor types
945    if (TxdOp::isData(desc) && ( TxdOp::ixsm(desc) || TxdOp::txsm(desc)) ) {
946        DPRINTF(EthernetDesc, "Calculating checksums for packet\n");
947        IpPtr ip(pktPtr);
948
949        if (TxdOp::ixsm(desc)) {
950            ip->sum(0);
951            ip->sum(cksum(ip));
952            DPRINTF(EthernetDesc, "Calculated IP checksum\n");
953        }
954       if (TxdOp::txsm(desc)) {
955           if (isTcp) {
956                TcpPtr tcp(ip);
957                assert(tcp);
958                tcp->sum(0);
959                tcp->sum(cksum(tcp));
960                DPRINTF(EthernetDesc, "Calculated TCP checksum\n");
961           } else {
962                UdpPtr udp(ip);
963                assert(udp);
964                udp->sum(0);
965                udp->sum(cksum(udp));
966                DPRINTF(EthernetDesc, "Calculated UDP checksum\n");
967           }
968        }
969    }
970
971    if (TxdOp::ide(desc)) {
972        // Deal with the rx timer interrupts
973        DPRINTF(EthernetDesc, "Descriptor had IDE set\n");
974        if (igbe->regs.tidv.idv()) {
975            DPRINTF(EthernetDesc, "setting tidv\n");
976            igbe->tidvEvent.reschedule(curTick + igbe->regs.tidv.idv() *
977                        igbe->intClock(), true);
978        }
979
980        if (igbe->regs.tadv.idv() && igbe->regs.tidv.idv()) {
981            DPRINTF(EthernetDesc, "setting tadv\n");
982            if (!igbe->tadvEvent.scheduled())
983                igbe->tadvEvent.schedule(curTick + igbe->regs.tadv.idv() *
984                        igbe->intClock());
985        }
986    }
987
988
989
990    unusedCache.pop_front();
991    usedCache.push_back(desc);
992    pktDone = true;
993    pktWaiting = false;
994    pktPtr = NULL;
995
996    DPRINTF(EthernetDesc, "Descriptor Done\n");
997
998    if (igbe->regs.txdctl.wthresh() == 0) {
999        DPRINTF(EthernetDesc, "WTHRESH == 0, writing back descriptor\n");
1000        writeback(0);
1001    } else if (igbe->regs.txdctl.wthresh() >= usedCache.size()) {
1002        DPRINTF(EthernetDesc, "used > WTHRESH, writing back descriptor\n");
1003        writeback((igbe->cacheBlockSize()-1)>>4);
1004    }
1005    enableSm();
1006    igbe->checkDrain();
1007}
1008
1009void
1010IGbE::TxDescCache::serialize(std::ostream &os)
1011{
1012    DescCache<TxDesc>::serialize(os);
1013    SERIALIZE_SCALAR(pktDone);
1014    SERIALIZE_SCALAR(isTcp);
1015    SERIALIZE_SCALAR(pktWaiting);
1016}
1017
1018void
1019IGbE::TxDescCache::unserialize(Checkpoint *cp, const std::string &section)
1020{
1021    DescCache<TxDesc>::unserialize(cp, section);
1022    UNSERIALIZE_SCALAR(pktDone);
1023    UNSERIALIZE_SCALAR(isTcp);
1024    UNSERIALIZE_SCALAR(pktWaiting);
1025}
1026
1027bool
1028IGbE::TxDescCache::packetAvailable()
1029{
1030    if (pktDone) {
1031        pktDone = false;
1032        return true;
1033    }
1034    return false;
1035}
1036
1037void
1038IGbE::TxDescCache::enableSm()
1039{
1040    igbe->txTick = true;
1041    igbe->restartClock();
1042}
1043
1044bool
1045IGbE::TxDescCache::hasOutstandingEvents()
1046{
1047    return pktEvent.scheduled() || wbEvent.scheduled() ||
1048        fetchEvent.scheduled();
1049}
1050
1051
1052///////////////////////////////////// IGbE /////////////////////////////////
1053
1054void
1055IGbE::restartClock()
1056{
1057    if (!tickEvent.scheduled() && (rxTick || txTick || txFifoTick) && getState() ==
1058            SimObject::Running)
1059        tickEvent.schedule((curTick/cycles(1)) * cycles(1) + cycles(1));
1060}
1061
1062unsigned int
1063IGbE::drain(Event *de)
1064{
1065    unsigned int count;
1066    count = pioPort->drain(de) + dmaPort->drain(de);
1067    if (rxDescCache.hasOutstandingEvents() ||
1068            txDescCache.hasOutstandingEvents()) {
1069        count++;
1070        drainEvent = de;
1071    }
1072
1073    txFifoTick = false;
1074    txTick = false;
1075    rxTick = false;
1076
1077    if (tickEvent.scheduled())
1078        tickEvent.deschedule();
1079
1080    if (count)
1081        changeState(Draining);
1082    else
1083        changeState(Drained);
1084
1085    return count;
1086}
1087
1088void
1089IGbE::resume()
1090{
1091    SimObject::resume();
1092
1093    txFifoTick = true;
1094    txTick = true;
1095    rxTick = true;
1096
1097    restartClock();
1098}
1099
1100void
1101IGbE::checkDrain()
1102{
1103    if (!drainEvent)
1104        return;
1105
1106    if (rxDescCache.hasOutstandingEvents() ||
1107            txDescCache.hasOutstandingEvents()) {
1108        drainEvent->process();
1109        drainEvent = NULL;
1110    }
1111}
1112
1113void
1114IGbE::txStateMachine()
1115{
1116    if (!regs.tctl.en()) {
1117        txTick = false;
1118        DPRINTF(EthernetSM, "TXS: TX disabled, stopping ticking\n");
1119        return;
1120    }
1121
1122    // If we have a packet available and it's length is not 0 (meaning it's not
1123    // a multidescriptor packet) put it in the fifo, otherwise an the next
1124    // iteration we'll get the rest of the data
1125    if (txPacket && txDescCache.packetAvailable() && txPacket->length) {
1126        bool success;
1127        DPRINTF(EthernetSM, "TXS: packet placed in TX FIFO\n");
1128        success = txFifo.push(txPacket);
1129        txFifoTick = true;
1130        assert(success);
1131        txPacket = NULL;
1132        txDescCache.writeback((cacheBlockSize()-1)>>4);
1133        return;
1134    }
1135
1136    // Only support descriptor granularity
1137    assert(regs.txdctl.gran());
1138    if (regs.txdctl.lwthresh() && txDescCache.descLeft() < (regs.txdctl.lwthresh() * 8)) {
1139        DPRINTF(EthernetSM, "TXS: LWTHRESH caused posting of TXDLOW\n");
1140        postInterrupt(IT_TXDLOW);
1141    }
1142
1143    if (!txPacket) {
1144        txPacket = new EthPacketData(16384);
1145    }
1146
1147    if (!txDescCache.packetWaiting()) {
1148        if (txDescCache.descLeft() == 0) {
1149            DPRINTF(EthernetSM, "TXS: No descriptors left in ring, forcing "
1150                    "writeback stopping ticking and posting TXQE\n");
1151            txDescCache.writeback(0);
1152            txTick = false;
1153            postInterrupt(IT_TXQE, true);
1154            return;
1155        }
1156
1157
1158        if (!(txDescCache.descUnused())) {
1159            DPRINTF(EthernetSM, "TXS: No descriptors available in cache, fetching and stopping ticking\n");
1160            txTick = false;
1161            txDescCache.fetchDescriptors();
1162            return;
1163        }
1164
1165        int size;
1166        size = txDescCache.getPacketSize();
1167        if (size > 0 && txFifo.avail() > size) {
1168            DPRINTF(EthernetSM, "TXS: Reserving %d bytes in FIFO and begining "
1169                    "DMA of next packet\n", size);
1170            txFifo.reserve(size);
1171            txDescCache.getPacketData(txPacket);
1172        } else if (size <= 0) {
1173            DPRINTF(EthernetSM, "TXS: No packets to get, writing back used descriptors\n");
1174            txDescCache.writeback(0);
1175        } else {
1176            DPRINTF(EthernetSM, "TXS: FIFO full, stopping ticking until space "
1177                    "available in FIFO\n");
1178            txDescCache.writeback((cacheBlockSize()-1)>>4);
1179            txTick = false;
1180        }
1181
1182
1183        return;
1184    }
1185    DPRINTF(EthernetSM, "TXS: Nothing to do, stopping ticking\n");
1186    txTick = false;
1187}
1188
1189bool
1190IGbE::ethRxPkt(EthPacketPtr pkt)
1191{
1192    DPRINTF(Ethernet, "RxFIFO: Receiving pcakte from wire\n");
1193    if (!regs.rctl.en()) {
1194        DPRINTF(Ethernet, "RxFIFO: RX not enabled, dropping\n");
1195        return true;
1196    }
1197
1198    // restart the state machines if they are stopped
1199    rxTick = true;
1200    if ((rxTick || txTick) && !tickEvent.scheduled()) {
1201        DPRINTF(EthernetSM, "RXS: received packet into fifo, starting ticking\n");
1202        restartClock();
1203    }
1204
1205    if (!rxFifo.push(pkt)) {
1206        DPRINTF(Ethernet, "RxFIFO: Packet won't fit in fifo... dropped\n");
1207        postInterrupt(IT_RXO, true);
1208        return false;
1209    }
1210    return true;
1211}
1212
1213
1214void
1215IGbE::rxStateMachine()
1216{
1217    if (!regs.rctl.en()) {
1218        rxTick = false;
1219        DPRINTF(EthernetSM, "RXS: RX disabled, stopping ticking\n");
1220        return;
1221    }
1222
1223    // If the packet is done check for interrupts/descriptors/etc
1224    if (rxDescCache.packetDone()) {
1225        rxDmaPacket = false;
1226        DPRINTF(EthernetSM, "RXS: Packet completed DMA to memory\n");
1227        int descLeft = rxDescCache.descLeft();
1228        switch (regs.rctl.rdmts()) {
1229            case 2: if (descLeft > .125 * regs.rdlen()) break;
1230            case 1: if (descLeft > .250 * regs.rdlen()) break;
1231            case 0: if (descLeft > .500 * regs.rdlen())  break;
1232                DPRINTF(Ethernet, "RXS: Interrupting (RXDMT) because of descriptors left\n");
1233                postInterrupt(IT_RXDMT);
1234                break;
1235        }
1236
1237        if (descLeft == 0) {
1238            DPRINTF(EthernetSM, "RXS: No descriptors left in ring, forcing"
1239                    " writeback and stopping ticking\n");
1240            rxDescCache.writeback(0);
1241            rxTick = false;
1242        }
1243
1244        // only support descriptor granulaties
1245        assert(regs.rxdctl.gran());
1246
1247        if (regs.rxdctl.wthresh() >= rxDescCache.descUsed()) {
1248            DPRINTF(EthernetSM, "RXS: Writing back because WTHRESH >= descUsed\n");
1249            if (regs.rxdctl.wthresh() < (cacheBlockSize()>>4))
1250                rxDescCache.writeback(regs.rxdctl.wthresh()-1);
1251            else
1252                rxDescCache.writeback((cacheBlockSize()-1)>>4);
1253        }
1254
1255        if ((rxDescCache.descUnused() < regs.rxdctl.pthresh()) &&
1256             ((rxDescCache.descLeft() - rxDescCache.descUnused()) > regs.rxdctl.hthresh())) {
1257            DPRINTF(EthernetSM, "RXS: Fetching descriptors because descUnused < PTHRESH\n");
1258            rxDescCache.fetchDescriptors();
1259        }
1260
1261        if (rxDescCache.descUnused() == 0) {
1262            DPRINTF(EthernetSM, "RXS: No descriptors available in cache, "
1263                    "fetching descriptors and stopping ticking\n");
1264            rxTick = false;
1265            rxDescCache.fetchDescriptors();
1266        }
1267        return;
1268    }
1269
1270    if (rxDmaPacket) {
1271        DPRINTF(EthernetSM, "RXS: stopping ticking until packet DMA completes\n");
1272        rxTick = false;
1273        return;
1274    }
1275
1276    if (!rxDescCache.descUnused()) {
1277        DPRINTF(EthernetSM, "RXS: No descriptors available in cache, stopping ticking\n");
1278        rxTick = false;
1279        DPRINTF(EthernetSM, "RXS: No descriptors available, fetching\n");
1280        rxDescCache.fetchDescriptors();
1281        return;
1282    }
1283
1284    if (rxFifo.empty()) {
1285        DPRINTF(EthernetSM, "RXS: RxFIFO empty, stopping ticking\n");
1286        rxTick = false;
1287        return;
1288    }
1289
1290    EthPacketPtr pkt;
1291    pkt = rxFifo.front();
1292
1293    DPRINTF(EthernetSM, "RXS: Writing packet into memory\n");
1294    if (!rxDescCache.writePacket(pkt)) {
1295        return;
1296    }
1297
1298    DPRINTF(EthernetSM, "RXS: Removing packet from FIFO\n");
1299    rxFifo.pop();
1300    DPRINTF(EthernetSM, "RXS: stopping ticking until packet DMA completes\n");
1301    rxTick = false;
1302    rxDmaPacket = true;
1303}
1304
1305void
1306IGbE::txWire()
1307{
1308    if (txFifo.empty()) {
1309        txFifoTick = false;
1310        return;
1311    }
1312
1313
1314    if (etherInt->sendPacket(txFifo.front())) {
1315        DPRINTF(EthernetSM, "TxFIFO: Successful transmit, bytes available in fifo: %d\n",
1316                txFifo.avail());
1317        txFifo.pop();
1318    } else {
1319        // We'll get woken up when the packet ethTxDone() gets called
1320        txFifoTick = false;
1321    }
1322
1323}
1324
1325void
1326IGbE::tick()
1327{
1328    DPRINTF(EthernetSM, "IGbE: -------------- Cycle --------------\n");
1329
1330    if (rxTick)
1331        rxStateMachine();
1332
1333    if (txTick)
1334        txStateMachine();
1335
1336    if (txFifoTick)
1337        txWire();
1338
1339
1340    if (rxTick || txTick || txFifoTick)
1341        tickEvent.schedule(curTick + cycles(1));
1342}
1343
1344void
1345IGbE::ethTxDone()
1346{
1347    // restart the tx state machines if they are stopped
1348    // fifo to send another packet
1349    // tx sm to put more data into the fifo
1350    txFifoTick = true;
1351    txTick = true;
1352
1353    restartClock();
1354    DPRINTF(EthernetSM, "TxFIFO: Transmission complete\n");
1355}
1356
1357void
1358IGbE::serialize(std::ostream &os)
1359{
1360    PciDev::serialize(os);
1361
1362    regs.serialize(os);
1363    SERIALIZE_SCALAR(eeOpBits);
1364    SERIALIZE_SCALAR(eeAddrBits);
1365    SERIALIZE_SCALAR(eeDataBits);
1366    SERIALIZE_SCALAR(eeOpcode);
1367    SERIALIZE_SCALAR(eeAddr);
1368    SERIALIZE_ARRAY(flash,iGbReg::EEPROM_SIZE);
1369
1370    rxFifo.serialize("rxfifo", os);
1371    txFifo.serialize("txfifo", os);
1372
1373    bool txPktExists = txPacket;
1374    SERIALIZE_SCALAR(txPktExists);
1375    if (txPktExists)
1376        txPacket->serialize("txpacket", os);
1377
1378    Tick rdtr_time = 0, radv_time = 0, tidv_time = 0, tadv_time = 0,
1379         inter_time = 0;
1380
1381    if (rdtrEvent.scheduled())
1382       rdtr_time = rdtrEvent.when();
1383    SERIALIZE_SCALAR(rdtr_time);
1384
1385    if (radvEvent.scheduled())
1386       radv_time = radvEvent.when();
1387    SERIALIZE_SCALAR(radv_time);
1388
1389    if (tidvEvent.scheduled())
1390       rdtr_time = tidvEvent.when();
1391    SERIALIZE_SCALAR(tidv_time);
1392
1393    if (tadvEvent.scheduled())
1394       rdtr_time = tadvEvent.when();
1395    SERIALIZE_SCALAR(tadv_time);
1396
1397    if (interEvent.scheduled())
1398       rdtr_time = interEvent.when();
1399    SERIALIZE_SCALAR(inter_time);
1400
1401    nameOut(os, csprintf("%s.TxDescCache", name()));
1402    txDescCache.serialize(os);
1403
1404    nameOut(os, csprintf("%s.RxDescCache", name()));
1405    rxDescCache.serialize(os);
1406}
1407
1408void
1409IGbE::unserialize(Checkpoint *cp, const std::string &section)
1410{
1411    PciDev::unserialize(cp, section);
1412
1413    regs.unserialize(cp, section);
1414    UNSERIALIZE_SCALAR(eeOpBits);
1415    UNSERIALIZE_SCALAR(eeAddrBits);
1416    UNSERIALIZE_SCALAR(eeDataBits);
1417    UNSERIALIZE_SCALAR(eeOpcode);
1418    UNSERIALIZE_SCALAR(eeAddr);
1419    UNSERIALIZE_ARRAY(flash,iGbReg::EEPROM_SIZE);
1420
1421    rxFifo.unserialize("rxfifo", cp, section);
1422    txFifo.unserialize("txfifo", cp, section);
1423
1424    bool txPktExists;
1425    UNSERIALIZE_SCALAR(txPktExists);
1426    if (txPktExists) {
1427        txPacket = new EthPacketData(16384);
1428        txPacket->unserialize("txpacket", cp, section);
1429    }
1430
1431    rxTick = true;
1432    txTick = true;
1433    txFifoTick = true;
1434
1435    Tick rdtr_time, radv_time, tidv_time, tadv_time, inter_time;
1436    UNSERIALIZE_SCALAR(rdtr_time);
1437    UNSERIALIZE_SCALAR(radv_time);
1438    UNSERIALIZE_SCALAR(tidv_time);
1439    UNSERIALIZE_SCALAR(tadv_time);
1440    UNSERIALIZE_SCALAR(inter_time);
1441
1442    if (rdtr_time)
1443        rdtrEvent.schedule(rdtr_time);
1444
1445    if (radv_time)
1446        radvEvent.schedule(radv_time);
1447
1448    if (tidv_time)
1449        tidvEvent.schedule(tidv_time);
1450
1451    if (tadv_time)
1452        tadvEvent.schedule(tadv_time);
1453
1454    if (inter_time)
1455        interEvent.schedule(inter_time);
1456
1457    txDescCache.unserialize(cp, csprintf("%s.TxDescCache", section));
1458
1459    rxDescCache.unserialize(cp, csprintf("%s.RxDescCache", section));
1460}
1461
1462IGbE *
1463IGbEParams::create()
1464{
1465    return new IGbE(this);
1466}
1467