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