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