Major changes to how SimObjects are created and initialized. Almost all
[gem5.git] / src / dev / sinic.cc
1 /*
2 * Copyright (c) 2004-2005 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: Nathan Binkert
29 */
30
31 #include <deque>
32 #include <limits>
33 #include <string>
34
35 #include "arch/vtophys.hh"
36 #include "base/inet.hh"
37 #include "cpu/thread_context.hh"
38 #include "cpu/intr_control.hh"
39 #include "dev/etherlink.hh"
40 #include "dev/sinic.hh"
41 #include "mem/packet.hh"
42 #include "mem/packet_access.hh"
43 #include "sim/debug.hh"
44 #include "sim/eventq.hh"
45 #include "sim/host.hh"
46 #include "sim/stats.hh"
47
48 using namespace Net;
49 using namespace TheISA;
50
51 namespace Sinic {
52
53 const char *RxStateStrings[] =
54 {
55 "rxIdle",
56 "rxFifoBlock",
57 "rxBeginCopy",
58 "rxCopy",
59 "rxCopyDone"
60 };
61
62 const char *TxStateStrings[] =
63 {
64 "txIdle",
65 "txFifoBlock",
66 "txBeginCopy",
67 "txCopy",
68 "txCopyDone"
69 };
70
71
72 ///////////////////////////////////////////////////////////////////////
73 //
74 // Sinic PCI Device
75 //
76 Base::Base(Params *p)
77 : PciDev(p), rxEnable(false), txEnable(false), clock(p->clock),
78 intrDelay(p->intr_delay), intrTick(0), cpuIntrEnable(false),
79 cpuPendingIntr(false), intrEvent(0), interface(NULL)
80 {
81 }
82
83 Device::Device(Params *p)
84 : Base(p), rxUnique(0), txUnique(0),
85 virtualRegs(p->virtual_count < 1 ? 1 : p->virtual_count),
86 rxFifo(p->rx_fifo_size), txFifo(p->tx_fifo_size),
87 rxKickTick(0), txKickTick(0),
88 txEvent(this), rxDmaEvent(this), txDmaEvent(this),
89 dmaReadDelay(p->dma_read_delay), dmaReadFactor(p->dma_read_factor),
90 dmaWriteDelay(p->dma_write_delay), dmaWriteFactor(p->dma_write_factor)
91 {
92 reset();
93
94 }
95
96 Device::~Device()
97 {}
98
99 void
100 Device::regStats()
101 {
102 rxBytes
103 .name(name() + ".rxBytes")
104 .desc("Bytes Received")
105 .prereq(rxBytes)
106 ;
107
108 rxBandwidth
109 .name(name() + ".rxBandwidth")
110 .desc("Receive Bandwidth (bits/s)")
111 .precision(0)
112 .prereq(rxBytes)
113 ;
114
115 rxPackets
116 .name(name() + ".rxPackets")
117 .desc("Number of Packets Received")
118 .prereq(rxBytes)
119 ;
120
121 rxPacketRate
122 .name(name() + ".rxPPS")
123 .desc("Packet Reception Rate (packets/s)")
124 .precision(0)
125 .prereq(rxBytes)
126 ;
127
128 rxIpPackets
129 .name(name() + ".rxIpPackets")
130 .desc("Number of IP Packets Received")
131 .prereq(rxBytes)
132 ;
133
134 rxTcpPackets
135 .name(name() + ".rxTcpPackets")
136 .desc("Number of Packets Received")
137 .prereq(rxBytes)
138 ;
139
140 rxUdpPackets
141 .name(name() + ".rxUdpPackets")
142 .desc("Number of UDP Packets Received")
143 .prereq(rxBytes)
144 ;
145
146 rxIpChecksums
147 .name(name() + ".rxIpChecksums")
148 .desc("Number of rx IP Checksums done by device")
149 .precision(0)
150 .prereq(rxBytes)
151 ;
152
153 rxTcpChecksums
154 .name(name() + ".rxTcpChecksums")
155 .desc("Number of rx TCP Checksums done by device")
156 .precision(0)
157 .prereq(rxBytes)
158 ;
159
160 rxUdpChecksums
161 .name(name() + ".rxUdpChecksums")
162 .desc("Number of rx UDP Checksums done by device")
163 .precision(0)
164 .prereq(rxBytes)
165 ;
166
167 totBandwidth
168 .name(name() + ".totBandwidth")
169 .desc("Total Bandwidth (bits/s)")
170 .precision(0)
171 .prereq(totBytes)
172 ;
173
174 totPackets
175 .name(name() + ".totPackets")
176 .desc("Total Packets")
177 .precision(0)
178 .prereq(totBytes)
179 ;
180
181 totBytes
182 .name(name() + ".totBytes")
183 .desc("Total Bytes")
184 .precision(0)
185 .prereq(totBytes)
186 ;
187
188 totPacketRate
189 .name(name() + ".totPPS")
190 .desc("Total Tranmission Rate (packets/s)")
191 .precision(0)
192 .prereq(totBytes)
193 ;
194
195 txBytes
196 .name(name() + ".txBytes")
197 .desc("Bytes Transmitted")
198 .prereq(txBytes)
199 ;
200
201 txBandwidth
202 .name(name() + ".txBandwidth")
203 .desc("Transmit Bandwidth (bits/s)")
204 .precision(0)
205 .prereq(txBytes)
206 ;
207
208 txPackets
209 .name(name() + ".txPackets")
210 .desc("Number of Packets Transmitted")
211 .prereq(txBytes)
212 ;
213
214 txPacketRate
215 .name(name() + ".txPPS")
216 .desc("Packet Tranmission Rate (packets/s)")
217 .precision(0)
218 .prereq(txBytes)
219 ;
220
221 txIpPackets
222 .name(name() + ".txIpPackets")
223 .desc("Number of IP Packets Transmitted")
224 .prereq(txBytes)
225 ;
226
227 txTcpPackets
228 .name(name() + ".txTcpPackets")
229 .desc("Number of TCP Packets Transmitted")
230 .prereq(txBytes)
231 ;
232
233 txUdpPackets
234 .name(name() + ".txUdpPackets")
235 .desc("Number of Packets Transmitted")
236 .prereq(txBytes)
237 ;
238
239 txIpChecksums
240 .name(name() + ".txIpChecksums")
241 .desc("Number of tx IP Checksums done by device")
242 .precision(0)
243 .prereq(txBytes)
244 ;
245
246 txTcpChecksums
247 .name(name() + ".txTcpChecksums")
248 .desc("Number of tx TCP Checksums done by device")
249 .precision(0)
250 .prereq(txBytes)
251 ;
252
253 txUdpChecksums
254 .name(name() + ".txUdpChecksums")
255 .desc("Number of tx UDP Checksums done by device")
256 .precision(0)
257 .prereq(txBytes)
258 ;
259
260 txBandwidth = txBytes * Stats::constant(8) / simSeconds;
261 rxBandwidth = rxBytes * Stats::constant(8) / simSeconds;
262 totBandwidth = txBandwidth + rxBandwidth;
263 totBytes = txBytes + rxBytes;
264 totPackets = txPackets + rxPackets;
265 txPacketRate = txPackets / simSeconds;
266 rxPacketRate = rxPackets / simSeconds;
267 }
268
269 void
270 Device::prepareIO(int cpu, int index)
271 {
272 int size = virtualRegs.size();
273 if (index > size)
274 panic("Trying to access a vnic that doesn't exist %d > %d\n",
275 index, size);
276 }
277
278 void
279 Device::prepareRead(int cpu, int index)
280 {
281 using namespace Regs;
282 prepareIO(cpu, index);
283
284 VirtualReg &vnic = virtualRegs[index];
285
286 // update rx registers
287 uint64_t rxdone = vnic.RxDone;
288 rxdone = set_RxDone_Packets(rxdone, rxFifo.countPacketsAfter(rxFifoPtr));
289 rxdone = set_RxDone_Empty(rxdone, rxFifo.empty());
290 rxdone = set_RxDone_High(rxdone, rxFifo.size() > regs.RxFifoMark);
291 rxdone = set_RxDone_NotHigh(rxdone, rxLow);
292 regs.RxData = vnic.RxData;
293 regs.RxDone = rxdone;
294 regs.RxWait = rxdone;
295
296 // update tx regsiters
297 uint64_t txdone = vnic.TxDone;
298 txdone = set_TxDone_Packets(txdone, txFifo.packets());
299 txdone = set_TxDone_Full(txdone, txFifo.avail() < regs.TxMaxCopy);
300 txdone = set_TxDone_Low(txdone, txFifo.size() < regs.TxFifoMark);
301 regs.TxData = vnic.TxData;
302 regs.TxDone = txdone;
303 regs.TxWait = txdone;
304 }
305
306 void
307 Device::prepareWrite(int cpu, int index)
308 {
309 prepareIO(cpu, index);
310 }
311
312 /**
313 * I/O read of device register
314 */
315 Tick
316 Device::read(PacketPtr pkt)
317 {
318 assert(config.command & PCI_CMD_MSE);
319 assert(pkt->getAddr() >= BARAddrs[0] && pkt->getSize() < BARSize[0]);
320
321 int cpu = pkt->req->getCpuNum();
322 Addr daddr = pkt->getAddr() - BARAddrs[0];
323 Addr index = daddr >> Regs::VirtualShift;
324 Addr raddr = daddr & Regs::VirtualMask;
325
326 pkt->allocate();
327
328 if (!regValid(raddr))
329 panic("invalid register: cpu=%d vnic=%d da=%#x pa=%#x size=%d",
330 cpu, index, daddr, pkt->getAddr(), pkt->getSize());
331
332 const Regs::Info &info = regInfo(raddr);
333 if (!info.read)
334 panic("read %s (write only): "
335 "cpu=%d vnic=%d da=%#x pa=%#x size=%d",
336 info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize());
337
338 panic("read %s (invalid size): "
339 "cpu=%d vnic=%d da=%#x pa=%#x size=%d",
340 info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize());
341
342 prepareRead(cpu, index);
343
344 uint64_t value = 0;
345 if (pkt->getSize() == 4) {
346 uint32_t reg = regData32(raddr);
347 pkt->set(reg);
348 value = reg;
349 }
350
351 if (pkt->getSize() == 8) {
352 uint64_t reg = regData64(raddr);
353 pkt->set(reg);
354 value = reg;
355 }
356
357 DPRINTF(EthernetPIO,
358 "read %s: cpu=%d vnic=%d da=%#x pa=%#x size=%d val=%#x\n",
359 info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize(), value);
360
361 // reading the interrupt status register has the side effect of
362 // clearing it
363 if (raddr == Regs::IntrStatus)
364 devIntrClear();
365
366 return pioDelay;
367 }
368
369 /**
370 * IPR read of device register
371
372 Fault
373 Device::iprRead(Addr daddr, int cpu, uint64_t &result)
374 {
375 if (!regValid(daddr))
376 panic("invalid address: da=%#x", daddr);
377
378 const Regs::Info &info = regInfo(daddr);
379 if (!info.read)
380 panic("reading %s (write only): cpu=%d da=%#x", info.name, cpu, daddr);
381
382 DPRINTF(EthernetPIO, "IPR read %s: cpu=%d da=%#x\n",
383 info.name, cpu, daddr);
384
385 prepareRead(cpu, 0);
386
387 if (info.size == 4)
388 result = regData32(daddr);
389
390 if (info.size == 8)
391 result = regData64(daddr);
392
393 DPRINTF(EthernetPIO, "IPR read %s: cpu=%s da=%#x val=%#x\n",
394 info.name, cpu, result);
395
396 return NoFault;
397 }
398 */
399 /**
400 * I/O write of device register
401 */
402 Tick
403 Device::write(PacketPtr pkt)
404 {
405 assert(config.command & PCI_CMD_MSE);
406 assert(pkt->getAddr() >= BARAddrs[0] && pkt->getSize() < BARSize[0]);
407
408 int cpu = pkt->req->getCpuNum();
409 Addr daddr = pkt->getAddr() - BARAddrs[0];
410 Addr index = daddr >> Regs::VirtualShift;
411 Addr raddr = daddr & Regs::VirtualMask;
412
413 if (!regValid(raddr))
414 panic("invalid register: cpu=%d, da=%#x pa=%#x size=%d",
415 cpu, daddr, pkt->getAddr(), pkt->getSize());
416
417 const Regs::Info &info = regInfo(raddr);
418 if (!info.write)
419 panic("write %s (read only): "
420 "cpu=%d vnic=%d da=%#x pa=%#x size=%d",
421 info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize());
422
423 if (pkt->getSize() != info.size)
424 panic("write %s (invalid size): "
425 "cpu=%d vnic=%d da=%#x pa=%#x size=%d",
426 info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize());
427
428 VirtualReg &vnic = virtualRegs[index];
429
430 DPRINTF(EthernetPIO,
431 "write %s vnic %d: cpu=%d val=%#x da=%#x pa=%#x size=%d\n",
432 info.name, index, cpu, info.size == 4 ? pkt->get<uint32_t>() :
433 pkt->get<uint64_t>(), daddr, pkt->getAddr(), pkt->getSize());
434
435 prepareWrite(cpu, index);
436
437 switch (raddr) {
438 case Regs::Config:
439 changeConfig(pkt->get<uint32_t>());
440 break;
441
442 case Regs::Command:
443 command(pkt->get<uint32_t>());
444 break;
445
446 case Regs::IntrStatus:
447 devIntrClear(regs.IntrStatus & pkt->get<uint32_t>());
448 break;
449
450 case Regs::IntrMask:
451 devIntrChangeMask(pkt->get<uint32_t>());
452 break;
453
454 case Regs::RxData:
455 if (Regs::get_RxDone_Busy(vnic.RxDone))
456 panic("receive machine busy with another request! rxState=%s",
457 RxStateStrings[rxState]);
458
459 vnic.rxUnique = rxUnique++;
460 vnic.RxDone = Regs::RxDone_Busy;
461 vnic.RxData = pkt->get<uint64_t>();
462
463 if (Regs::get_RxData_Vaddr(pkt->get<uint64_t>())) {
464 panic("vtophys not implemented in newmem");
465 /* Addr vaddr = Regs::get_RxData_Addr(reg64);
466 Addr paddr = vtophys(req->xc, vaddr);
467 DPRINTF(EthernetPIO, "write RxData vnic %d (rxunique %d): "
468 "vaddr=%#x, paddr=%#x\n",
469 index, vnic.rxUnique, vaddr, paddr);
470
471 vnic.RxData = Regs::set_RxData_Addr(vnic.RxData, paddr);*/
472 } else {
473 DPRINTF(EthernetPIO, "write RxData vnic %d (rxunique %d)\n",
474 index, vnic.rxUnique);
475 }
476
477 if (vnic.rxPacket == rxFifo.end()) {
478 DPRINTF(EthernetPIO, "request new packet...appending to rxList\n");
479 rxList.push_back(index);
480 } else {
481 DPRINTF(EthernetPIO, "packet exists...appending to rxBusy\n");
482 rxBusy.push_back(index);
483 }
484
485 if (rxEnable && (rxState == rxIdle || rxState == rxFifoBlock)) {
486 rxState = rxFifoBlock;
487 rxKick();
488 }
489 break;
490
491 case Regs::TxData:
492 if (Regs::get_TxDone_Busy(vnic.TxDone))
493 panic("transmit machine busy with another request! txState=%s",
494 TxStateStrings[txState]);
495
496 vnic.txUnique = txUnique++;
497 vnic.TxDone = Regs::TxDone_Busy;
498
499 if (Regs::get_TxData_Vaddr(pkt->get<uint64_t>())) {
500 panic("vtophys won't work here in newmem.\n");
501 /*Addr vaddr = Regs::get_TxData_Addr(reg64);
502 Addr paddr = vtophys(req->xc, vaddr);
503 DPRINTF(EthernetPIO, "write TxData vnic %d (rxunique %d): "
504 "vaddr=%#x, paddr=%#x\n",
505 index, vnic.txUnique, vaddr, paddr);
506
507 vnic.TxData = Regs::set_TxData_Addr(vnic.TxData, paddr);*/
508 } else {
509 DPRINTF(EthernetPIO, "write TxData vnic %d (rxunique %d)\n",
510 index, vnic.txUnique);
511 }
512
513 if (txList.empty() || txList.front() != index)
514 txList.push_back(index);
515 if (txEnable && txState == txIdle && txList.front() == index) {
516 txState = txFifoBlock;
517 txKick();
518 }
519 break;
520 }
521
522 return pioDelay;
523 }
524
525 void
526 Device::devIntrPost(uint32_t interrupts)
527 {
528 if ((interrupts & Regs::Intr_Res))
529 panic("Cannot set a reserved interrupt");
530
531 regs.IntrStatus |= interrupts;
532
533 DPRINTF(EthernetIntr,
534 "interrupt written to intStatus: intr=%#x status=%#x mask=%#x\n",
535 interrupts, regs.IntrStatus, regs.IntrMask);
536
537 interrupts = regs.IntrStatus & regs.IntrMask;
538
539 // Intr_RxHigh is special, we only signal it if we've emptied the fifo
540 // and then filled it above the high watermark
541 if (rxEmpty)
542 rxEmpty = false;
543 else
544 interrupts &= ~Regs::Intr_RxHigh;
545
546 // Intr_TxLow is special, we only signal it if we've filled up the fifo
547 // and then dropped below the low watermark
548 if (txFull)
549 txFull = false;
550 else
551 interrupts &= ~Regs::Intr_TxLow;
552
553 if (interrupts) {
554 Tick when = curTick;
555 if ((interrupts & Regs::Intr_NoDelay) == 0)
556 when += intrDelay;
557 cpuIntrPost(when);
558 }
559 }
560
561 void
562 Device::devIntrClear(uint32_t interrupts)
563 {
564 if ((interrupts & Regs::Intr_Res))
565 panic("Cannot clear a reserved interrupt");
566
567 regs.IntrStatus &= ~interrupts;
568
569 DPRINTF(EthernetIntr,
570 "interrupt cleared from intStatus: intr=%x status=%x mask=%x\n",
571 interrupts, regs.IntrStatus, regs.IntrMask);
572
573 if (!(regs.IntrStatus & regs.IntrMask))
574 cpuIntrClear();
575 }
576
577 void
578 Device::devIntrChangeMask(uint32_t newmask)
579 {
580 if (regs.IntrMask == newmask)
581 return;
582
583 regs.IntrMask = newmask;
584
585 DPRINTF(EthernetIntr,
586 "interrupt mask changed: intStatus=%x intMask=%x masked=%x\n",
587 regs.IntrStatus, regs.IntrMask, regs.IntrStatus & regs.IntrMask);
588
589 if (regs.IntrStatus & regs.IntrMask)
590 cpuIntrPost(curTick);
591 else
592 cpuIntrClear();
593 }
594
595 void
596 Base::cpuIntrPost(Tick when)
597 {
598 // If the interrupt you want to post is later than an interrupt
599 // already scheduled, just let it post in the coming one and don't
600 // schedule another.
601 // HOWEVER, must be sure that the scheduled intrTick is in the
602 // future (this was formerly the source of a bug)
603 /**
604 * @todo this warning should be removed and the intrTick code should
605 * be fixed.
606 */
607 assert(when >= curTick);
608 assert(intrTick >= curTick || intrTick == 0);
609 if (!cpuIntrEnable) {
610 DPRINTF(EthernetIntr, "interrupts not enabled.\n",
611 intrTick);
612 return;
613 }
614
615 if (when > intrTick && intrTick != 0) {
616 DPRINTF(EthernetIntr, "don't need to schedule event...intrTick=%d\n",
617 intrTick);
618 return;
619 }
620
621 intrTick = when;
622 if (intrTick < curTick) {
623 debug_break();
624 intrTick = curTick;
625 }
626
627 DPRINTF(EthernetIntr, "going to schedule an interrupt for intrTick=%d\n",
628 intrTick);
629
630 if (intrEvent)
631 intrEvent->squash();
632 intrEvent = new IntrEvent(this, intrTick, true);
633 }
634
635 void
636 Base::cpuInterrupt()
637 {
638 assert(intrTick == curTick);
639
640 // Whether or not there's a pending interrupt, we don't care about
641 // it anymore
642 intrEvent = 0;
643 intrTick = 0;
644
645 // Don't send an interrupt if there's already one
646 if (cpuPendingIntr) {
647 DPRINTF(EthernetIntr,
648 "would send an interrupt now, but there's already pending\n");
649 } else {
650 // Send interrupt
651 cpuPendingIntr = true;
652
653 DPRINTF(EthernetIntr, "posting interrupt\n");
654 intrPost();
655 }
656 }
657
658 void
659 Base::cpuIntrClear()
660 {
661 if (!cpuPendingIntr)
662 return;
663
664 if (intrEvent) {
665 intrEvent->squash();
666 intrEvent = 0;
667 }
668
669 intrTick = 0;
670
671 cpuPendingIntr = false;
672
673 DPRINTF(EthernetIntr, "clearing cchip interrupt\n");
674 intrClear();
675 }
676
677 bool
678 Base::cpuIntrPending() const
679 { return cpuPendingIntr; }
680
681 void
682 Device::changeConfig(uint32_t newconf)
683 {
684 uint32_t changed = regs.Config ^ newconf;
685 if (!changed)
686 return;
687
688 regs.Config = newconf;
689
690 if ((changed & Regs::Config_IntEn)) {
691 cpuIntrEnable = regs.Config & Regs::Config_IntEn;
692 if (cpuIntrEnable) {
693 if (regs.IntrStatus & regs.IntrMask)
694 cpuIntrPost(curTick);
695 } else {
696 cpuIntrClear();
697 }
698 }
699
700 if ((changed & Regs::Config_TxEn)) {
701 txEnable = regs.Config & Regs::Config_TxEn;
702 if (txEnable)
703 txKick();
704 }
705
706 if ((changed & Regs::Config_RxEn)) {
707 rxEnable = regs.Config & Regs::Config_RxEn;
708 if (rxEnable)
709 rxKick();
710 }
711 }
712
713 void
714 Device::command(uint32_t command)
715 {
716 if (command & Regs::Command_Intr)
717 devIntrPost(Regs::Intr_Soft);
718
719 if (command & Regs::Command_Reset)
720 reset();
721 }
722
723 void
724 Device::reset()
725 {
726 using namespace Regs;
727
728 memset(&regs, 0, sizeof(regs));
729
730 regs.Config = 0;
731 if (params()->rx_thread)
732 regs.Config |= Config_RxThread;
733 if (params()->tx_thread)
734 regs.Config |= Config_TxThread;
735 if (params()->rss)
736 regs.Config |= Config_RSS;
737 if (params()->zero_copy)
738 regs.Config |= Config_ZeroCopy;
739 if (params()->delay_copy)
740 regs.Config |= Config_DelayCopy;
741 if (params()->virtual_addr)
742 regs.Config |= Config_Vaddr;
743
744 if (params()->delay_copy && params()->zero_copy)
745 panic("Can't delay copy and zero copy");
746
747 regs.IntrMask = Intr_Soft | Intr_RxHigh | Intr_RxPacket | Intr_TxLow;
748 regs.RxMaxCopy = params()->rx_max_copy;
749 regs.TxMaxCopy = params()->tx_max_copy;
750 regs.RxMaxIntr = params()->rx_max_intr;
751 regs.VirtualCount = params()->virtual_count;
752 regs.RxFifoSize = params()->rx_fifo_size;
753 regs.TxFifoSize = params()->tx_fifo_size;
754 regs.RxFifoMark = params()->rx_fifo_threshold;
755 regs.TxFifoMark = params()->tx_fifo_threshold;
756 regs.HwAddr = params()->hardware_address;
757
758 rxList.clear();
759 rxBusy.clear();
760 rxActive = -1;
761 txList.clear();
762
763 rxState = rxIdle;
764 txState = txIdle;
765
766 rxFifo.clear();
767 rxFifoPtr = rxFifo.end();
768 txFifo.clear();
769 rxEmpty = false;
770 rxLow = true;
771 txFull = false;
772
773 int size = virtualRegs.size();
774 virtualRegs.clear();
775 virtualRegs.resize(size);
776 for (int i = 0; i < size; ++i)
777 virtualRegs[i].rxPacket = rxFifo.end();
778 }
779
780 void
781 Device::rxDmaDone()
782 {
783 assert(rxState == rxCopy);
784 rxState = rxCopyDone;
785 DPRINTF(EthernetDMA, "end rx dma write paddr=%#x len=%d\n",
786 rxDmaAddr, rxDmaLen);
787 DDUMP(EthernetData, rxDmaData, rxDmaLen);
788
789 // If the transmit state machine has a pending DMA, let it go first
790 if (txState == txBeginCopy)
791 txKick();
792
793 rxKick();
794 }
795
796 void
797 Device::rxKick()
798 {
799 VirtualReg *vnic = NULL;
800
801 DPRINTF(EthernetSM, "rxKick: rxState=%s (rxFifo.size=%d)\n",
802 RxStateStrings[rxState], rxFifo.size());
803
804 if (rxKickTick > curTick) {
805 DPRINTF(EthernetSM, "rxKick: exiting, can't run till %d\n",
806 rxKickTick);
807 return;
808 }
809
810 next:
811 if (rxState == rxIdle)
812 goto exit;
813
814 if (rxActive == -1) {
815 if (rxState != rxFifoBlock)
816 panic("no active vnic while in state %s", RxStateStrings[rxState]);
817
818 DPRINTF(EthernetSM, "processing rxState=%s\n",
819 RxStateStrings[rxState]);
820 } else {
821 vnic = &virtualRegs[rxActive];
822 DPRINTF(EthernetSM,
823 "processing rxState=%s for vnic %d (rxunique %d)\n",
824 RxStateStrings[rxState], rxActive, vnic->rxUnique);
825 }
826
827 switch (rxState) {
828 case rxFifoBlock:
829 if (DTRACE(EthernetSM)) {
830 PacketFifo::iterator end = rxFifo.end();
831 int size = virtualRegs.size();
832 for (int i = 0; i < size; ++i) {
833 VirtualReg *vn = &virtualRegs[i];
834 if (vn->rxPacket != end &&
835 !Regs::get_RxDone_Busy(vn->RxDone)) {
836 DPRINTF(EthernetSM,
837 "vnic %d (rxunique %d), has outstanding packet %d\n",
838 i, vn->rxUnique,
839 rxFifo.countPacketsBefore(vn->rxPacket));
840 }
841 }
842 }
843
844 if (!rxBusy.empty()) {
845 rxActive = rxBusy.front();
846 rxBusy.pop_front();
847 vnic = &virtualRegs[rxActive];
848
849 if (vnic->rxPacket == rxFifo.end())
850 panic("continuing vnic without packet\n");
851
852 DPRINTF(EthernetSM,
853 "continue processing for vnic %d (rxunique %d)\n",
854 rxActive, vnic->rxUnique);
855
856 rxState = rxBeginCopy;
857
858 break;
859 }
860
861 if (rxFifoPtr == rxFifo.end()) {
862 DPRINTF(EthernetSM, "receive waiting for data. Nothing to do.\n");
863 goto exit;
864 }
865
866 if (rxList.empty())
867 panic("Not idle, but nothing to do!");
868
869 assert(!rxFifo.empty());
870
871 rxActive = rxList.front();
872 rxList.pop_front();
873 vnic = &virtualRegs[rxActive];
874
875 DPRINTF(EthernetSM,
876 "processing new packet for vnic %d (rxunique %d)\n",
877 rxActive, vnic->rxUnique);
878
879 // Grab a new packet from the fifo.
880 vnic->rxPacket = rxFifoPtr++;
881 vnic->rxPacketOffset = 0;
882 vnic->rxPacketBytes = (*vnic->rxPacket)->length;
883 assert(vnic->rxPacketBytes);
884
885 vnic->rxDoneData = 0;
886 /* scope for variables */ {
887 IpPtr ip(*vnic->rxPacket);
888 if (ip) {
889 DPRINTF(Ethernet, "ID is %d\n", ip->id());
890 vnic->rxDoneData |= Regs::RxDone_IpPacket;
891 rxIpChecksums++;
892 if (cksum(ip) != 0) {
893 DPRINTF(EthernetCksum, "Rx IP Checksum Error\n");
894 vnic->rxDoneData |= Regs::RxDone_IpError;
895 }
896 TcpPtr tcp(ip);
897 UdpPtr udp(ip);
898 if (tcp) {
899 DPRINTF(Ethernet,
900 "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n",
901 tcp->sport(), tcp->dport(), tcp->seq(),
902 tcp->ack());
903 vnic->rxDoneData |= Regs::RxDone_TcpPacket;
904 rxTcpChecksums++;
905 if (cksum(tcp) != 0) {
906 DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n");
907 vnic->rxDoneData |= Regs::RxDone_TcpError;
908 }
909 } else if (udp) {
910 vnic->rxDoneData |= Regs::RxDone_UdpPacket;
911 rxUdpChecksums++;
912 if (cksum(udp) != 0) {
913 DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n");
914 vnic->rxDoneData |= Regs::RxDone_UdpError;
915 }
916 }
917 }
918 }
919 rxState = rxBeginCopy;
920 break;
921
922 case rxBeginCopy:
923 if (dmaPending() || getState() != Running)
924 goto exit;
925
926 rxDmaAddr = params()->platform->pciToDma(
927 Regs::get_RxData_Addr(vnic->RxData));
928 rxDmaLen = std::min<int>(Regs::get_RxData_Len(vnic->RxData),
929 vnic->rxPacketBytes);
930 rxDmaData = (*vnic->rxPacket)->data + vnic->rxPacketOffset;
931 rxState = rxCopy;
932 if (rxDmaAddr == 1LL) {
933 rxState = rxCopyDone;
934 break;
935 }
936
937
938 dmaWrite(rxDmaAddr, rxDmaLen, &rxDmaEvent, rxDmaData);
939 break;
940
941 case rxCopy:
942 DPRINTF(EthernetSM, "receive machine still copying\n");
943 goto exit;
944
945 case rxCopyDone:
946 vnic->RxDone = vnic->rxDoneData;
947 vnic->RxDone |= Regs::RxDone_Complete;
948
949 if (vnic->rxPacketBytes == rxDmaLen) {
950 // Packet is complete. Indicate how many bytes were copied
951 vnic->RxDone = Regs::set_RxDone_CopyLen(vnic->RxDone, rxDmaLen);
952
953 DPRINTF(EthernetSM,
954 "rxKick: packet complete on vnic %d (rxunique %d)\n",
955 rxActive, vnic->rxUnique);
956 rxFifo.remove(vnic->rxPacket);
957 vnic->rxPacket = rxFifo.end();
958 } else {
959 vnic->rxPacketBytes -= rxDmaLen;
960 vnic->rxPacketOffset += rxDmaLen;
961 vnic->RxDone |= Regs::RxDone_More;
962 vnic->RxDone = Regs::set_RxDone_CopyLen(vnic->RxDone,
963 vnic->rxPacketBytes);
964 DPRINTF(EthernetSM,
965 "rxKick: packet not complete on vnic %d (rxunique %d): "
966 "%d bytes left\n",
967 rxActive, vnic->rxUnique, vnic->rxPacketBytes);
968 }
969
970 rxActive = -1;
971 rxState = rxBusy.empty() && rxList.empty() ? rxIdle : rxFifoBlock;
972
973 if (rxFifo.empty()) {
974 devIntrPost(Regs::Intr_RxEmpty);
975 rxEmpty = true;
976 }
977
978 if (rxFifo.size() < params()->rx_fifo_low_mark)
979 rxLow = true;
980
981 if (rxFifo.size() > params()->rx_fifo_threshold)
982 rxLow = false;
983
984 devIntrPost(Regs::Intr_RxDMA);
985 break;
986
987 default:
988 panic("Invalid rxState!");
989 }
990
991 DPRINTF(EthernetSM, "entering next rxState=%s\n",
992 RxStateStrings[rxState]);
993
994 goto next;
995
996 exit:
997 /**
998 * @todo do we want to schedule a future kick?
999 */
1000 DPRINTF(EthernetSM, "rx state machine exited rxState=%s\n",
1001 RxStateStrings[rxState]);
1002 }
1003
1004 void
1005 Device::txDmaDone()
1006 {
1007 assert(txState == txCopy);
1008 txState = txCopyDone;
1009 DPRINTF(EthernetDMA, "tx dma read paddr=%#x len=%d\n",
1010 txDmaAddr, txDmaLen);
1011 DDUMP(EthernetData, txDmaData, txDmaLen);
1012
1013 // If the receive state machine has a pending DMA, let it go first
1014 if (rxState == rxBeginCopy)
1015 rxKick();
1016
1017 txKick();
1018 }
1019
1020 void
1021 Device::transmit()
1022 {
1023 if (txFifo.empty()) {
1024 DPRINTF(Ethernet, "nothing to transmit\n");
1025 return;
1026 }
1027
1028 uint32_t interrupts;
1029 EthPacketPtr packet = txFifo.front();
1030 if (!interface->sendPacket(packet)) {
1031 DPRINTF(Ethernet, "Packet Transmit: failed txFifo available %d\n",
1032 txFifo.avail());
1033 goto reschedule;
1034 }
1035
1036 txFifo.pop();
1037 #if TRACING_ON
1038 if (DTRACE(Ethernet)) {
1039 IpPtr ip(packet);
1040 if (ip) {
1041 DPRINTF(Ethernet, "ID is %d\n", ip->id());
1042 TcpPtr tcp(ip);
1043 if (tcp) {
1044 DPRINTF(Ethernet,
1045 "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n",
1046 tcp->sport(), tcp->dport(), tcp->seq(),
1047 tcp->ack());
1048 }
1049 }
1050 }
1051 #endif
1052
1053 DDUMP(EthernetData, packet->data, packet->length);
1054 txBytes += packet->length;
1055 txPackets++;
1056
1057 DPRINTF(Ethernet, "Packet Transmit: successful txFifo Available %d\n",
1058 txFifo.avail());
1059
1060 interrupts = Regs::Intr_TxPacket;
1061 if (txFifo.size() < regs.TxFifoMark)
1062 interrupts |= Regs::Intr_TxLow;
1063 devIntrPost(interrupts);
1064
1065 reschedule:
1066 if (!txFifo.empty() && !txEvent.scheduled()) {
1067 DPRINTF(Ethernet, "reschedule transmit\n");
1068 txEvent.schedule(curTick + retryTime);
1069 }
1070 }
1071
1072 void
1073 Device::txKick()
1074 {
1075 VirtualReg *vnic;
1076 DPRINTF(EthernetSM, "txKick: txState=%s (txFifo.size=%d)\n",
1077 TxStateStrings[txState], txFifo.size());
1078
1079 if (txKickTick > curTick) {
1080 DPRINTF(EthernetSM, "txKick: exiting, can't run till %d\n",
1081 txKickTick);
1082 return;
1083 }
1084
1085 next:
1086 if (txState == txIdle)
1087 goto exit;
1088
1089 assert(!txList.empty());
1090 vnic = &virtualRegs[txList.front()];
1091
1092 switch (txState) {
1093 case txFifoBlock:
1094 assert(Regs::get_TxDone_Busy(vnic->TxDone));
1095 if (!txPacket) {
1096 // Grab a new packet from the fifo.
1097 txPacket = new EthPacketData(16384);
1098 txPacketOffset = 0;
1099 }
1100
1101 if (txFifo.avail() - txPacket->length <
1102 Regs::get_TxData_Len(vnic->TxData)) {
1103 DPRINTF(EthernetSM, "transmit fifo full. Nothing to do.\n");
1104 goto exit;
1105 }
1106
1107 txState = txBeginCopy;
1108 break;
1109
1110 case txBeginCopy:
1111 if (dmaPending() || getState() != Running)
1112 goto exit;
1113
1114 txDmaAddr = params()->platform->pciToDma(
1115 Regs::get_TxData_Addr(vnic->TxData));
1116 txDmaLen = Regs::get_TxData_Len(vnic->TxData);
1117 txDmaData = txPacket->data + txPacketOffset;
1118 txState = txCopy;
1119
1120 dmaRead(txDmaAddr, txDmaLen, &txDmaEvent, txDmaData);
1121 break;
1122
1123 case txCopy:
1124 DPRINTF(EthernetSM, "transmit machine still copying\n");
1125 goto exit;
1126
1127 case txCopyDone:
1128 vnic->TxDone = txDmaLen | Regs::TxDone_Complete;
1129 txPacket->length += txDmaLen;
1130 if ((vnic->TxData & Regs::TxData_More)) {
1131 txPacketOffset += txDmaLen;
1132 txState = txIdle;
1133 devIntrPost(Regs::Intr_TxDMA);
1134 break;
1135 }
1136
1137 assert(txPacket->length <= txFifo.avail());
1138 if ((vnic->TxData & Regs::TxData_Checksum)) {
1139 IpPtr ip(txPacket);
1140 if (ip) {
1141 TcpPtr tcp(ip);
1142 if (tcp) {
1143 tcp->sum(0);
1144 tcp->sum(cksum(tcp));
1145 txTcpChecksums++;
1146 }
1147
1148 UdpPtr udp(ip);
1149 if (udp) {
1150 udp->sum(0);
1151 udp->sum(cksum(udp));
1152 txUdpChecksums++;
1153 }
1154
1155 ip->sum(0);
1156 ip->sum(cksum(ip));
1157 txIpChecksums++;
1158 }
1159 }
1160
1161 txFifo.push(txPacket);
1162 if (txFifo.avail() < regs.TxMaxCopy) {
1163 devIntrPost(Regs::Intr_TxFull);
1164 txFull = true;
1165 }
1166 txPacket = 0;
1167 transmit();
1168 txList.pop_front();
1169 txState = txList.empty() ? txIdle : txFifoBlock;
1170 devIntrPost(Regs::Intr_TxDMA);
1171 break;
1172
1173 default:
1174 panic("Invalid txState!");
1175 }
1176
1177 DPRINTF(EthernetSM, "entering next txState=%s\n",
1178 TxStateStrings[txState]);
1179
1180 goto next;
1181
1182 exit:
1183 /**
1184 * @todo do we want to schedule a future kick?
1185 */
1186 DPRINTF(EthernetSM, "tx state machine exited txState=%s\n",
1187 TxStateStrings[txState]);
1188 }
1189
1190 void
1191 Device::transferDone()
1192 {
1193 if (txFifo.empty()) {
1194 DPRINTF(Ethernet, "transfer complete: txFifo empty...nothing to do\n");
1195 return;
1196 }
1197
1198 DPRINTF(Ethernet, "transfer complete: data in txFifo...schedule xmit\n");
1199
1200 txEvent.reschedule(curTick + cycles(1), true);
1201 }
1202
1203 bool
1204 Device::rxFilter(const EthPacketPtr &packet)
1205 {
1206 if (!Regs::get_Config_Filter(regs.Config))
1207 return false;
1208
1209 panic("receive filter not implemented\n");
1210 bool drop = true;
1211
1212 #if 0
1213 string type;
1214
1215 EthHdr *eth = packet->eth();
1216 if (eth->unicast()) {
1217 // If we're accepting all unicast addresses
1218 if (acceptUnicast)
1219 drop = false;
1220
1221 // If we make a perfect match
1222 if (acceptPerfect && params->eaddr == eth.dst())
1223 drop = false;
1224
1225 if (acceptArp && eth->type() == ETH_TYPE_ARP)
1226 drop = false;
1227
1228 } else if (eth->broadcast()) {
1229 // if we're accepting broadcasts
1230 if (acceptBroadcast)
1231 drop = false;
1232
1233 } else if (eth->multicast()) {
1234 // if we're accepting all multicasts
1235 if (acceptMulticast)
1236 drop = false;
1237
1238 }
1239
1240 if (drop) {
1241 DPRINTF(Ethernet, "rxFilter drop\n");
1242 DDUMP(EthernetData, packet->data, packet->length);
1243 }
1244 #endif
1245 return drop;
1246 }
1247
1248 bool
1249 Device::recvPacket(EthPacketPtr packet)
1250 {
1251 rxBytes += packet->length;
1252 rxPackets++;
1253
1254 DPRINTF(Ethernet, "Receiving packet from wire, rxFifo Available is %d\n",
1255 rxFifo.avail());
1256
1257 if (!rxEnable) {
1258 DPRINTF(Ethernet, "receive disabled...packet dropped\n");
1259 return true;
1260 }
1261
1262 if (rxFilter(packet)) {
1263 DPRINTF(Ethernet, "packet filtered...dropped\n");
1264 return true;
1265 }
1266
1267 if (rxFifo.size() >= regs.RxFifoMark)
1268 devIntrPost(Regs::Intr_RxHigh);
1269
1270 if (!rxFifo.push(packet)) {
1271 DPRINTF(Ethernet,
1272 "packet will not fit in receive buffer...packet dropped\n");
1273 return false;
1274 }
1275
1276 // If we were at the last element, back up one ot go to the new
1277 // last element of the list.
1278 if (rxFifoPtr == rxFifo.end())
1279 --rxFifoPtr;
1280
1281 devIntrPost(Regs::Intr_RxPacket);
1282 rxKick();
1283 return true;
1284 }
1285
1286 void
1287 Device::resume()
1288 {
1289 SimObject::resume();
1290
1291 // During drain we could have left the state machines in a waiting state and
1292 // they wouldn't get out until some other event occured to kick them.
1293 // This way they'll get out immediately
1294 txKick();
1295 rxKick();
1296 }
1297
1298 //=====================================================================
1299 //
1300 //
1301 void
1302 Base::serialize(std::ostream &os)
1303 {
1304 // Serialize the PciDev base class
1305 PciDev::serialize(os);
1306
1307 SERIALIZE_SCALAR(rxEnable);
1308 SERIALIZE_SCALAR(txEnable);
1309 SERIALIZE_SCALAR(cpuIntrEnable);
1310
1311 /*
1312 * Keep track of pending interrupt status.
1313 */
1314 SERIALIZE_SCALAR(intrTick);
1315 SERIALIZE_SCALAR(cpuPendingIntr);
1316 Tick intrEventTick = 0;
1317 if (intrEvent)
1318 intrEventTick = intrEvent->when();
1319 SERIALIZE_SCALAR(intrEventTick);
1320 }
1321
1322 void
1323 Base::unserialize(Checkpoint *cp, const std::string &section)
1324 {
1325 // Unserialize the PciDev base class
1326 PciDev::unserialize(cp, section);
1327
1328 UNSERIALIZE_SCALAR(rxEnable);
1329 UNSERIALIZE_SCALAR(txEnable);
1330 UNSERIALIZE_SCALAR(cpuIntrEnable);
1331
1332 /*
1333 * Keep track of pending interrupt status.
1334 */
1335 UNSERIALIZE_SCALAR(intrTick);
1336 UNSERIALIZE_SCALAR(cpuPendingIntr);
1337 Tick intrEventTick;
1338 UNSERIALIZE_SCALAR(intrEventTick);
1339 if (intrEventTick) {
1340 intrEvent = new IntrEvent(this, intrEventTick, true);
1341 }
1342 }
1343
1344 void
1345 Device::serialize(std::ostream &os)
1346 {
1347 int count;
1348
1349 // Serialize the PciDev base class
1350 Base::serialize(os);
1351
1352 if (rxState == rxCopy)
1353 panic("can't serialize with an in flight dma request rxState=%s",
1354 RxStateStrings[rxState]);
1355
1356 if (txState == txCopy)
1357 panic("can't serialize with an in flight dma request txState=%s",
1358 TxStateStrings[txState]);
1359
1360 /*
1361 * Serialize the device registers
1362 */
1363 SERIALIZE_SCALAR(regs.Config);
1364 SERIALIZE_SCALAR(regs.IntrStatus);
1365 SERIALIZE_SCALAR(regs.IntrMask);
1366 SERIALIZE_SCALAR(regs.RxMaxCopy);
1367 SERIALIZE_SCALAR(regs.TxMaxCopy);
1368 SERIALIZE_SCALAR(regs.RxMaxIntr);
1369 SERIALIZE_SCALAR(regs.VirtualCount);
1370 SERIALIZE_SCALAR(regs.RxData);
1371 SERIALIZE_SCALAR(regs.RxDone);
1372 SERIALIZE_SCALAR(regs.TxData);
1373 SERIALIZE_SCALAR(regs.TxDone);
1374
1375 /*
1376 * Serialize the virtual nic state
1377 */
1378 int virtualRegsSize = virtualRegs.size();
1379 SERIALIZE_SCALAR(virtualRegsSize);
1380 for (int i = 0; i < virtualRegsSize; ++i) {
1381 VirtualReg *vnic = &virtualRegs[i];
1382
1383 std::string reg = csprintf("vnic%d", i);
1384 paramOut(os, reg + ".RxData", vnic->RxData);
1385 paramOut(os, reg + ".RxDone", vnic->RxDone);
1386 paramOut(os, reg + ".TxData", vnic->TxData);
1387 paramOut(os, reg + ".TxDone", vnic->TxDone);
1388
1389 bool rxPacketExists = vnic->rxPacket != rxFifo.end();
1390 paramOut(os, reg + ".rxPacketExists", rxPacketExists);
1391 if (rxPacketExists) {
1392 int rxPacket = 0;
1393 PacketFifo::iterator i = rxFifo.begin();
1394 while (i != vnic->rxPacket) {
1395 assert(i != rxFifo.end());
1396 ++i;
1397 ++rxPacket;
1398 }
1399
1400 paramOut(os, reg + ".rxPacket", rxPacket);
1401 paramOut(os, reg + ".rxPacketOffset", vnic->rxPacketOffset);
1402 paramOut(os, reg + ".rxPacketBytes", vnic->rxPacketBytes);
1403 }
1404 paramOut(os, reg + ".rxDoneData", vnic->rxDoneData);
1405 }
1406
1407 int rxFifoPtr = rxFifo.countPacketsBefore(this->rxFifoPtr);
1408 SERIALIZE_SCALAR(rxFifoPtr);
1409
1410 SERIALIZE_SCALAR(rxActive);
1411
1412 VirtualList::iterator i, end;
1413 for (count = 0, i = rxList.begin(), end = rxList.end(); i != end; ++i)
1414 paramOut(os, csprintf("rxList%d", count++), *i);
1415 int rxListSize = count;
1416 SERIALIZE_SCALAR(rxListSize);
1417
1418 for (count = 0, i = rxBusy.begin(), end = rxBusy.end(); i != end; ++i)
1419 paramOut(os, csprintf("rxBusy%d", count++), *i);
1420 int rxBusySize = count;
1421 SERIALIZE_SCALAR(rxBusySize);
1422
1423 for (count = 0, i = txList.begin(), end = txList.end(); i != end; ++i)
1424 paramOut(os, csprintf("txList%d", count++), *i);
1425 int txListSize = count;
1426 SERIALIZE_SCALAR(txListSize);
1427
1428 /*
1429 * Serialize rx state machine
1430 */
1431 int rxState = this->rxState;
1432 SERIALIZE_SCALAR(rxState);
1433 SERIALIZE_SCALAR(rxEmpty);
1434 SERIALIZE_SCALAR(rxLow);
1435 rxFifo.serialize("rxFifo", os);
1436
1437 /*
1438 * Serialize tx state machine
1439 */
1440 int txState = this->txState;
1441 SERIALIZE_SCALAR(txState);
1442 SERIALIZE_SCALAR(txFull);
1443 txFifo.serialize("txFifo", os);
1444 bool txPacketExists = txPacket;
1445 SERIALIZE_SCALAR(txPacketExists);
1446 if (txPacketExists) {
1447 txPacket->serialize("txPacket", os);
1448 SERIALIZE_SCALAR(txPacketOffset);
1449 SERIALIZE_SCALAR(txPacketBytes);
1450 }
1451
1452 /*
1453 * If there's a pending transmit, store the time so we can
1454 * reschedule it later
1455 */
1456 Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick : 0;
1457 SERIALIZE_SCALAR(transmitTick);
1458 }
1459
1460 void
1461 Device::unserialize(Checkpoint *cp, const std::string &section)
1462 {
1463 // Unserialize the PciDev base class
1464 Base::unserialize(cp, section);
1465
1466 /*
1467 * Unserialize the device registers
1468 */
1469 UNSERIALIZE_SCALAR(regs.Config);
1470 UNSERIALIZE_SCALAR(regs.IntrStatus);
1471 UNSERIALIZE_SCALAR(regs.IntrMask);
1472 UNSERIALIZE_SCALAR(regs.RxMaxCopy);
1473 UNSERIALIZE_SCALAR(regs.TxMaxCopy);
1474 UNSERIALIZE_SCALAR(regs.RxMaxIntr);
1475 UNSERIALIZE_SCALAR(regs.VirtualCount);
1476 UNSERIALIZE_SCALAR(regs.RxData);
1477 UNSERIALIZE_SCALAR(regs.RxDone);
1478 UNSERIALIZE_SCALAR(regs.TxData);
1479 UNSERIALIZE_SCALAR(regs.TxDone);
1480
1481 UNSERIALIZE_SCALAR(rxActive);
1482
1483 int rxListSize;
1484 UNSERIALIZE_SCALAR(rxListSize);
1485 rxList.clear();
1486 for (int i = 0; i < rxListSize; ++i) {
1487 int value;
1488 paramIn(cp, section, csprintf("rxList%d", i), value);
1489 rxList.push_back(value);
1490 }
1491
1492 int rxBusySize;
1493 UNSERIALIZE_SCALAR(rxBusySize);
1494 rxBusy.clear();
1495 for (int i = 0; i < rxBusySize; ++i) {
1496 int value;
1497 paramIn(cp, section, csprintf("rxBusy%d", i), value);
1498 rxBusy.push_back(value);
1499 }
1500
1501 int txListSize;
1502 UNSERIALIZE_SCALAR(txListSize);
1503 txList.clear();
1504 for (int i = 0; i < txListSize; ++i) {
1505 int value;
1506 paramIn(cp, section, csprintf("txList%d", i), value);
1507 txList.push_back(value);
1508 }
1509
1510 /*
1511 * Unserialize rx state machine
1512 */
1513 int rxState;
1514 UNSERIALIZE_SCALAR(rxState);
1515 UNSERIALIZE_SCALAR(rxEmpty);
1516 UNSERIALIZE_SCALAR(rxLow);
1517 this->rxState = (RxState) rxState;
1518 rxFifo.unserialize("rxFifo", cp, section);
1519
1520 int rxFifoPtr;
1521 UNSERIALIZE_SCALAR(rxFifoPtr);
1522 this->rxFifoPtr = rxFifo.begin();
1523 for (int i = 0; i < rxFifoPtr; ++i)
1524 ++this->rxFifoPtr;
1525
1526 /*
1527 * Unserialize tx state machine
1528 */
1529 int txState;
1530 UNSERIALIZE_SCALAR(txState);
1531 UNSERIALIZE_SCALAR(txFull);
1532 this->txState = (TxState) txState;
1533 txFifo.unserialize("txFifo", cp, section);
1534 bool txPacketExists;
1535 UNSERIALIZE_SCALAR(txPacketExists);
1536 txPacket = 0;
1537 if (txPacketExists) {
1538 txPacket = new EthPacketData(16384);
1539 txPacket->unserialize("txPacket", cp, section);
1540 UNSERIALIZE_SCALAR(txPacketOffset);
1541 UNSERIALIZE_SCALAR(txPacketBytes);
1542 }
1543
1544 /*
1545 * unserialize the virtual nic registers/state
1546 *
1547 * this must be done after the unserialization of the rxFifo
1548 * because the packet iterators depend on the fifo being populated
1549 */
1550 int virtualRegsSize;
1551 UNSERIALIZE_SCALAR(virtualRegsSize);
1552 virtualRegs.clear();
1553 virtualRegs.resize(virtualRegsSize);
1554 for (int i = 0; i < virtualRegsSize; ++i) {
1555 VirtualReg *vnic = &virtualRegs[i];
1556 std::string reg = csprintf("vnic%d", i);
1557
1558 paramIn(cp, section, reg + ".RxData", vnic->RxData);
1559 paramIn(cp, section, reg + ".RxDone", vnic->RxDone);
1560 paramIn(cp, section, reg + ".TxData", vnic->TxData);
1561 paramIn(cp, section, reg + ".TxDone", vnic->TxDone);
1562
1563 vnic->rxUnique = rxUnique++;
1564 vnic->txUnique = txUnique++;
1565
1566 bool rxPacketExists;
1567 paramIn(cp, section, reg + ".rxPacketExists", rxPacketExists);
1568 if (rxPacketExists) {
1569 int rxPacket;
1570 paramIn(cp, section, reg + ".rxPacket", rxPacket);
1571 vnic->rxPacket = rxFifo.begin();
1572 while (rxPacket--)
1573 ++vnic->rxPacket;
1574
1575 paramIn(cp, section, reg + ".rxPacketOffset",
1576 vnic->rxPacketOffset);
1577 paramIn(cp, section, reg + ".rxPacketBytes", vnic->rxPacketBytes);
1578 } else {
1579 vnic->rxPacket = rxFifo.end();
1580 }
1581 paramIn(cp, section, reg + ".rxDoneData", vnic->rxDoneData);
1582 }
1583
1584 /*
1585 * If there's a pending transmit, reschedule it now
1586 */
1587 Tick transmitTick;
1588 UNSERIALIZE_SCALAR(transmitTick);
1589 if (transmitTick)
1590 txEvent.schedule(curTick + transmitTick);
1591
1592 pioPort->sendStatusChange(Port::RangeChange);
1593
1594 }
1595
1596 /* namespace Sinic */ }
1597
1598 Sinic::Interface *
1599 SinicIntParams::create()
1600 {
1601 using namespace Sinic;
1602
1603 Interface *dev_int = new Interface(name, device);
1604
1605 if (peer) {
1606 dev_int->setPeer(peer);
1607 peer->setPeer(dev_int);
1608 }
1609
1610 return dev_int;
1611 }
1612
1613 Sinic::Device *
1614 SinicParams::create()
1615 {
1616 return new Sinic::Device(this);
1617 }