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