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