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