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