i8254xGBe.cc revision 5954
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), pktOffset(0),
61      fetchDelay(p->fetch_delay), wbDelay(p->wb_delay),
62      fetchCompDelay(p->fetch_comp_delay), wbCompDelay(p->wb_comp_delay),
63      rxWriteDelay(p->rx_write_delay), txReadDelay(p->tx_read_delay),
64      rdtrEvent(this), radvEvent(this),
65      tadvEvent(this), tidvEvent(this), tickEvent(this), interEvent(this),
66      rxDescCache(this, name()+".RxDesc", p->rx_desc_cache_size),
67      txDescCache(this, name()+".TxDesc", p->tx_desc_cache_size),
68      clock(p->clock), lastInterrupt(0)
69{
70    etherInt = new IGbEInt(name() + ".int", this);
71
72    // Initialized internal registers per Intel documentation
73    // All registers intialized to 0 by per register constructor
74    regs.ctrl.fd(1);
75    regs.ctrl.lrst(1);
76    regs.ctrl.speed(2);
77    regs.ctrl.frcspd(1);
78    regs.sts.speed(3); // Say we're 1000Mbps
79    regs.sts.fd(1); // full duplex
80    regs.sts.lu(1); // link up
81    regs.eecd.fwe(1);
82    regs.eecd.ee_type(1);
83    regs.imr = 0;
84    regs.iam = 0;
85    regs.rxdctl.gran(1);
86    regs.rxdctl.wthresh(1);
87    regs.fcrth(1);
88    regs.tdwba = 0;
89    regs.rlpml = 0;
90    regs.sw_fw_sync = 0;
91
92    regs.pba.rxa(0x30);
93    regs.pba.txa(0x10);
94
95    eeOpBits            = 0;
96    eeAddrBits          = 0;
97    eeDataBits          = 0;
98    eeOpcode            = 0;
99
100    // clear all 64 16 bit words of the eeprom
101    memset(&flash, 0, EEPROM_SIZE*2);
102
103    // Set the MAC address
104    memcpy(flash, p->hardware_address.bytes(), ETH_ADDR_LEN);
105    for (int x = 0; x < ETH_ADDR_LEN/2; x++)
106        flash[x] = htobe(flash[x]);
107
108    uint16_t csum = 0;
109    for (int x = 0; x < EEPROM_SIZE; x++)
110        csum += htobe(flash[x]);
111
112
113    // Magic happy checksum value
114    flash[EEPROM_SIZE-1] = htobe((uint16_t)(EEPROM_CSUM - csum));
115
116    // Store the MAC address as queue ID
117    macAddr = p->hardware_address;
118
119    rxFifo.clear();
120    txFifo.clear();
121}
122
123void
124IGbE::init()
125{
126    cpa = CPA::cpa();
127    PciDev::init();
128}
129
130EtherInt*
131IGbE::getEthPort(const std::string &if_name, int idx)
132{
133
134    if (if_name == "interface") {
135        if (etherInt->getPeer())
136            panic("Port already connected to\n");
137        return etherInt;
138    }
139    return NULL;
140}
141
142Tick
143IGbE::writeConfig(PacketPtr pkt)
144{
145    int offset = pkt->getAddr() & PCI_CONFIG_SIZE;
146    if (offset < PCI_DEVICE_SPECIFIC)
147        PciDev::writeConfig(pkt);
148    else
149        panic("Device specific PCI config space not implemented.\n");
150
151    ///
152    /// Some work may need to be done here based for the pci COMMAND bits.
153    ///
154
155    return pioDelay;
156}
157
158Tick
159IGbE::read(PacketPtr pkt)
160{
161    int bar;
162    Addr daddr;
163
164    if (!getBAR(pkt->getAddr(), bar, daddr))
165        panic("Invalid PCI memory access to unmapped memory.\n");
166
167    // Only Memory register BAR is allowed
168    assert(bar == 0);
169
170    // Only 32bit accesses allowed
171    assert(pkt->getSize() == 4);
172
173    DPRINTF(Ethernet, "Read device register %#X\n", daddr);
174
175    pkt->allocate();
176
177    ///
178    /// Handle read of register here
179    ///
180
181
182    switch (daddr) {
183      case REG_CTRL:
184        pkt->set<uint32_t>(regs.ctrl());
185        break;
186      case REG_STATUS:
187        pkt->set<uint32_t>(regs.sts());
188        break;
189      case REG_EECD:
190        pkt->set<uint32_t>(regs.eecd());
191        break;
192      case REG_EERD:
193        pkt->set<uint32_t>(regs.eerd());
194        break;
195      case REG_CTRL_EXT:
196        pkt->set<uint32_t>(regs.ctrl_ext());
197        break;
198      case REG_MDIC:
199        pkt->set<uint32_t>(regs.mdic());
200        break;
201      case REG_ICR:
202        DPRINTF(Ethernet, "Reading ICR. ICR=%#x IMR=%#x IAM=%#x IAME=%d\n", regs.icr(),
203                regs.imr, regs.iam, regs.ctrl_ext.iame());
204        pkt->set<uint32_t>(regs.icr());
205        if (regs.icr.int_assert() || regs.imr == 0) {
206            regs.icr = regs.icr() & ~mask(30);
207            DPRINTF(Ethernet, "Cleared ICR. ICR=%#x\n", regs.icr());
208        }
209        if (regs.ctrl_ext.iame() && regs.icr.int_assert())
210            regs.imr &= ~regs.iam;
211        chkInterrupt();
212        break;
213      case REG_EICR:
214        // This is only useful for MSI, but the driver reads it every time
215        // Just don't do anything
216        pkt->set<uint32_t>(0);
217        break;
218      case REG_ITR:
219        pkt->set<uint32_t>(regs.itr());
220        break;
221      case REG_RCTL:
222        pkt->set<uint32_t>(regs.rctl());
223        break;
224      case REG_FCTTV:
225        pkt->set<uint32_t>(regs.fcttv());
226        break;
227      case REG_TCTL:
228        pkt->set<uint32_t>(regs.tctl());
229        break;
230      case REG_PBA:
231        pkt->set<uint32_t>(regs.pba());
232        break;
233      case REG_WUC:
234      case REG_LEDCTL:
235        pkt->set<uint32_t>(0); // We don't care, so just return 0
236        break;
237      case REG_FCRTL:
238        pkt->set<uint32_t>(regs.fcrtl());
239        break;
240      case REG_FCRTH:
241        pkt->set<uint32_t>(regs.fcrth());
242        break;
243      case REG_RDBAL:
244        pkt->set<uint32_t>(regs.rdba.rdbal());
245        break;
246      case REG_RDBAH:
247        pkt->set<uint32_t>(regs.rdba.rdbah());
248        break;
249      case REG_RDLEN:
250        pkt->set<uint32_t>(regs.rdlen());
251        break;
252      case REG_SRRCTL:
253        pkt->set<uint32_t>(regs.srrctl());
254        break;
255      case REG_RDH:
256        pkt->set<uint32_t>(regs.rdh());
257        break;
258      case REG_RDT:
259        pkt->set<uint32_t>(regs.rdt());
260        break;
261      case REG_RDTR:
262        pkt->set<uint32_t>(regs.rdtr());
263        if (regs.rdtr.fpd()) {
264            rxDescCache.writeback(0);
265            DPRINTF(EthernetIntr, "Posting interrupt because of RDTR.FPD write\n");
266            postInterrupt(IT_RXT);
267            regs.rdtr.fpd(0);
268        }
269        break;
270      case REG_RXDCTL:
271        pkt->set<uint32_t>(regs.rxdctl());
272        break;
273      case REG_RADV:
274        pkt->set<uint32_t>(regs.radv());
275        break;
276      case REG_TDBAL:
277        pkt->set<uint32_t>(regs.tdba.tdbal());
278        break;
279      case REG_TDBAH:
280        pkt->set<uint32_t>(regs.tdba.tdbah());
281        break;
282      case REG_TDLEN:
283        pkt->set<uint32_t>(regs.tdlen());
284        break;
285      case REG_TDH:
286        pkt->set<uint32_t>(regs.tdh());
287        break;
288      case REG_TXDCA_CTL:
289        pkt->set<uint32_t>(regs.txdca_ctl());
290        break;
291      case REG_TDT:
292        pkt->set<uint32_t>(regs.tdt());
293        break;
294      case REG_TIDV:
295        pkt->set<uint32_t>(regs.tidv());
296        break;
297      case REG_TXDCTL:
298        pkt->set<uint32_t>(regs.txdctl());
299        break;
300      case REG_TADV:
301        pkt->set<uint32_t>(regs.tadv());
302        break;
303      case REG_TDWBAL:
304        pkt->set<uint32_t>(regs.tdwba & mask(32));
305        break;
306      case REG_TDWBAH:
307        pkt->set<uint32_t>(regs.tdwba >> 32);
308        break;
309      case REG_RXCSUM:
310        pkt->set<uint32_t>(regs.rxcsum());
311        break;
312      case REG_RLPML:
313        pkt->set<uint32_t>(regs.rlpml);
314        break;
315      case REG_RFCTL:
316        pkt->set<uint32_t>(regs.rfctl());
317        break;
318      case REG_MANC:
319        pkt->set<uint32_t>(regs.manc());
320        break;
321      case REG_SWSM:
322        pkt->set<uint32_t>(regs.swsm());
323        regs.swsm.smbi(1);
324        break;
325      case REG_FWSM:
326        pkt->set<uint32_t>(regs.fwsm());
327        break;
328      case REG_SWFWSYNC:
329        pkt->set<uint32_t>(regs.sw_fw_sync);
330        break;
331      default:
332        if (!(daddr >= REG_VFTA && daddr < (REG_VFTA + VLAN_FILTER_TABLE_SIZE*4)) &&
333            !(daddr >= REG_RAL && daddr < (REG_RAL + RCV_ADDRESS_TABLE_SIZE*8)) &&
334            !(daddr >= REG_MTA && daddr < (REG_MTA + MULTICAST_TABLE_SIZE*4)) &&
335            !(daddr >= REG_CRCERRS && daddr < (REG_CRCERRS + STATS_REGS_SIZE)))
336            panic("Read request to unknown register number: %#x\n", daddr);
337        else
338            pkt->set<uint32_t>(0);
339    };
340
341    pkt->makeAtomicResponse();
342    return pioDelay;
343}
344
345Tick
346IGbE::write(PacketPtr pkt)
347{
348    int bar;
349    Addr daddr;
350
351
352    if (!getBAR(pkt->getAddr(), bar, daddr))
353        panic("Invalid PCI memory access to unmapped memory.\n");
354
355    // Only Memory register BAR is allowed
356    assert(bar == 0);
357
358    // Only 32bit accesses allowed
359    assert(pkt->getSize() == sizeof(uint32_t));
360
361    DPRINTF(Ethernet, "Wrote device register %#X value %#X\n", daddr, pkt->get<uint32_t>());
362
363    ///
364    /// Handle write of register here
365    ///
366    uint32_t val = pkt->get<uint32_t>();
367
368    Regs::RCTL oldrctl;
369    Regs::TCTL oldtctl;
370
371    switch (daddr) {
372      case REG_CTRL:
373        regs.ctrl = val;
374        if (regs.ctrl.tfce())
375            warn("TX Flow control enabled, should implement\n");
376        if (regs.ctrl.rfce())
377            warn("RX Flow control enabled, should implement\n");
378        break;
379      case REG_CTRL_EXT:
380        regs.ctrl_ext = val;
381        break;
382      case REG_STATUS:
383        regs.sts = val;
384        break;
385      case REG_EECD:
386        int oldClk;
387        oldClk = regs.eecd.sk();
388        regs.eecd = val;
389        // See if this is a eeprom access and emulate accordingly
390        if (!oldClk && regs.eecd.sk()) {
391            if (eeOpBits < 8) {
392                eeOpcode = eeOpcode << 1 | regs.eecd.din();
393                eeOpBits++;
394            } else if (eeAddrBits < 8 && eeOpcode == EEPROM_READ_OPCODE_SPI) {
395                eeAddr = eeAddr << 1 | regs.eecd.din();
396                eeAddrBits++;
397            } else if (eeDataBits < 16 && eeOpcode == EEPROM_READ_OPCODE_SPI) {
398                assert(eeAddr>>1 < EEPROM_SIZE);
399                DPRINTF(EthernetEEPROM, "EEPROM bit read: %d word: %#X\n",
400                        flash[eeAddr>>1] >> eeDataBits & 0x1, flash[eeAddr>>1]);
401                regs.eecd.dout((flash[eeAddr>>1] >> (15-eeDataBits)) & 0x1);
402                eeDataBits++;
403            } else if (eeDataBits < 8 && eeOpcode == EEPROM_RDSR_OPCODE_SPI) {
404                regs.eecd.dout(0);
405                eeDataBits++;
406            } else
407                panic("What's going on with eeprom interface? opcode:"
408                       " %#x:%d addr: %#x:%d, data: %d\n", (uint32_t)eeOpcode,
409                       (uint32_t)eeOpBits, (uint32_t)eeAddr,
410                       (uint32_t)eeAddrBits, (uint32_t)eeDataBits);
411
412            // Reset everything for the next command
413            if ((eeDataBits == 16 && eeOpcode == EEPROM_READ_OPCODE_SPI) ||
414               (eeDataBits == 8 && eeOpcode == EEPROM_RDSR_OPCODE_SPI)) {
415                eeOpBits = 0;
416                eeAddrBits = 0;
417                eeDataBits = 0;
418               eeOpcode = 0;
419                eeAddr = 0;
420            }
421
422           DPRINTF(EthernetEEPROM, "EEPROM: opcode: %#X:%d addr: %#X:%d\n",
423                    (uint32_t)eeOpcode, (uint32_t) eeOpBits,
424                    (uint32_t)eeAddr>>1, (uint32_t)eeAddrBits);
425           if (eeOpBits == 8 && !(eeOpcode == EEPROM_READ_OPCODE_SPI ||
426                                   eeOpcode == EEPROM_RDSR_OPCODE_SPI ))
427                panic("Unknown eeprom opcode: %#X:%d\n", (uint32_t)eeOpcode,
428                        (uint32_t)eeOpBits);
429
430
431        }
432        // If driver requests eeprom access, immediately give it to it
433        regs.eecd.ee_gnt(regs.eecd.ee_req());
434        break;
435      case REG_EERD:
436        regs.eerd = val;
437        if (regs.eerd.start()) {
438            regs.eerd.done(1);
439            assert(regs.eerd.addr() < EEPROM_SIZE);
440            regs.eerd.data(flash[regs.eerd.addr()]);
441            regs.eerd.start(0);
442            DPRINTF(EthernetEEPROM, "EEPROM: read addr: %#X data %#x\n",
443                    regs.eerd.addr(), regs.eerd.data());
444        }
445        break;
446      case REG_MDIC:
447        regs.mdic = val;
448        if (regs.mdic.i())
449            panic("No support for interrupt on mdic complete\n");
450        if (regs.mdic.phyadd() != 1)
451            panic("No support for reading anything but phy\n");
452        DPRINTF(Ethernet, "%s phy address %x\n", regs.mdic.op() == 1 ? "Writing"
453                : "Reading", regs.mdic.regadd());
454        switch (regs.mdic.regadd()) {
455            case PHY_PSTATUS:
456                regs.mdic.data(0x796D); // link up
457                break;
458            case PHY_PID:
459                regs.mdic.data(params()->phy_pid);
460                break;
461            case PHY_EPID:
462                regs.mdic.data(params()->phy_epid);
463                break;
464            case PHY_GSTATUS:
465                regs.mdic.data(0x7C00);
466                break;
467            case PHY_EPSTATUS:
468                regs.mdic.data(0x3000);
469                break;
470            case PHY_AGC:
471                regs.mdic.data(0x180); // some random length
472                break;
473            default:
474                regs.mdic.data(0);
475        }
476        regs.mdic.r(1);
477        break;
478      case REG_ICR:
479        DPRINTF(Ethernet, "Writing ICR. ICR=%#x IMR=%#x IAM=%#x IAME=%d\n", regs.icr(),
480                regs.imr, regs.iam, regs.ctrl_ext.iame());
481        if (regs.ctrl_ext.iame())
482            regs.imr &= ~regs.iam;
483        regs.icr = ~bits(val,30,0) & regs.icr();
484        chkInterrupt();
485        break;
486      case REG_ITR:
487        regs.itr = val;
488        break;
489      case REG_ICS:
490        DPRINTF(EthernetIntr, "Posting interrupt because of ICS write\n");
491        postInterrupt((IntTypes)val);
492        break;
493       case REG_IMS:
494        regs.imr |= val;
495        chkInterrupt();
496        break;
497      case REG_IMC:
498        regs.imr &= ~val;
499        chkInterrupt();
500        break;
501      case REG_IAM:
502        regs.iam = val;
503        break;
504      case REG_RCTL:
505        oldrctl = regs.rctl;
506        regs.rctl = val;
507        if (regs.rctl.rst()) {
508            rxDescCache.reset();
509            DPRINTF(EthernetSM, "RXS: Got RESET!\n");
510            rxFifo.clear();
511            regs.rctl.rst(0);
512        }
513        if (regs.rctl.en())
514            rxTick = true;
515        restartClock();
516        break;
517      case REG_FCTTV:
518        regs.fcttv = val;
519        break;
520      case REG_TCTL:
521        regs.tctl = val;
522        oldtctl = regs.tctl;
523        regs.tctl = val;
524        if (regs.tctl.en())
525           txTick = true;
526        restartClock();
527        if (regs.tctl.en() && !oldtctl.en()) {
528            txDescCache.reset();
529        }
530         break;
531      case REG_PBA:
532        regs.pba.rxa(val);
533        regs.pba.txa(64 - regs.pba.rxa());
534        break;
535      case REG_WUC:
536      case REG_LEDCTL:
537      case REG_FCAL:
538      case REG_FCAH:
539      case REG_FCT:
540      case REG_VET:
541      case REG_AIFS:
542      case REG_TIPG:
543        ; // We don't care, so don't store anything
544        break;
545      case REG_IVAR0:
546        warn("Writing to IVAR0, ignoring...\n");
547        break;
548      case REG_FCRTL:
549        regs.fcrtl = val;
550        break;
551      case REG_FCRTH:
552        regs.fcrth = val;
553        break;
554      case REG_RDBAL:
555        regs.rdba.rdbal( val & ~mask(4));
556        rxDescCache.areaChanged();
557        break;
558      case REG_RDBAH:
559        regs.rdba.rdbah(val);
560        rxDescCache.areaChanged();
561        break;
562      case REG_RDLEN:
563        regs.rdlen = val & ~mask(7);
564        rxDescCache.areaChanged();
565        break;
566      case REG_SRRCTL:
567        regs.srrctl = val;
568        break;
569      case REG_RDH:
570        regs.rdh = val;
571        rxDescCache.areaChanged();
572        break;
573      case REG_RDT:
574        regs.rdt = val;
575        DPRINTF(EthernetSM, "RXS: RDT Updated.\n");
576        if (getState() == SimObject::Running) {
577            DPRINTF(EthernetSM, "RXS: RDT Fetching Descriptors!\n");
578            rxDescCache.fetchDescriptors();
579        } else {
580            DPRINTF(EthernetSM, "RXS: RDT NOT Fetching Desc b/c draining!\n");
581        }
582        break;
583      case REG_RDTR:
584        regs.rdtr = val;
585        break;
586      case REG_RADV:
587        regs.radv = val;
588        break;
589      case REG_RXDCTL:
590        regs.rxdctl = val;
591        break;
592      case REG_TDBAL:
593        regs.tdba.tdbal( val & ~mask(4));
594        txDescCache.areaChanged();
595        break;
596      case REG_TDBAH:
597        regs.tdba.tdbah(val);
598        txDescCache.areaChanged();
599        break;
600      case REG_TDLEN:
601        regs.tdlen = val & ~mask(7);
602        txDescCache.areaChanged();
603        break;
604      case REG_TDH:
605        regs.tdh = val;
606        txDescCache.areaChanged();
607        break;
608      case REG_TXDCA_CTL:
609        regs.txdca_ctl = val;
610        if (regs.txdca_ctl.enabled())
611            panic("No support for DCA\n");
612        break;
613      case REG_TDT:
614        regs.tdt = val;
615        DPRINTF(EthernetSM, "TXS: TX Tail pointer updated\n");
616        if (getState() == SimObject::Running) {
617            DPRINTF(EthernetSM, "TXS: TDT Fetching Descriptors!\n");
618            txDescCache.fetchDescriptors();
619        } else {
620            DPRINTF(EthernetSM, "TXS: TDT NOT Fetching Desc b/c draining!\n");
621        }
622        break;
623      case REG_TIDV:
624        regs.tidv = val;
625        break;
626      case REG_TXDCTL:
627        regs.txdctl = val;
628        break;
629      case REG_TADV:
630        regs.tadv = val;
631        break;
632      case REG_TDWBAL:
633        regs.tdwba &= ~mask(32);
634        regs.tdwba |= val;
635        txDescCache.completionWriteback(regs.tdwba & ~mask(1), regs.tdwba & mask(1));
636        break;
637      case REG_TDWBAH:
638        regs.tdwba &= mask(32);
639        regs.tdwba |= (uint64_t)val << 32;
640        txDescCache.completionWriteback(regs.tdwba & ~mask(1), regs.tdwba & mask(1));
641        break;
642      case REG_RXCSUM:
643        regs.rxcsum = val;
644        break;
645      case REG_RLPML:
646        regs.rlpml = val;
647        break;
648      case REG_RFCTL:
649        regs.rfctl = val;
650        if (regs.rfctl.exsten())
651            panic("Extended RX descriptors not implemented\n");
652        break;
653      case REG_MANC:
654        regs.manc = val;
655        break;
656      case REG_SWSM:
657        regs.swsm = val;
658        if (regs.fwsm.eep_fw_semaphore())
659            regs.swsm.swesmbi(0);
660        break;
661      case REG_SWFWSYNC:
662        regs.sw_fw_sync = val;
663        break;
664      default:
665       if (!(daddr >= REG_VFTA && daddr < (REG_VFTA + VLAN_FILTER_TABLE_SIZE*4)) &&
666           !(daddr >= REG_RAL && daddr < (REG_RAL + RCV_ADDRESS_TABLE_SIZE*8)) &&
667           !(daddr >= REG_MTA && daddr < (REG_MTA + MULTICAST_TABLE_SIZE*4)))
668           panic("Write request to unknown register number: %#x\n", daddr);
669    };
670
671    pkt->makeAtomicResponse();
672    return pioDelay;
673}
674
675void
676IGbE::postInterrupt(IntTypes t, bool now)
677{
678    assert(t);
679
680    // Interrupt is already pending
681    if (t & regs.icr() && !now)
682        return;
683
684    regs.icr = regs.icr() | t;
685
686    Tick itr_interval = Clock::Int::ns * 256 * regs.itr.interval();
687    DPRINTF(EthernetIntr, "EINT: postInterrupt() curTick: %d itr: %d interval: %d\n",
688            curTick, regs.itr.interval(), itr_interval);
689
690    if (regs.itr.interval() == 0 || now || lastInterrupt + itr_interval <= curTick) {
691        if (interEvent.scheduled()) {
692            deschedule(interEvent);
693        }
694        cpuPostInt();
695    } else {
696       Tick int_time = lastInterrupt + itr_interval;
697       assert(int_time > 0);
698       DPRINTF(EthernetIntr, "EINT: Scheduling timer interrupt for tick %d\n",
699                int_time);
700       if (!interEvent.scheduled()) {
701           schedule(interEvent, int_time);
702       }
703    }
704}
705
706void
707IGbE::delayIntEvent()
708{
709    cpuPostInt();
710}
711
712
713void
714IGbE::cpuPostInt()
715{
716
717    postedInterrupts++;
718
719    if (!(regs.icr() & regs.imr)) {
720        DPRINTF(Ethernet, "Interrupt Masked. Not Posting\n");
721        return;
722    }
723
724    DPRINTF(Ethernet, "Posting Interrupt\n");
725
726
727    if (interEvent.scheduled()) {
728        deschedule(interEvent);
729    }
730
731    if (rdtrEvent.scheduled()) {
732        regs.icr.rxt0(1);
733        deschedule(rdtrEvent);
734    }
735    if (radvEvent.scheduled()) {
736        regs.icr.rxt0(1);
737        deschedule(radvEvent);
738    }
739    if (tadvEvent.scheduled()) {
740        regs.icr.txdw(1);
741        deschedule(tadvEvent);
742    }
743    if (tidvEvent.scheduled()) {
744        regs.icr.txdw(1);
745        deschedule(tidvEvent);
746    }
747
748    regs.icr.int_assert(1);
749    DPRINTF(EthernetIntr, "EINT: Posting interrupt to CPU now. Vector %#x\n",
750            regs.icr());
751
752    intrPost();
753
754    lastInterrupt = curTick;
755}
756
757void
758IGbE::cpuClearInt()
759{
760    if (regs.icr.int_assert()) {
761        regs.icr.int_assert(0);
762        DPRINTF(EthernetIntr, "EINT: Clearing interrupt to CPU now. Vector %#x\n",
763                regs.icr());
764        intrClear();
765    }
766}
767
768void
769IGbE::chkInterrupt()
770{
771    DPRINTF(Ethernet, "Checking interrupts icr: %#x imr: %#x\n", regs.icr(),
772            regs.imr);
773    // Check if we need to clear the cpu interrupt
774    if (!(regs.icr() & regs.imr)) {
775        DPRINTF(Ethernet, "Mask cleaned all interrupts\n");
776        if (interEvent.scheduled())
777           deschedule(interEvent);
778        if (regs.icr.int_assert())
779            cpuClearInt();
780    }
781    DPRINTF(Ethernet, "ITR = %#X itr.interval = %#X\n", regs.itr(), regs.itr.interval());
782
783    if (regs.icr() & regs.imr) {
784        if (regs.itr.interval() == 0)  {
785            cpuPostInt();
786        } else {
787            DPRINTF(Ethernet, "Possibly scheduling interrupt because of imr write\n");
788            if (!interEvent.scheduled()) {
789               DPRINTF(Ethernet, "Scheduling for %d\n", curTick + Clock::Int::ns
790                       * 256 * regs.itr.interval());
791               schedule(interEvent,
792                   curTick + Clock::Int::ns * 256 * regs.itr.interval());
793            }
794        }
795    }
796
797
798}
799
800
801IGbE::RxDescCache::RxDescCache(IGbE *i, const std::string n, int s)
802    : DescCache<RxDesc>(i, n, s), pktDone(false), splitCount(0),
803      pktEvent(this), pktHdrEvent(this), pktDataEvent(this)
804
805{
806    annSmFetch = "RX Desc Fetch";
807    annSmWb = "RX Desc Writeback";
808    annUnusedDescQ = "RX Unused Descriptors";
809    annUnusedCacheQ = "RX Unused Descriptor Cache";
810    annUsedCacheQ = "RX Used Descriptor Cache";
811    annUsedDescQ = "RX Used Descriptors";
812    annDescQ = "RX Descriptors";
813}
814
815void
816IGbE::RxDescCache::pktSplitDone()
817{
818    splitCount++;
819    DPRINTF(EthernetDesc, "Part of split packet done: splitcount now %d\n", splitCount);
820    assert(splitCount <= 2);
821    if (splitCount != 2)
822        return;
823    splitCount = 0;
824    DPRINTF(EthernetDesc, "Part of split packet done: calling pktComplete()\n");
825    pktComplete();
826}
827
828int
829IGbE::RxDescCache::writePacket(EthPacketPtr packet, int pkt_offset)
830{
831        assert(unusedCache.size());
832    //if (!unusedCache.size())
833    //    return false;
834
835    pktPtr = packet;
836    pktDone = false;
837    int buf_len, hdr_len;
838
839    RxDesc *desc = unusedCache.front();
840    switch (igbe->regs.srrctl.desctype()) {
841      case RXDT_LEGACY:
842        assert(pkt_offset == 0);
843        bytesCopied = packet->length;
844        DPRINTF(EthernetDesc, "Packet Length: %d Desc Size: %d\n",
845            packet->length, igbe->regs.rctl.descSize());
846        assert(packet->length < igbe->regs.rctl.descSize());
847        igbe->dmaWrite(igbe->platform->pciToDma(desc->legacy.buf), packet->length, &pktEvent,
848                packet->data, igbe->rxWriteDelay);
849        break;
850      case RXDT_ADV_ONEBUF:
851        assert(pkt_offset == 0);
852        bytesCopied = packet->length;
853        buf_len = igbe->regs.rctl.lpe() ? igbe->regs.srrctl.bufLen() :
854                                              igbe->regs.rctl.descSize();
855        DPRINTF(EthernetDesc, "Packet Length: %d srrctl: %#x Desc Size: %d\n",
856            packet->length, igbe->regs.srrctl(), buf_len);
857        assert(packet->length < buf_len);
858        igbe->dmaWrite(igbe->platform->pciToDma(desc->adv_read.pkt), packet->length, &pktEvent,
859                packet->data, igbe->rxWriteDelay);
860        desc->adv_wb.header_len = htole(0);
861        desc->adv_wb.sph = htole(0);
862        desc->adv_wb.pkt_len = htole((uint16_t)(pktPtr->length));
863        break;
864      case RXDT_ADV_SPLIT_A:
865        int split_point;
866
867        buf_len = igbe->regs.rctl.lpe() ? igbe->regs.srrctl.bufLen() :
868                                              igbe->regs.rctl.descSize();
869        hdr_len = igbe->regs.rctl.lpe() ? igbe->regs.srrctl.hdrLen() : 0;
870        DPRINTF(EthernetDesc, "lpe: %d Packet Length: %d offset: %d srrctl: %#x hdr addr: %#x Hdr Size: %d desc addr: %#x Desc Size: %d\n",
871            igbe->regs.rctl.lpe(), packet->length, pkt_offset, igbe->regs.srrctl(), desc->adv_read.hdr, hdr_len, desc->adv_read.pkt, buf_len);
872
873        split_point = hsplit(pktPtr);
874
875        if (packet->length <= hdr_len) {
876            bytesCopied = packet->length;
877            assert(pkt_offset == 0);
878            DPRINTF(EthernetDesc, "Header Splitting: Entire packet being placed in header\n");
879            igbe->dmaWrite(igbe->platform->pciToDma(desc->adv_read.hdr), packet->length, &pktEvent,
880                    packet->data, igbe->rxWriteDelay);
881            desc->adv_wb.header_len = htole((uint16_t)packet->length);
882            desc->adv_wb.sph = htole(0);
883            desc->adv_wb.pkt_len = htole(0);
884        } else if (split_point) {
885            if (pkt_offset) {
886                // we are only copying some data, header/data has already been
887                // copied
888                int max_to_copy = std::min(packet->length - pkt_offset, buf_len);
889                bytesCopied += max_to_copy;
890                DPRINTF(EthernetDesc, "Header Splitting: Continuing data buffer copy\n");
891                igbe->dmaWrite(igbe->platform->pciToDma(desc->adv_read.pkt),max_to_copy, &pktEvent,
892                        packet->data + pkt_offset, igbe->rxWriteDelay);
893                desc->adv_wb.header_len = htole(0);
894                desc->adv_wb.pkt_len = htole((uint16_t)max_to_copy);
895                desc->adv_wb.sph = htole(0);
896            } else {
897                int max_to_copy = std::min(packet->length - split_point, buf_len);
898                bytesCopied += max_to_copy + split_point;
899
900                DPRINTF(EthernetDesc, "Header Splitting: splitting at %d\n",
901                        split_point);
902                igbe->dmaWrite(igbe->platform->pciToDma(desc->adv_read.hdr), split_point, &pktHdrEvent,
903                        packet->data, igbe->rxWriteDelay);
904                igbe->dmaWrite(igbe->platform->pciToDma(desc->adv_read.pkt),
905                        max_to_copy, &pktDataEvent, packet->data + split_point, igbe->rxWriteDelay);
906                desc->adv_wb.header_len = htole(split_point);
907                desc->adv_wb.sph = 1;
908                desc->adv_wb.pkt_len = htole((uint16_t)(max_to_copy));
909            }
910        } else {
911            panic("Header split not fitting within header buffer or undecodable"
912                  " packet not fitting in header unsupported\n");
913        }
914        break;
915      default:
916        panic("Unimplemnted RX receive buffer type: %d\n",
917                igbe->regs.srrctl.desctype());
918    }
919    return bytesCopied;
920
921}
922
923void
924IGbE::RxDescCache::pktComplete()
925{
926    assert(unusedCache.size());
927    RxDesc *desc;
928    desc = unusedCache.front();
929
930    igbe->anBegin("RXS", "Update Desc");
931
932    uint16_t crcfixup = igbe->regs.rctl.secrc() ? 0 : 4 ;
933    DPRINTF(EthernetDesc, "pktPtr->length: %d bytesCopied: %d stripcrc offset: %d value written: %d %d\n",
934            pktPtr->length, bytesCopied, crcfixup,
935            htole((uint16_t)(pktPtr->length + crcfixup)),
936            (uint16_t)(pktPtr->length + crcfixup));
937
938    // no support for anything but starting at 0
939    assert(igbe->regs.rxcsum.pcss() == 0);
940
941    DPRINTF(EthernetDesc, "Packet written to memory updating Descriptor\n");
942
943    uint16_t status = RXDS_DD;
944    uint8_t err = 0;
945    uint16_t ext_err = 0;
946    uint16_t csum = 0;
947    uint16_t ptype = 0;
948    uint16_t ip_id = 0;
949
950    assert(bytesCopied <= pktPtr->length);
951    if (bytesCopied == pktPtr->length)
952        status |= RXDS_EOP;
953
954    IpPtr ip(pktPtr);
955
956    if (ip) {
957        DPRINTF(EthernetDesc, "Proccesing Ip packet with Id=%d\n", ip->id());
958        ptype |= RXDP_IPV4;
959        ip_id = ip->id();
960
961        if (igbe->regs.rxcsum.ipofld()) {
962            DPRINTF(EthernetDesc, "Checking IP checksum\n");
963            status |= RXDS_IPCS;
964            csum = htole(cksum(ip));
965            igbe->rxIpChecksums++;
966            if (cksum(ip) != 0) {
967                err |= RXDE_IPE;
968                ext_err |= RXDEE_IPE;
969                DPRINTF(EthernetDesc, "Checksum is bad!!\n");
970            }
971        }
972        TcpPtr tcp(ip);
973        if (tcp && igbe->regs.rxcsum.tuofld()) {
974            DPRINTF(EthernetDesc, "Checking TCP checksum\n");
975            status |= RXDS_TCPCS;
976            ptype |= RXDP_TCP;
977            csum = htole(cksum(tcp));
978            igbe->rxTcpChecksums++;
979            if (cksum(tcp) != 0) {
980                DPRINTF(EthernetDesc, "Checksum is bad!!\n");
981                err |= RXDE_TCPE;
982                ext_err |= RXDEE_TCPE;
983            }
984        }
985
986        UdpPtr udp(ip);
987        if (udp && igbe->regs.rxcsum.tuofld()) {
988            DPRINTF(EthernetDesc, "Checking UDP checksum\n");
989            status |= RXDS_UDPCS;
990            ptype |= RXDP_UDP;
991            csum = htole(cksum(udp));
992            igbe->rxUdpChecksums++;
993            if (cksum(udp) != 0) {
994                DPRINTF(EthernetDesc, "Checksum is bad!!\n");
995                ext_err |= RXDEE_TCPE;
996                err |= RXDE_TCPE;
997            }
998        }
999    } else { // if ip
1000        DPRINTF(EthernetSM, "Proccesing Non-Ip packet\n");
1001    }
1002
1003    switch (igbe->regs.srrctl.desctype()) {
1004      case RXDT_LEGACY:
1005        desc->legacy.len = htole((uint16_t)(pktPtr->length + crcfixup));
1006        desc->legacy.status = htole(status);
1007        desc->legacy.errors = htole(err);
1008        // No vlan support at this point... just set it to 0
1009        desc->legacy.vlan = 0;
1010        break;
1011      case RXDT_ADV_SPLIT_A:
1012      case RXDT_ADV_ONEBUF:
1013        desc->adv_wb.rss_type = htole(0);
1014        desc->adv_wb.pkt_type = htole(ptype);
1015        if (igbe->regs.rxcsum.pcsd()) {
1016            // no rss support right now
1017            desc->adv_wb.rss_hash = htole(0);
1018        } else {
1019            desc->adv_wb.id = htole(ip_id);
1020            desc->adv_wb.csum = htole(csum);
1021        }
1022        desc->adv_wb.status = htole(status);
1023        desc->adv_wb.errors = htole(ext_err);
1024        // no vlan support
1025        desc->adv_wb.vlan_tag = htole(0);
1026        break;
1027      default:
1028        panic("Unimplemnted RX receive buffer type %d\n",
1029                igbe->regs.srrctl.desctype());
1030    }
1031
1032    DPRINTF(EthernetDesc, "Descriptor complete w0: %#x w1: %#x\n",
1033            desc->adv_read.pkt, desc->adv_read.hdr);
1034
1035    if (bytesCopied == pktPtr->length) {
1036        DPRINTF(EthernetDesc, "Packet completely written to descriptor buffers\n");
1037        // Deal with the rx timer interrupts
1038        if (igbe->regs.rdtr.delay()) {
1039            DPRINTF(EthernetSM, "RXS: Scheduling DTR for %d\n",
1040                    igbe->regs.rdtr.delay() * igbe->intClock());
1041            igbe->reschedule(igbe->rdtrEvent,
1042                curTick + igbe->regs.rdtr.delay() * igbe->intClock(), true);
1043        }
1044
1045        if (igbe->regs.radv.idv()) {
1046            DPRINTF(EthernetSM, "RXS: Scheduling ADV for %d\n",
1047                    igbe->regs.radv.idv() * igbe->intClock());
1048            if (!igbe->radvEvent.scheduled()) {
1049                igbe->schedule(igbe->radvEvent,
1050                    curTick + igbe->regs.radv.idv() * igbe->intClock());
1051            }
1052        }
1053
1054        // if neither radv or rdtr, maybe itr is set...
1055        if (!igbe->regs.rdtr.delay() && !igbe->regs.radv.idv()) {
1056            DPRINTF(EthernetSM, "RXS: Receive interrupt delay disabled, posting IT_RXT\n");
1057            igbe->postInterrupt(IT_RXT);
1058        }
1059
1060        // If the packet is small enough, interrupt appropriately
1061        // I wonder if this is delayed or not?!
1062        if (pktPtr->length <= igbe->regs.rsrpd.idv()) {
1063            DPRINTF(EthernetSM, "RXS: Posting IT_SRPD beacuse small packet received\n");
1064            igbe->postInterrupt(IT_SRPD);
1065        }
1066        bytesCopied = 0;
1067    }
1068
1069    pktPtr = NULL;
1070    igbe->checkDrain();
1071    enableSm();
1072    pktDone = true;
1073
1074    igbe->anBegin("RXS", "Done Updating Desc");
1075    DPRINTF(EthernetDesc, "Processing of this descriptor complete\n");
1076    igbe->anDq("RXS", annUnusedCacheQ);
1077    unusedCache.pop_front();
1078    igbe->anQ("RXS", annUsedCacheQ);
1079    usedCache.push_back(desc);
1080}
1081
1082void
1083IGbE::RxDescCache::enableSm()
1084{
1085    if (!igbe->drainEvent) {
1086        igbe->rxTick = true;
1087        igbe->restartClock();
1088    }
1089}
1090
1091bool
1092IGbE::RxDescCache::packetDone()
1093{
1094    if (pktDone) {
1095        pktDone = false;
1096        return true;
1097    }
1098    return false;
1099}
1100
1101bool
1102IGbE::RxDescCache::hasOutstandingEvents()
1103{
1104    return pktEvent.scheduled() || wbEvent.scheduled() ||
1105        fetchEvent.scheduled() || pktHdrEvent.scheduled() ||
1106        pktDataEvent.scheduled();
1107
1108}
1109
1110void
1111IGbE::RxDescCache::serialize(std::ostream &os)
1112{
1113    DescCache<RxDesc>::serialize(os);
1114    SERIALIZE_SCALAR(pktDone);
1115    SERIALIZE_SCALAR(splitCount);
1116    SERIALIZE_SCALAR(bytesCopied);
1117}
1118
1119void
1120IGbE::RxDescCache::unserialize(Checkpoint *cp, const std::string &section)
1121{
1122    DescCache<RxDesc>::unserialize(cp, section);
1123    UNSERIALIZE_SCALAR(pktDone);
1124    UNSERIALIZE_SCALAR(splitCount);
1125    UNSERIALIZE_SCALAR(bytesCopied);
1126}
1127
1128
1129///////////////////////////////////// IGbE::TxDesc /////////////////////////////////
1130
1131IGbE::TxDescCache::TxDescCache(IGbE *i, const std::string n, int s)
1132    : DescCache<TxDesc>(i,n, s), pktDone(false), isTcp(false), pktWaiting(false),
1133       completionAddress(0), completionEnabled(false),
1134       useTso(false), pktEvent(this), headerEvent(this), nullEvent(this)
1135
1136{
1137    annSmFetch = "TX Desc Fetch";
1138    annSmWb = "TX Desc Writeback";
1139    annUnusedDescQ = "TX Unused Descriptors";
1140    annUnusedCacheQ = "TX Unused Descriptor Cache";
1141    annUsedCacheQ = "TX Used Descriptor Cache";
1142    annUsedDescQ = "TX Used Descriptors";
1143    annDescQ = "TX Descriptors";
1144}
1145
1146void
1147IGbE::TxDescCache::processContextDesc()
1148{
1149    assert(unusedCache.size());
1150    TxDesc *desc;
1151
1152    DPRINTF(EthernetDesc, "Checking and  processing context descriptors\n");
1153
1154    while (!useTso && unusedCache.size() && TxdOp::isContext(unusedCache.front())) {
1155        DPRINTF(EthernetDesc, "Got context descriptor type...\n");
1156
1157        desc = unusedCache.front();
1158        DPRINTF(EthernetDesc, "Descriptor upper: %#x lower: %#X\n",
1159                    desc->d1, desc->d2);
1160
1161
1162        // is this going to be a tcp or udp packet?
1163        isTcp = TxdOp::tcp(desc) ? true : false;
1164
1165        // setup all the TSO variables, they'll be ignored if we don't use
1166        // tso for this connection
1167        tsoHeaderLen = TxdOp::hdrlen(desc);
1168        tsoMss  = TxdOp::mss(desc);
1169
1170        if (TxdOp::isType(desc, TxdOp::TXD_CNXT) && TxdOp::tse(desc)) {
1171            DPRINTF(EthernetDesc, "TCP offload enabled for packet hdrlen: %d mss: %d paylen %d\n",
1172                    TxdOp::hdrlen(desc), TxdOp::mss(desc), TxdOp::getLen(desc));
1173            useTso = true;
1174            tsoTotalLen = TxdOp::getLen(desc);
1175            tsoLoadedHeader = false;
1176            tsoDescBytesUsed = 0;
1177            tsoUsedLen = 0;
1178            tsoPrevSeq = 0;
1179            tsoPktHasHeader = false;
1180            tsoPkts = 0;
1181
1182        }
1183
1184        TxdOp::setDd(desc);
1185        unusedCache.pop_front();
1186        igbe->anDq("TXS", annUnusedCacheQ);
1187        usedCache.push_back(desc);
1188        igbe->anQ("TXS", annUsedCacheQ);
1189    }
1190
1191    if (!unusedCache.size())
1192        return;
1193
1194    desc = unusedCache.front();
1195    if (!useTso && TxdOp::isType(desc, TxdOp::TXD_ADVDATA) && TxdOp::tse(desc)) {
1196        DPRINTF(EthernetDesc, "TCP offload(adv) enabled for packet hdrlen: %d mss: %d paylen %d\n",
1197                tsoHeaderLen, tsoMss, TxdOp::getTsoLen(desc));
1198        useTso = true;
1199        tsoTotalLen = TxdOp::getTsoLen(desc);
1200        tsoLoadedHeader = false;
1201        tsoDescBytesUsed = 0;
1202        tsoUsedLen = 0;
1203        tsoPrevSeq = 0;
1204        tsoPktHasHeader = false;
1205        tsoPkts = 0;
1206    }
1207
1208    if (useTso && !tsoLoadedHeader) {
1209        // we need to fetch a header
1210        DPRINTF(EthernetDesc, "Starting DMA of TSO header\n");
1211        assert(TxdOp::isData(desc) && TxdOp::getLen(desc) >= tsoHeaderLen);
1212        pktWaiting = true;
1213        assert(tsoHeaderLen <= 256);
1214        igbe->dmaRead(igbe->platform->pciToDma(TxdOp::getBuf(desc)),
1215                tsoHeaderLen, &headerEvent, tsoHeader, 0);
1216    }
1217}
1218
1219void
1220IGbE::TxDescCache::headerComplete()
1221{
1222    DPRINTF(EthernetDesc, "TSO: Fetching TSO header complete\n");
1223    pktWaiting = false;
1224
1225    assert(unusedCache.size());
1226    TxDesc *desc = unusedCache.front();
1227    DPRINTF(EthernetDesc, "TSO: len: %d tsoHeaderLen: %d\n",
1228            TxdOp::getLen(desc), tsoHeaderLen);
1229
1230    if (TxdOp::getLen(desc) == tsoHeaderLen) {
1231        tsoDescBytesUsed = 0;
1232        tsoLoadedHeader = true;
1233        unusedCache.pop_front();
1234        usedCache.push_back(desc);
1235    } else {
1236        // I don't think this case happens, I think the headrer is always
1237        // it's own packet, if it wasn't it might be as simple as just
1238        // incrementing descBytesUsed by the header length, but I'm not
1239        // completely sure
1240        panic("TSO header part of bigger packet, not implemented\n");
1241    }
1242    enableSm();
1243    igbe->checkDrain();
1244}
1245
1246int
1247IGbE::TxDescCache::getPacketSize(EthPacketPtr p)
1248{
1249    TxDesc *desc;
1250
1251
1252    if (!unusedCache.size())
1253        return -1;
1254
1255    DPRINTF(EthernetDesc, "Starting processing of descriptor\n");
1256
1257    assert(!useTso || tsoLoadedHeader);
1258    desc = unusedCache.front();
1259
1260
1261    if (useTso) {
1262        DPRINTF(EthernetDesc, "getPacket(): TxDescriptor data d1: %#llx d2: %#llx\n", desc->d1, desc->d2);
1263        DPRINTF(EthernetDesc, "TSO: use: %d hdrlen: %d mss: %d total: %d used: %d loaded hdr: %d\n",
1264                useTso, tsoHeaderLen, tsoMss, tsoTotalLen, tsoUsedLen, tsoLoadedHeader);
1265        DPRINTF(EthernetDesc, "TSO: descBytesUsed: %d copyBytes: %d this descLen: %d\n",
1266                tsoDescBytesUsed, tsoCopyBytes, TxdOp::getLen(desc));
1267        DPRINTF(EthernetDesc, "TSO: pktHasHeader: %d\n", tsoPktHasHeader);
1268
1269        if (tsoPktHasHeader)
1270            tsoCopyBytes =  std::min((tsoMss + tsoHeaderLen) - p->length, TxdOp::getLen(desc) - tsoDescBytesUsed);
1271        else
1272            tsoCopyBytes =  std::min(tsoMss, TxdOp::getLen(desc) - tsoDescBytesUsed);
1273        Addr pkt_size = tsoCopyBytes + (tsoPktHasHeader ? 0 : tsoHeaderLen);
1274        DPRINTF(EthernetDesc, "TSO: Next packet is %d bytes\n", pkt_size);
1275        return pkt_size;
1276    }
1277
1278    DPRINTF(EthernetDesc, "Next TX packet is %d bytes\n",
1279                TxdOp::getLen(unusedCache.front()));
1280    return TxdOp::getLen(desc);
1281}
1282
1283void
1284IGbE::TxDescCache::getPacketData(EthPacketPtr p)
1285{
1286    assert(unusedCache.size());
1287
1288    TxDesc *desc;
1289    desc = unusedCache.front();
1290
1291    DPRINTF(EthernetDesc, "getPacketData(): TxDescriptor data d1: %#llx d2: %#llx\n", desc->d1, desc->d2);
1292    assert((TxdOp::isLegacy(desc) || TxdOp::isData(desc)) && TxdOp::getLen(desc));
1293
1294    pktPtr = p;
1295
1296    pktWaiting = true;
1297
1298    DPRINTF(EthernetDesc, "Starting DMA of packet at offset %d\n", p->length);
1299
1300    if (useTso) {
1301        assert(tsoLoadedHeader);
1302        if (!tsoPktHasHeader) {
1303            DPRINTF(EthernetDesc, "Loading TSO header (%d bytes) into start of packet\n",
1304                   tsoHeaderLen);
1305            memcpy(p->data, &tsoHeader,tsoHeaderLen);
1306            p->length +=tsoHeaderLen;
1307            tsoPktHasHeader = true;
1308        }
1309    }
1310
1311    if (useTso) {
1312        tsoDescBytesUsed += tsoCopyBytes;
1313        assert(tsoDescBytesUsed <= TxdOp::getLen(desc));
1314        DPRINTF(EthernetDesc, "Starting DMA of packet at offset %d length: %d\n",
1315                p->length, tsoCopyBytes);
1316        igbe->dmaRead(igbe->platform->pciToDma(TxdOp::getBuf(desc)) + tsoDescBytesUsed,
1317            tsoCopyBytes, &pktEvent, p->data + p->length, igbe->txReadDelay);
1318    } else {
1319        igbe->dmaRead(igbe->platform->pciToDma(TxdOp::getBuf(desc)),
1320            TxdOp::getLen(desc), &pktEvent, p->data + p->length, igbe->txReadDelay);
1321    }
1322}
1323
1324void
1325IGbE::TxDescCache::pktComplete()
1326{
1327
1328    TxDesc *desc;
1329    assert(unusedCache.size());
1330    assert(pktPtr);
1331
1332    igbe->anBegin("TXS", "Update Desc");
1333
1334    DPRINTF(EthernetDesc, "DMA of packet complete\n");
1335
1336
1337    desc = unusedCache.front();
1338    assert((TxdOp::isLegacy(desc) || TxdOp::isData(desc)) && TxdOp::getLen(desc));
1339
1340    DPRINTF(EthernetDesc, "TxDescriptor data d1: %#llx d2: %#llx\n", desc->d1, desc->d2);
1341    DPRINTF(EthernetDesc, "TSO: use: %d hdrlen: %d mss: %d total: %d used: %d loaded hdr: %d\n",
1342            useTso, tsoHeaderLen, tsoMss, tsoTotalLen, tsoUsedLen, tsoLoadedHeader);
1343
1344    // Set the length of the data in the EtherPacket
1345    if (useTso) {
1346        pktPtr->length += tsoCopyBytes;
1347        tsoUsedLen += tsoCopyBytes;
1348    } else
1349        pktPtr->length += TxdOp::getLen(desc);
1350
1351    DPRINTF(EthernetDesc, "TSO: descBytesUsed: %d copyBytes: %d\n",
1352            tsoDescBytesUsed, tsoCopyBytes);
1353
1354
1355    if ((!TxdOp::eop(desc) && !useTso) ||
1356            (pktPtr->length < ( tsoMss + tsoHeaderLen) &&
1357             tsoTotalLen != tsoUsedLen && useTso)) {
1358        assert(!useTso || (tsoDescBytesUsed == TxdOp::getLen(desc)));
1359        igbe->anDq("TXS", annUnusedCacheQ);
1360        unusedCache.pop_front();
1361        igbe->anQ("TXS", annUsedCacheQ);
1362        usedCache.push_back(desc);
1363
1364        tsoDescBytesUsed = 0;
1365        pktDone = true;
1366        pktWaiting = false;
1367        pktMultiDesc = true;
1368
1369        DPRINTF(EthernetDesc, "Partial Packet Descriptor of %d bytes Done\n",
1370                pktPtr->length);
1371        pktPtr = NULL;
1372
1373        enableSm();
1374        igbe->checkDrain();
1375        return;
1376    }
1377
1378
1379    pktMultiDesc = false;
1380    // no support for vlans
1381    assert(!TxdOp::vle(desc));
1382
1383    // we only support single packet descriptors at this point
1384    if (!useTso)
1385        assert(TxdOp::eop(desc));
1386
1387    // set that this packet is done
1388    if (TxdOp::rs(desc))
1389        TxdOp::setDd(desc);
1390
1391    DPRINTF(EthernetDesc, "TxDescriptor data d1: %#llx d2: %#llx\n", desc->d1, desc->d2);
1392
1393    if (useTso) {
1394        IpPtr ip(pktPtr);
1395        if (ip) {
1396            DPRINTF(EthernetDesc, "TSO: Modifying IP header. Id + %d\n",
1397                    tsoPkts);
1398            ip->id(ip->id() + tsoPkts++);
1399            ip->len(pktPtr->length - EthPtr(pktPtr)->size());
1400
1401            TcpPtr tcp(ip);
1402            if (tcp) {
1403                DPRINTF(EthernetDesc, "TSO: Modifying TCP header. old seq %d + %d\n",
1404                    tcp->seq(), tsoPrevSeq);
1405                tcp->seq(tcp->seq() + tsoPrevSeq);
1406                if (tsoUsedLen != tsoTotalLen)
1407                    tcp->flags(tcp->flags() & ~9); // clear fin & psh
1408            }
1409            UdpPtr udp(ip);
1410            if (udp) {
1411                DPRINTF(EthernetDesc, "TSO: Modifying UDP header.\n");
1412                udp->len(pktPtr->length - EthPtr(pktPtr)->size());
1413            }
1414        }
1415        tsoPrevSeq = tsoUsedLen;
1416    }
1417
1418    if (DTRACE(EthernetDesc)) {
1419        IpPtr ip(pktPtr);
1420        if (ip)
1421            DPRINTF(EthernetDesc, "Proccesing Ip packet with Id=%d\n",
1422                    ip->id());
1423        else
1424            DPRINTF(EthernetSM, "Proccesing Non-Ip packet\n");
1425    }
1426
1427    // Checksums are only ofloaded for new descriptor types
1428    if (TxdOp::isData(desc) && ( TxdOp::ixsm(desc) || TxdOp::txsm(desc)) ) {
1429        DPRINTF(EthernetDesc, "Calculating checksums for packet\n");
1430        IpPtr ip(pktPtr);
1431        assert(ip);
1432        if (TxdOp::ixsm(desc)) {
1433            ip->sum(0);
1434            ip->sum(cksum(ip));
1435            igbe->txIpChecksums++;
1436            DPRINTF(EthernetDesc, "Calculated IP checksum\n");
1437        }
1438        if (TxdOp::txsm(desc)) {
1439            TcpPtr tcp(ip);
1440            UdpPtr udp(ip);
1441            if (tcp) {
1442                 tcp->sum(0);
1443                 tcp->sum(cksum(tcp));
1444                 igbe->txTcpChecksums++;
1445                 DPRINTF(EthernetDesc, "Calculated TCP checksum\n");
1446            } else if (udp) {
1447                 assert(udp);
1448                 udp->sum(0);
1449                 udp->sum(cksum(udp));
1450                 igbe->txUdpChecksums++;
1451                 DPRINTF(EthernetDesc, "Calculated UDP checksum\n");
1452            } else {
1453                panic("Told to checksum, but don't know how\n");
1454            }
1455        }
1456    }
1457
1458    if (TxdOp::ide(desc)) {
1459        // Deal with the rx timer interrupts
1460        DPRINTF(EthernetDesc, "Descriptor had IDE set\n");
1461        if (igbe->regs.tidv.idv()) {
1462            DPRINTF(EthernetDesc, "setting tidv\n");
1463            igbe->reschedule(igbe->tidvEvent,
1464                curTick + igbe->regs.tidv.idv() * igbe->intClock(), true);
1465        }
1466
1467        if (igbe->regs.tadv.idv() && igbe->regs.tidv.idv()) {
1468            DPRINTF(EthernetDesc, "setting tadv\n");
1469            if (!igbe->tadvEvent.scheduled()) {
1470                igbe->schedule(igbe->tadvEvent,
1471                    curTick + igbe->regs.tadv.idv() * igbe->intClock());
1472            }
1473        }
1474    }
1475
1476
1477    if (!useTso ||  TxdOp::getLen(desc) == tsoDescBytesUsed) {
1478        DPRINTF(EthernetDesc, "Descriptor Done\n");
1479        igbe->anDq("TXS", annUnusedCacheQ);
1480        unusedCache.pop_front();
1481        igbe->anQ("TXS", annUsedCacheQ);
1482        usedCache.push_back(desc);
1483        tsoDescBytesUsed = 0;
1484    }
1485
1486    if (useTso && tsoUsedLen == tsoTotalLen)
1487        useTso = false;
1488
1489
1490    DPRINTF(EthernetDesc, "------Packet of %d bytes ready for transmission-------\n",
1491            pktPtr->length);
1492    pktDone = true;
1493    pktWaiting = false;
1494    pktPtr = NULL;
1495    tsoPktHasHeader = false;
1496
1497    if (igbe->regs.txdctl.wthresh() == 0) {
1498        igbe->anBegin("TXS", "Desc Writeback");
1499        DPRINTF(EthernetDesc, "WTHRESH == 0, writing back descriptor\n");
1500        writeback(0);
1501    } else if (igbe->regs.txdctl.gran() && igbe->regs.txdctl.wthresh() >=
1502            descInBlock(usedCache.size())) {
1503        DPRINTF(EthernetDesc, "used > WTHRESH, writing back descriptor\n");
1504        igbe->anBegin("TXS", "Desc Writeback");
1505        writeback((igbe->cacheBlockSize()-1)>>4);
1506    } else if (igbe->regs.txdctl.wthresh() >= usedCache.size()) {
1507        DPRINTF(EthernetDesc, "used > WTHRESH, writing back descriptor\n");
1508        igbe->anBegin("TXS", "Desc Writeback");
1509        writeback((igbe->cacheBlockSize()-1)>>4);
1510    }
1511
1512    enableSm();
1513    igbe->checkDrain();
1514}
1515
1516void
1517IGbE::TxDescCache::actionAfterWb()
1518{
1519    DPRINTF(EthernetDesc, "actionAfterWb() completionEnabled: %d\n",
1520            completionEnabled);
1521    igbe->postInterrupt(iGbReg::IT_TXDW);
1522    if (completionEnabled) {
1523        descEnd = igbe->regs.tdh();
1524        DPRINTF(EthernetDesc, "Completion writing back value: %d to addr: %#x\n", descEnd,
1525                completionAddress);
1526        igbe->dmaWrite(igbe->platform->pciToDma(mbits(completionAddress, 63, 2)),
1527                    sizeof(descEnd), &nullEvent, (uint8_t*)&descEnd, 0);
1528    }
1529}
1530
1531void
1532IGbE::TxDescCache::serialize(std::ostream &os)
1533{
1534    DescCache<TxDesc>::serialize(os);
1535    SERIALIZE_SCALAR(pktDone);
1536    SERIALIZE_SCALAR(isTcp);
1537    SERIALIZE_SCALAR(pktWaiting);
1538    SERIALIZE_SCALAR(pktMultiDesc);
1539
1540    SERIALIZE_SCALAR(useTso);
1541    SERIALIZE_SCALAR(tsoHeaderLen);
1542    SERIALIZE_SCALAR(tsoMss);
1543    SERIALIZE_SCALAR(tsoTotalLen);
1544    SERIALIZE_SCALAR(tsoUsedLen);
1545    SERIALIZE_SCALAR(tsoPrevSeq);;
1546    SERIALIZE_SCALAR(tsoPktPayloadBytes);
1547    SERIALIZE_SCALAR(tsoLoadedHeader);
1548    SERIALIZE_SCALAR(tsoPktHasHeader);
1549    SERIALIZE_ARRAY(tsoHeader, 256);
1550    SERIALIZE_SCALAR(tsoDescBytesUsed);
1551    SERIALIZE_SCALAR(tsoCopyBytes);
1552    SERIALIZE_SCALAR(tsoPkts);
1553
1554    SERIALIZE_SCALAR(completionAddress);
1555    SERIALIZE_SCALAR(completionEnabled);
1556    SERIALIZE_SCALAR(descEnd);
1557}
1558
1559void
1560IGbE::TxDescCache::unserialize(Checkpoint *cp, const std::string &section)
1561{
1562    DescCache<TxDesc>::unserialize(cp, section);
1563    UNSERIALIZE_SCALAR(pktDone);
1564    UNSERIALIZE_SCALAR(isTcp);
1565    UNSERIALIZE_SCALAR(pktWaiting);
1566    UNSERIALIZE_SCALAR(pktMultiDesc);
1567
1568    UNSERIALIZE_SCALAR(useTso);
1569    UNSERIALIZE_SCALAR(tsoHeaderLen);
1570    UNSERIALIZE_SCALAR(tsoMss);
1571    UNSERIALIZE_SCALAR(tsoTotalLen);
1572    UNSERIALIZE_SCALAR(tsoUsedLen);
1573    UNSERIALIZE_SCALAR(tsoPrevSeq);;
1574    UNSERIALIZE_SCALAR(tsoPktPayloadBytes);
1575    UNSERIALIZE_SCALAR(tsoLoadedHeader);
1576    UNSERIALIZE_SCALAR(tsoPktHasHeader);
1577    UNSERIALIZE_ARRAY(tsoHeader, 256);
1578    UNSERIALIZE_SCALAR(tsoDescBytesUsed);
1579    UNSERIALIZE_SCALAR(tsoCopyBytes);
1580    UNSERIALIZE_SCALAR(tsoPkts);
1581
1582    UNSERIALIZE_SCALAR(completionAddress);
1583    UNSERIALIZE_SCALAR(completionEnabled);
1584    UNSERIALIZE_SCALAR(descEnd);
1585}
1586
1587bool
1588IGbE::TxDescCache::packetAvailable()
1589{
1590    if (pktDone) {
1591        pktDone = false;
1592        return true;
1593    }
1594    return false;
1595}
1596
1597void
1598IGbE::TxDescCache::enableSm()
1599{
1600    if (!igbe->drainEvent) {
1601        igbe->txTick = true;
1602        igbe->restartClock();
1603    }
1604}
1605
1606bool
1607IGbE::TxDescCache::hasOutstandingEvents()
1608{
1609    return pktEvent.scheduled() || wbEvent.scheduled() ||
1610        fetchEvent.scheduled();
1611}
1612
1613
1614///////////////////////////////////// IGbE /////////////////////////////////
1615
1616void
1617IGbE::restartClock()
1618{
1619    if (!tickEvent.scheduled() && (rxTick || txTick || txFifoTick) &&
1620        getState() == SimObject::Running)
1621        schedule(tickEvent, (curTick / ticks(1)) * ticks(1) + ticks(1));
1622}
1623
1624unsigned int
1625IGbE::drain(Event *de)
1626{
1627    unsigned int count;
1628    count = pioPort->drain(de) + dmaPort->drain(de);
1629    if (rxDescCache.hasOutstandingEvents() ||
1630            txDescCache.hasOutstandingEvents()) {
1631        count++;
1632        drainEvent = de;
1633    }
1634
1635    txFifoTick = false;
1636    txTick = false;
1637    rxTick = false;
1638
1639    if (tickEvent.scheduled())
1640        deschedule(tickEvent);
1641
1642    if (count)
1643        changeState(Draining);
1644    else
1645        changeState(Drained);
1646
1647    DPRINTF(EthernetSM, "got drain() returning %d", count);
1648    return count;
1649}
1650
1651void
1652IGbE::resume()
1653{
1654    SimObject::resume();
1655
1656    txFifoTick = true;
1657    txTick = true;
1658    rxTick = true;
1659
1660    restartClock();
1661    DPRINTF(EthernetSM, "resuming from drain");
1662}
1663
1664void
1665IGbE::checkDrain()
1666{
1667    if (!drainEvent)
1668        return;
1669
1670    DPRINTF(EthernetSM, "checkDrain() in drain\n");
1671    txFifoTick = false;
1672    txTick = false;
1673    rxTick = false;
1674    if (!rxDescCache.hasOutstandingEvents() &&
1675            !txDescCache.hasOutstandingEvents()) {
1676        drainEvent->process();
1677        drainEvent = NULL;
1678    }
1679}
1680
1681void
1682IGbE::txStateMachine()
1683{
1684    if (!regs.tctl.en()) {
1685        txTick = false;
1686        DPRINTF(EthernetSM, "TXS: TX disabled, stopping ticking\n");
1687        return;
1688    }
1689
1690    // If we have a packet available and it's length is not 0 (meaning it's not
1691    // a multidescriptor packet) put it in the fifo, otherwise an the next
1692    // iteration we'll get the rest of the data
1693    if (txPacket && txDescCache.packetAvailable()
1694                 && !txDescCache.packetMultiDesc() && txPacket->length) {
1695        bool success;
1696
1697        anQ("TXS", "TX FIFO Q");
1698        DPRINTF(EthernetSM, "TXS: packet placed in TX FIFO\n");
1699        success = txFifo.push(txPacket);
1700        txFifoTick = true && !drainEvent;
1701        assert(success);
1702        txPacket = NULL;
1703        anBegin("TXS", "Desc Writeback");
1704        txDescCache.writeback((cacheBlockSize()-1)>>4);
1705        return;
1706    }
1707
1708    // Only support descriptor granularity
1709    if (regs.txdctl.lwthresh() && txDescCache.descLeft() < (regs.txdctl.lwthresh() * 8)) {
1710        DPRINTF(EthernetSM, "TXS: LWTHRESH caused posting of TXDLOW\n");
1711        postInterrupt(IT_TXDLOW);
1712    }
1713
1714    if (!txPacket) {
1715        txPacket = new EthPacketData(16384);
1716    }
1717
1718    if (!txDescCache.packetWaiting()) {
1719        if (txDescCache.descLeft() == 0) {
1720            postInterrupt(IT_TXQE);
1721            anBegin("TXS", "Desc Writeback");
1722            txDescCache.writeback(0);
1723            anBegin("TXS", "Desc Fetch");
1724            anWe("TXS", txDescCache.annUnusedCacheQ);
1725            txDescCache.fetchDescriptors();
1726            DPRINTF(EthernetSM, "TXS: No descriptors left in ring, forcing "
1727                    "writeback stopping ticking and posting TXQE\n");
1728            txTick = false;
1729            return;
1730        }
1731
1732
1733        if (!(txDescCache.descUnused())) {
1734            anBegin("TXS", "Desc Fetch");
1735            txDescCache.fetchDescriptors();
1736            anWe("TXS", txDescCache.annUnusedCacheQ);
1737            DPRINTF(EthernetSM, "TXS: No descriptors available in cache, fetching and stopping ticking\n");
1738            txTick = false;
1739            return;
1740        }
1741        anPq("TXS", txDescCache.annUnusedCacheQ);
1742
1743
1744        txDescCache.processContextDesc();
1745        if (txDescCache.packetWaiting()) {
1746            DPRINTF(EthernetSM, "TXS: Fetching TSO header, stopping ticking\n");
1747            txTick = false;
1748            return;
1749        }
1750
1751        int size;
1752        size = txDescCache.getPacketSize(txPacket);
1753        if (size > 0 && txFifo.avail() > size) {
1754            anRq("TXS", "TX FIFO Q");
1755            anBegin("TXS", "DMA Packet");
1756            DPRINTF(EthernetSM, "TXS: Reserving %d bytes in FIFO and begining "
1757                    "DMA of next packet\n", size);
1758            txFifo.reserve(size);
1759            txDescCache.getPacketData(txPacket);
1760        } else if (size <= 0) {
1761            DPRINTF(EthernetSM, "TXS: getPacketSize returned: %d\n", size);
1762            DPRINTF(EthernetSM, "TXS: No packets to get, writing back used descriptors\n");
1763            anBegin("TXS", "Desc Writeback");
1764            txDescCache.writeback(0);
1765        } else {
1766            anWf("TXS", "TX FIFO Q");
1767            DPRINTF(EthernetSM, "TXS: FIFO full, stopping ticking until space "
1768                    "available in FIFO\n");
1769            txTick = false;
1770        }
1771
1772
1773        return;
1774    }
1775    DPRINTF(EthernetSM, "TXS: Nothing to do, stopping ticking\n");
1776    txTick = false;
1777}
1778
1779bool
1780IGbE::ethRxPkt(EthPacketPtr pkt)
1781{
1782    rxBytes += pkt->length;
1783    rxPackets++;
1784
1785    DPRINTF(Ethernet, "RxFIFO: Receiving pcakte from wire\n");
1786    anBegin("RXQ", "Wire Recv");
1787
1788
1789    if (!regs.rctl.en()) {
1790        DPRINTF(Ethernet, "RxFIFO: RX not enabled, dropping\n");
1791        anBegin("RXQ", "FIFO Drop", CPA::FL_BAD);
1792        return true;
1793    }
1794
1795    // restart the state machines if they are stopped
1796    rxTick = true && !drainEvent;
1797    if ((rxTick || txTick) && !tickEvent.scheduled()) {
1798        DPRINTF(EthernetSM, "RXS: received packet into fifo, starting ticking\n");
1799        restartClock();
1800    }
1801
1802    if (!rxFifo.push(pkt)) {
1803        DPRINTF(Ethernet, "RxFIFO: Packet won't fit in fifo... dropped\n");
1804        postInterrupt(IT_RXO, true);
1805        anBegin("RXQ", "FIFO Drop", CPA::FL_BAD);
1806        return false;
1807    }
1808
1809    if (CPA::available() && cpa->enabled()) {
1810        assert(sys->numSystemsRunning <= 2);
1811        System *other_sys;
1812        if (sys->systemList[0] == sys)
1813            other_sys = sys->systemList[1];
1814        else
1815            other_sys = sys->systemList[0];
1816
1817        cpa->hwDq(CPA::FL_NONE, sys, macAddr, "RXQ", "WireQ", 0, other_sys);
1818        anQ("RXQ", "RX FIFO Q");
1819        cpa->hwWe(CPA::FL_NONE, sys, macAddr, "RXQ", "WireQ", 0, other_sys);
1820    }
1821
1822    return true;
1823}
1824
1825
1826void
1827IGbE::rxStateMachine()
1828{
1829    if (!regs.rctl.en()) {
1830        rxTick = false;
1831        DPRINTF(EthernetSM, "RXS: RX disabled, stopping ticking\n");
1832        return;
1833    }
1834
1835    // If the packet is done check for interrupts/descriptors/etc
1836    if (rxDescCache.packetDone()) {
1837        rxDmaPacket = false;
1838        DPRINTF(EthernetSM, "RXS: Packet completed DMA to memory\n");
1839        int descLeft = rxDescCache.descLeft();
1840        DPRINTF(EthernetSM, "RXS: descLeft: %d rdmts: %d rdlen: %d\n",
1841                descLeft, regs.rctl.rdmts(), regs.rdlen());
1842        switch (regs.rctl.rdmts()) {
1843            case 2: if (descLeft > .125 * regs.rdlen()) break;
1844            case 1: if (descLeft > .250 * regs.rdlen()) break;
1845            case 0: if (descLeft > .500 * regs.rdlen())  break;
1846                DPRINTF(Ethernet, "RXS: Interrupting (RXDMT) because of descriptors left\n");
1847                postInterrupt(IT_RXDMT);
1848                break;
1849        }
1850
1851        if (rxFifo.empty())
1852            rxDescCache.writeback(0);
1853
1854        if (descLeft == 0) {
1855            anBegin("RXS", "Writeback Descriptors");
1856            rxDescCache.writeback(0);
1857            DPRINTF(EthernetSM, "RXS: No descriptors left in ring, forcing"
1858                    " writeback and stopping ticking\n");
1859            rxTick = false;
1860        }
1861
1862        // only support descriptor granulaties
1863        assert(regs.rxdctl.gran());
1864
1865        if (regs.rxdctl.wthresh() >= rxDescCache.descUsed()) {
1866            DPRINTF(EthernetSM, "RXS: Writing back because WTHRESH >= descUsed\n");
1867            anBegin("RXS", "Writeback Descriptors");
1868            if (regs.rxdctl.wthresh() < (cacheBlockSize()>>4))
1869                rxDescCache.writeback(regs.rxdctl.wthresh()-1);
1870            else
1871                rxDescCache.writeback((cacheBlockSize()-1)>>4);
1872        }
1873
1874        if ((rxDescCache.descUnused() < regs.rxdctl.pthresh()) &&
1875             ((rxDescCache.descLeft() - rxDescCache.descUnused()) > regs.rxdctl.hthresh())) {
1876            DPRINTF(EthernetSM, "RXS: Fetching descriptors because descUnused < PTHRESH\n");
1877            anBegin("RXS", "Fetch Descriptors");
1878            rxDescCache.fetchDescriptors();
1879        }
1880
1881        if (rxDescCache.descUnused() == 0) {
1882            anBegin("RXS", "Fetch Descriptors");
1883            rxDescCache.fetchDescriptors();
1884            anWe("RXS", rxDescCache.annUnusedCacheQ);
1885            DPRINTF(EthernetSM, "RXS: No descriptors available in cache, "
1886                    "fetching descriptors and stopping ticking\n");
1887            rxTick = false;
1888        }
1889        return;
1890    }
1891
1892    if (rxDmaPacket) {
1893        DPRINTF(EthernetSM, "RXS: stopping ticking until packet DMA completes\n");
1894        rxTick = false;
1895        return;
1896    }
1897
1898    if (!rxDescCache.descUnused()) {
1899        anBegin("RXS", "Fetch Descriptors");
1900        rxDescCache.fetchDescriptors();
1901        anWe("RXS", rxDescCache.annUnusedCacheQ);
1902        DPRINTF(EthernetSM, "RXS: No descriptors available in cache, stopping ticking\n");
1903        rxTick = false;
1904        DPRINTF(EthernetSM, "RXS: No descriptors available, fetching\n");
1905        return;
1906    }
1907    anPq("RXS", rxDescCache.annUnusedCacheQ);
1908
1909    if (rxFifo.empty()) {
1910        anWe("RXS", "RX FIFO Q");
1911        DPRINTF(EthernetSM, "RXS: RxFIFO empty, stopping ticking\n");
1912        rxTick = false;
1913        return;
1914    }
1915    anPq("RXS", "RX FIFO Q");
1916    anBegin("RXS", "Get Desc");
1917
1918    EthPacketPtr pkt;
1919    pkt = rxFifo.front();
1920
1921
1922    pktOffset = rxDescCache.writePacket(pkt, pktOffset);
1923    DPRINTF(EthernetSM, "RXS: Writing packet into memory\n");
1924    if (pktOffset == pkt->length) {
1925        anBegin( "RXS", "FIFO Dequeue");
1926        DPRINTF(EthernetSM, "RXS: Removing packet from FIFO\n");
1927        pktOffset = 0;
1928        anDq("RXS", "RX FIFO Q");
1929        rxFifo.pop();
1930    }
1931
1932    DPRINTF(EthernetSM, "RXS: stopping ticking until packet DMA completes\n");
1933    rxTick = false;
1934    rxDmaPacket = true;
1935    anBegin("RXS", "DMA Packet");
1936}
1937
1938void
1939IGbE::txWire()
1940{
1941    if (txFifo.empty()) {
1942        anWe("TXQ", "TX FIFO Q");
1943        txFifoTick = false;
1944        return;
1945    }
1946
1947
1948    anPq("TXQ", "TX FIFO Q");
1949    if (etherInt->sendPacket(txFifo.front())) {
1950        cpa->hwQ(CPA::FL_NONE, sys, macAddr, "TXQ", "WireQ", 0);
1951        if (DTRACE(EthernetSM)) {
1952            IpPtr ip(txFifo.front());
1953            if (ip)
1954                DPRINTF(EthernetSM, "Transmitting Ip packet with Id=%d\n",
1955                        ip->id());
1956            else
1957                DPRINTF(EthernetSM, "Transmitting Non-Ip packet\n");
1958        }
1959        anDq("TXQ", "TX FIFO Q");
1960        anBegin("TXQ", "Wire Send");
1961        DPRINTF(EthernetSM, "TxFIFO: Successful transmit, bytes available in fifo: %d\n",
1962                txFifo.avail());
1963
1964        txBytes += txFifo.front()->length;
1965        txPackets++;
1966        txFifoTick = false;
1967
1968        txFifo.pop();
1969    } else {
1970        // We'll get woken up when the packet ethTxDone() gets called
1971        txFifoTick = false;
1972    }
1973}
1974
1975void
1976IGbE::tick()
1977{
1978    DPRINTF(EthernetSM, "IGbE: -------------- Cycle --------------\n");
1979
1980    if (rxTick)
1981        rxStateMachine();
1982
1983    if (txTick)
1984        txStateMachine();
1985
1986    if (txFifoTick)
1987        txWire();
1988
1989
1990    if (rxTick || txTick || txFifoTick)
1991        schedule(tickEvent, curTick + ticks(1));
1992}
1993
1994void
1995IGbE::ethTxDone()
1996{
1997    anBegin("TXQ", "Send Done");
1998    // restart the tx state machines if they are stopped
1999    // fifo to send another packet
2000    // tx sm to put more data into the fifo
2001    txFifoTick = true && !drainEvent;
2002    if (txDescCache.descLeft() != 0 && !drainEvent)
2003        txTick = true;
2004
2005    restartClock();
2006    txWire();
2007    DPRINTF(EthernetSM, "TxFIFO: Transmission complete\n");
2008}
2009
2010void
2011IGbE::serialize(std::ostream &os)
2012{
2013    PciDev::serialize(os);
2014
2015    regs.serialize(os);
2016    SERIALIZE_SCALAR(eeOpBits);
2017    SERIALIZE_SCALAR(eeAddrBits);
2018    SERIALIZE_SCALAR(eeDataBits);
2019    SERIALIZE_SCALAR(eeOpcode);
2020    SERIALIZE_SCALAR(eeAddr);
2021    SERIALIZE_SCALAR(lastInterrupt);
2022    SERIALIZE_ARRAY(flash,iGbReg::EEPROM_SIZE);
2023
2024    rxFifo.serialize("rxfifo", os);
2025    txFifo.serialize("txfifo", os);
2026
2027    bool txPktExists = txPacket;
2028    SERIALIZE_SCALAR(txPktExists);
2029    if (txPktExists)
2030        txPacket->serialize("txpacket", os);
2031
2032    Tick rdtr_time = 0, radv_time = 0, tidv_time = 0, tadv_time = 0,
2033         inter_time = 0;
2034
2035    if (rdtrEvent.scheduled())
2036       rdtr_time = rdtrEvent.when();
2037    SERIALIZE_SCALAR(rdtr_time);
2038
2039    if (radvEvent.scheduled())
2040       radv_time = radvEvent.when();
2041    SERIALIZE_SCALAR(radv_time);
2042
2043    if (tidvEvent.scheduled())
2044       tidv_time = tidvEvent.when();
2045    SERIALIZE_SCALAR(tidv_time);
2046
2047    if (tadvEvent.scheduled())
2048       tadv_time = tadvEvent.when();
2049    SERIALIZE_SCALAR(tadv_time);
2050
2051    if (interEvent.scheduled())
2052       inter_time = interEvent.when();
2053    SERIALIZE_SCALAR(inter_time);
2054
2055    SERIALIZE_SCALAR(pktOffset);
2056
2057    nameOut(os, csprintf("%s.TxDescCache", name()));
2058    txDescCache.serialize(os);
2059
2060    nameOut(os, csprintf("%s.RxDescCache", name()));
2061    rxDescCache.serialize(os);
2062}
2063
2064void
2065IGbE::unserialize(Checkpoint *cp, const std::string &section)
2066{
2067    PciDev::unserialize(cp, section);
2068
2069    regs.unserialize(cp, section);
2070    UNSERIALIZE_SCALAR(eeOpBits);
2071    UNSERIALIZE_SCALAR(eeAddrBits);
2072    UNSERIALIZE_SCALAR(eeDataBits);
2073    UNSERIALIZE_SCALAR(eeOpcode);
2074    UNSERIALIZE_SCALAR(eeAddr);
2075    UNSERIALIZE_SCALAR(lastInterrupt);
2076    UNSERIALIZE_ARRAY(flash,iGbReg::EEPROM_SIZE);
2077
2078    rxFifo.unserialize("rxfifo", cp, section);
2079    txFifo.unserialize("txfifo", cp, section);
2080
2081    bool txPktExists;
2082    UNSERIALIZE_SCALAR(txPktExists);
2083    if (txPktExists) {
2084        txPacket = new EthPacketData(16384);
2085        txPacket->unserialize("txpacket", cp, section);
2086    }
2087
2088    rxTick = true;
2089    txTick = true;
2090    txFifoTick = true;
2091
2092    Tick rdtr_time, radv_time, tidv_time, tadv_time, inter_time;
2093    UNSERIALIZE_SCALAR(rdtr_time);
2094    UNSERIALIZE_SCALAR(radv_time);
2095    UNSERIALIZE_SCALAR(tidv_time);
2096    UNSERIALIZE_SCALAR(tadv_time);
2097    UNSERIALIZE_SCALAR(inter_time);
2098
2099    if (rdtr_time)
2100        schedule(rdtrEvent, rdtr_time);
2101
2102    if (radv_time)
2103        schedule(radvEvent, radv_time);
2104
2105    if (tidv_time)
2106        schedule(tidvEvent, tidv_time);
2107
2108    if (tadv_time)
2109        schedule(tadvEvent, tadv_time);
2110
2111    if (inter_time)
2112        schedule(interEvent, inter_time);
2113
2114    UNSERIALIZE_SCALAR(pktOffset);
2115
2116    txDescCache.unserialize(cp, csprintf("%s.TxDescCache", section));
2117
2118    rxDescCache.unserialize(cp, csprintf("%s.RxDescCache", section));
2119}
2120
2121IGbE *
2122IGbEParams::create()
2123{
2124    return new IGbE(this);
2125}
2126