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