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