gem5
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
sinic.cc
Go to the documentation of this file.
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 
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 
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 
104 {}
105 
106 void
108 {
109  Base::regStats();
110 
111  _maxVnicDistance = 0;
112 
114  .name(name() + ".maxVnicDistance")
115  .desc("maximum vnic distance")
116  ;
117 
119  .name(name() + ".totalVnicDistance")
120  .desc("total vnic distance")
121  ;
123  .name(name() + ".numVnicDistance")
124  .desc("number of vnic distance measurements")
125  ;
126 
128  .name(name() + ".avgVnicDistance")
129  .desc("average vnic distance")
130  ;
131 
133 }
134 
135 void
137 {
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
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
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
212 {
213  prepareIO(cpu, index);
214 }
215 
219 Tick
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 
304 Tick
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",
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",
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
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)
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);
540 }
541 
542 void
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
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
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
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
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
702 {
703  assert(rxState == rxCopy);
705  DPRINTF(EthernetDMA, "end rx dma write paddr=%#x len=%d\n",
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
718 {
719  VirtualReg *vnic = NULL;
720 
721  DPRINTF(EthernetSM, "rxKick: rxState=%s (rxFifo.size=%d)\n",
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)) {
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,
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:
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 
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:
966  DPRINTF(EthernetSM, "rx state machine exited rxState=%s\n",
967  RxStateStrings[rxState]);
968 }
969 
970 void
972 {
973  assert(txState == txCopy);
975  DPRINTF(EthernetDMA, "tx dma read paddr=%#x len=%d\n",
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
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
1034 {
1035  VirtualReg *vnic;
1036  DPRINTF(EthernetSM, "txKick: txState=%s (txFifo.size=%d)\n",
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:
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 
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)) {
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:
1146  DPRINTF(EthernetSM, "tx state machine exited txState=%s\n",
1147  TxStateStrings[txState]);
1148 }
1149 
1150 void
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
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
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
1248 {
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
1263 {
1264  // Serialize the PciDevice base class
1266 
1270 
1271  /*
1272  * Keep track of pending interrupt status.
1273  */
1276  Tick intrEventTick = 0;
1277  if (intrEvent)
1278  intrEventTick = intrEvent->when();
1279  SERIALIZE_SCALAR(intrEventTick);
1280 }
1281 
1282 void
1284 {
1285  // Unserialize the PciDevice base class
1287 
1291 
1292  /*
1293  * Keep track of pending interrupt status.
1294  */
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
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",
1316 
1317  if (txState == txCopy)
1318  panic("can't serialize with an in flight dma request txState=%s",
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 
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);
1395  rxFifo.serialize("rxFifo", cp);
1396 
1397  /*
1398  * Serialize tx state machine
1399  */
1400  int txState = this->txState;
1401  SERIALIZE_SCALAR(txState);
1403  txFifo.serialize("txFifo", cp);
1404  bool txPacketExists = txPacket != nullptr;
1405  SERIALIZE_SCALAR(txPacketExists);
1406  if (txPacketExists) {
1407  txPacket->serialize("txPacket", cp);
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
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 
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);
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);
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>(16384);
1500  txPacket->unserialize("txPacket", cp);
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 
1554 
1555 }
1556 
1557 } // namespace Sinic
1558 
1559 Sinic::Device *
1560 SinicParams::create()
1561 {
1562  return new Sinic::Device(this);
1563 }
void reset()
Definition: sinic.cc:631
count
Definition: misc.hh:704
#define DPRINTF(x,...)
Definition: trace.hh:212
uint16_t type() const
Definition: inet.hh:130
uint16_t dport() const
Definition: inet.hh:513
EthPacketPtr front()
Definition: pktfifo.hh:120
void remove(iterator i)
Definition: pktfifo.hh:160
EventWrapper< Device,&Device::rxDmaDone > rxDmaEvent
Definition: sinic.hh:249
const char * TxStateStrings[]
Definition: sinic.cc:68
void set(T v, ByteOrder endian)
Set the value in the data pointer to v using the specified endianness.
int txPacketOffset
Definition: sinic.hh:188
Bitfield< 30, 0 > index
Counter rxUnique
Definition: sinic.hh:158
virtual void resetStats()
Reset statistics associated with this object.
Definition: sim_object.cc:110
Bitfield< 5, 3 > reg
Definition: types.hh:89
Cycles is a wrapper class for representing cycle counts, i.e.
Definition: types.hh:83
const Regs::Info & regInfo(Addr daddr)
Definition: sinicreg.hh:184
void unserialize(CheckpointIn &cp) override
Reconstruct the state of this object from a checkpoint.
Definition: device.cc:490
void transferDone()
Definition: sinic.cc:1151
void dmaRead(Addr addr, int size, Event *event, uint8_t *data, Tick delay=0)
Definition: dma_device.hh:170
PacketFifo::iterator rxFifoPtr
Definition: sinic.hh:177
void unserialize(const std::string &base, CheckpointIn &cp)
Definition: pktfifo.cc:101
Bitfield< 7 > i
Definition: miscregs.hh:1378
uint16_t sum() const
Definition: inet.hh:264
ContextID contextId() const
Accessor function for context ID.
Definition: request.hh:694
void unserialize(CheckpointIn &cp) override
Unserialize an object.
Definition: sinic.cc:1421
#define panic(...)
Definition: misc.hh:153
Dummy class to keep the Python class hierarchy in sync with the C++ object hierarchy.
Definition: etherdevice.hh:134
void devIntrPost(uint32_t interrupts)
Interrupt management.
Definition: sinic.cc:433
#define LL(N)
int64_t constant
Definition: types.hh:52
void txDmaDone()
Definition: sinic.cc:971
TxState
Transmit State Machine states.
Definition: sinic.hh:101
RxState rxState
Definition: sinic.hh:175
iterator begin()
Definition: pktfifo.hh:114
int countPacketsBefore(const_iterator i) const
Definition: pktfifo.hh:179
void prepareRead(ContextID cpu, int index)
Definition: sinic.cc:170
uint8_t * txDmaData
Definition: sinic.hh:191
uint16_t cksum(const IpPtr &ptr)
Definition: inet.cc:207
uint8_t * rxDmaData
Definition: sinic.hh:181
bool empty() const
Definition: pktfifo.hh:103
void transmit()
Retransmit event.
Definition: sinic.cc:987
Bitfield< 3 > exit
Definition: misc.hh:849
struct Sinic::Device::@70 regs
device register file
Counter txUnique
Definition: sinic.hh:159
Stats::Scalar rxIpChecksums
Definition: etherdevice.hh:78
int rxDirtyCount
Definition: sinic.hh:168
int rxMappedCount
Definition: sinic.hh:167
void cpuIntrPost(Tick when)
Definition: sinic.cc:503
#define PCI_CMD_MSE
Definition: pcireg.h:105
Stats::Scalar rxUdpChecksums
Definition: etherdevice.hh:82
bool scheduled() const
Determine if the current event is scheduled.
Definition: eventq.hh:381
#define DDUMP(x, data, count)
Definition: trace.hh:211
void regStats() override
Register statistics for this object.
Definition: sinic.cc:107
EtherInt * getPeer()
Definition: etherint.hh:63
unsigned rxDmaLen
Definition: sinic.hh:182
PacketFifo txFifo
Definition: sinic.hh:185
Addr rxDmaAddr
Definition: sinic.hh:180
void dmaWrite(Addr addr, int size, Event *event, uint8_t *data, Tick delay=0)
Definition: dma_device.hh:164
int _maxVnicDistance
Definition: sinic.hh:290
iterator end()
Definition: pktfifo.hh:115
Stats::Scalar rxTcpChecksums
Definition: etherdevice.hh:80
void command(uint32_t command)
Definition: sinic.cc:621
Stats::Scalar txBytes
Definition: etherdevice.hh:73
Stats::Scalar maxVnicDistance
Definition: sinic.hh:287
Addr pciToDma(Addr pci_addr) const
Definition: device.hh:189
void serialize(const std::string &base, CheckpointOut &cp) const
Serialization stuff.
Definition: pktfifo.cc:88
bool rxEnable
Definition: sinic.hh:52
T get(ByteOrder endian) const
Get the data in the packet byte swapped from the specified endianness.
bool txFull
Definition: sinic.hh:186
static const int VirtualShift
Definition: sinicreg.hh:60
Tick rxKickTick
Definition: sinic.hh:198
EthPacketPtr txPacket
Definition: sinic.hh:187
uint16_t id() const
Definition: inet.hh:259
PioPort pioPort
The pioPort that handles the requests for us and provides us requests that it sees.
Definition: io_device.hh:91
void serialize(CheckpointOut &cp) const override
Serialization stuff.
Definition: sinic.cc:1262
bool txEnable
Definition: sinic.hh:53
VirtualRegs virtualRegs
Definition: sinic.hh:160
Bitfield< 5, 0 > status
Definition: miscregs.hh:1604
bool rxFilter(const EthPacketPtr &packet)
receive address filter
Definition: sinic.cc:1164
uint64_t & regData64(Addr daddr)
Definition: sinic.hh:172
Stats::Scalar rxPackets
Definition: etherdevice.hh:76
#define UNSERIALIZE_SCALAR(scalar)
Definition: serialize.hh:145
Tick clockEdge(Cycles cycles=Cycles(0)) const
Determine the tick when a cycle begins, by default the current one, but the argument also enables the...
void rxKick()
Definition: sinic.cc:717
Tick curTick()
The current simulated tick.
Definition: core.hh:47
std::string csprintf(const char *format, const Args &...args)
Definition: cprintf.hh:161
#define DTRACE(x)
Definition: trace.hh:210
unsigned avail() const
Definition: pktfifo.hh:102
bool tcp(TxDesc *d)
Tick when() const
Get the time that the event is scheduled.
Definition: eventq.hh:397
EtherInt * getEthPort(const std::string &if_name, int idx) override
Additional function to return the Port of a memory object.
Definition: sinic.cc:144
void regStats()
Register statistics for this object.
Definition: etherdevice.cc:37
DmaDeviceParams Params
Definition: dma_device.hh:160
uint64_t Tick
Tick count type.
Definition: types.hh:63
bool cpuPendingIntr
Definition: sinic.hh:59
bool regValid(Addr daddr)
Definition: sinicreg.hh:226
void prepareIO(ContextID cpu, int index)
Definition: sinic.cc:157
Stats::Scalar numVnicDistance
Definition: sinic.hh:286
void paramOut(CheckpointOut &cp, const string &name, ExtMachInst const &machInst)
Definition: types.cc:40
TxEvent txEvent
Definition: sinic.hh:219
Tick read(PacketPtr pkt) override
Memory Interface.
Definition: sinic.cc:220
const RequestPtr req
A pointer to the original request.
Definition: packet.hh:304
Addr txDmaAddr
Definition: sinic.hh:190
Stats::Formula avgVnicDistance
Definition: sinic.hh:288
void unserialize(CheckpointIn &cp) override
Unserialize an object.
Definition: sinic.cc:1283
unsigned size() const
Definition: pktfifo.hh:100
void resetStats() override
Reset statistics associated with this object.
Definition: sinic.cc:136
Stats::Scalar txIpChecksums
Definition: etherdevice.hh:77
std::shared_ptr< EthPacketData > EthPacketPtr
Definition: etherpkt.hh:90
uint16_t sum() const
Definition: inet.hh:619
VirtualList rxList
Definition: sinic.hh:161
void rxDmaDone()
DMA parameters.
Definition: sinic.cc:701
PacketFifo rxFifo
Definition: sinic.hh:176
Tick pioDelay
Definition: device.hh:185
void devIntrClear(uint32_t interrupts=Regs::Intr_All)
Definition: sinic.cc:469
void squash()
Squash the current event.
Definition: eventq.hh:384
int txDmaLen
Definition: sinic.hh:192
Defines global host-dependent types: Counter, Tick, and (indirectly) {int,uint}{8,16,32,64}_t.
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
Definition: types.hh:142
unsigned packets() const
Definition: pktfifo.hh:98
A Packet is used to encapsulate a transfer between two objects in the memory system (e...
Definition: packet.hh:245
bool recvPacket(EthPacketPtr packet)
device ethernet interface
Definition: sinic.cc:1209
Interface * interface
Definition: sinic.hh:67
Addr BARAddrs[6]
The current address mapping of the BARs.
Definition: device.hh:113
uint16_t command
Definition: pcireg.h:62
Stats::Scalar rxBytes
Definition: etherdevice.hh:74
void sendRangeChange() const
Called by the owner to send a range change.
Definition: port.hh:410
#define SERIALIZE_SCALAR(scalar)
Definition: serialize.hh:143
Stats::Scalar totalVnicDistance
Statistics.
Definition: sinic.hh:285
uint16_t sport() const
Definition: inet.hh:512
static const int NumArgumentRegs M5_VAR_USED
Definition: process.cc:83
bool sendPacket(EthPacketPtr packet)
Definition: etherint.hh:68
Derived & name(const std::string &name)
Set the name and marks this stat to print at the end of simulation.
Definition: statistics.hh:254
uint32_t & regData32(Addr daddr)
Definition: sinic.hh:171
void reschedule(Event &event, Tick when, bool always=false)
Definition: eventq.hh:740
Stats::Scalar txUdpChecksums
Definition: etherdevice.hh:81
Tick write(PacketPtr pkt) override
IPR read of device register.
Definition: sinic.cc:305
void txKick()
Definition: sinic.cc:1033
type
Definition: misc.hh:728
int size()
Definition: pagetable.hh:146
bool cpuIntrPending() const
Definition: sinic.cc:585
virtual const std::string name() const
Definition: sim_object.hh:117
bool rxLow
Definition: sinic.hh:179
IntrEvent * intrEvent
Definition: sinic.hh:66
Addr vtophys(Addr vaddr)
Definition: vtophys.cc:75
Declaration of the Packet class.
std::ostream CheckpointOut
Definition: serialize.hh:67
fifo_list::iterator iterator
Definition: pktfifo.hh:83
void prepareWrite(ContextID cpu, int index)
Definition: sinic.cc:211
void changeConfig(uint32_t newconfig)
device configuration
Definition: sinic.cc:589
Tick intrDelay
Definition: sinic.hh:56
virtual void drainResume()
Resume execution after a successful drain.
Definition: drain.hh:257
bool rxEmpty
Definition: sinic.hh:178
int rxBusyCount
Definition: sinic.hh:166
VirtualList txList
Definition: sinic.hh:164
const EthAddr & dst() const
Definition: inet.hh:146
Tick txKickTick
Definition: sinic.hh:203
PacketFifo::iterator rxIndex
Definition: sinic.hh:143
void devIntrChangeMask(uint32_t newmask)
Definition: sinic.cc:485
void schedule(Event &event, Tick when)
Definition: eventq.hh:728
Tick intrTick
Definition: sinic.hh:57
int txPacketBytes
Definition: sinic.hh:189
void paramIn(CheckpointIn &cp, const string &name, ExtMachInst &machInst)
Definition: types.cc:71
int countPacketsAfter(const_iterator i) const
Definition: pktfifo.hh:186
RxState
Receive State Machine States.
Definition: sinic.hh:92
DrainState drainState() const
Return the current drain state of an object.
Definition: drain.hh:282
void cpuInterrupt()
Definition: sinic.cc:543
Derived & desc(const std::string &_desc)
Set the description and marks this stat to print at the end of simulation.
Definition: statistics.hh:287
virtual void drainResume() override
Resume execution after a successful drain.
Definition: sinic.cc:1247
void cpuIntrClear()
Definition: sinic.cc:566
bool ip(TxDesc *d)
uint16_t sum() const
Definition: inet.hh:519
Device(const Params *p)
Definition: sinic.cc:89
unsigned getSize() const
Definition: packet.hh:649
uint32_t ack() const
Definition: inet.hh:515
bool dmaPending() const
Definition: dma_device.hh:176
void pop()
Definition: pktfifo.hh:139
void clear()
Definition: pktfifo.hh:151
VirtualList rxBusy
Definition: sinic.hh:162
void intrPost()
Definition: device.hh:193
TxState txState
Definition: sinic.hh:184
bool push(EthPacketPtr ptr)
Definition: pktfifo.hh:122
void check() const
Definition: pktfifo.hh:194
PCIConfig config
The current config space.
Definition: device.hh:76
Bitfield< 0 > p
uint32_t seq() const
Definition: inet.hh:514
void intrClear()
Definition: device.hh:194
static const int VirtualMask
Definition: sinicreg.hh:61
const Params * params() const
Definition: sinic.hh:84
int ContextID
Globally unique thread context ID.
Definition: types.hh:175
void serialize(CheckpointOut &cp) const override
Serialization stuff.
Definition: sinic.cc:1306
void serialize(CheckpointOut &cp) const override
Serialize this object to the given output stream.
Definition: device.cc:425
uint32_t BARSize[6]
The size of the BARs.
Definition: device.hh:110
Stats::Scalar txTcpChecksums
Definition: etherdevice.hh:79
const char * RxStateStrings[]
Definition: sinic.cc:59
EventWrapper< Base,&Base::cpuInterrupt > IntrEvent
Definition: sinic.hh:64
bool cpuIntrEnable
Definition: sinic.hh:58
EventWrapper< Device,&Device::txDmaDone > txDmaEvent
Definition: sinic.hh:253
Addr getAddr() const
Definition: packet.hh:639
Stats::Scalar txPackets
Definition: etherdevice.hh:75
int rxActive
Definition: sinic.hh:163

Generated on Fri Jun 9 2017 13:03:46 for gem5 by doxygen 1.8.6