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