gem5  v20.0.0.0
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
i8254xGBe.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2006 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 
29 /* @file
30  * Device model for Intel's 8254x line of gigabit ethernet controllers.
31  * In particular an 82547 revision 2 (82547GI) MAC because it seems to have the
32  * fewest workarounds in the driver. It will probably work with most of the
33  * other MACs with slight modifications.
34  */
35 
36 #include "dev/net/i8254xGBe.hh"
37 
38 /*
39  * @todo really there are multiple dma engines.. we should implement them.
40  */
41 
42 #include <algorithm>
43 #include <memory>
44 
45 #include "base/inet.hh"
46 #include "base/trace.hh"
47 #include "debug/Drain.hh"
48 #include "debug/EthernetAll.hh"
49 #include "mem/packet.hh"
50 #include "mem/packet_access.hh"
51 #include "params/IGbE.hh"
52 #include "sim/stats.hh"
53 #include "sim/system.hh"
54 
55 using namespace iGbReg;
56 using namespace Net;
57 
59  : EtherDevice(p), etherInt(NULL), cpa(NULL),
60  rxFifo(p->rx_fifo_size), txFifo(p->tx_fifo_size), inTick(false),
61  rxTick(false), txTick(false), txFifoTick(false), rxDmaPacket(false),
62  pktOffset(0), fetchDelay(p->fetch_delay), wbDelay(p->wb_delay),
63  fetchCompDelay(p->fetch_comp_delay), wbCompDelay(p->wb_comp_delay),
64  rxWriteDelay(p->rx_write_delay), txReadDelay(p->tx_read_delay),
65  rdtrEvent([this]{ rdtrProcess(); }, name()),
66  radvEvent([this]{ radvProcess(); }, name()),
67  tadvEvent([this]{ tadvProcess(); }, name()),
68  tidvEvent([this]{ tidvProcess(); }, name()),
69  tickEvent([this]{ tick(); }, name()),
70  interEvent([this]{ delayIntEvent(); }, name()),
71  rxDescCache(this, name()+".RxDesc", p->rx_desc_cache_size),
72  txDescCache(this, name()+".TxDesc", p->tx_desc_cache_size),
73  lastInterrupt(0)
74 {
75  etherInt = new IGbEInt(name() + ".int", this);
76 
77  // Initialized internal registers per Intel documentation
78  // All registers intialized to 0 by per register constructor
79  regs.ctrl.fd(1);
80  regs.ctrl.lrst(1);
81  regs.ctrl.speed(2);
82  regs.ctrl.frcspd(1);
83  regs.sts.speed(3); // Say we're 1000Mbps
84  regs.sts.fd(1); // full duplex
85  regs.sts.lu(1); // link up
86  regs.eecd.fwe(1);
87  regs.eecd.ee_type(1);
88  regs.imr = 0;
89  regs.iam = 0;
90  regs.rxdctl.gran(1);
91  regs.rxdctl.wthresh(1);
92  regs.fcrth(1);
93  regs.tdwba = 0;
94  regs.rlpml = 0;
95  regs.sw_fw_sync = 0;
96 
97  regs.pba.rxa(0x30);
98  regs.pba.txa(0x10);
99 
100  eeOpBits = 0;
101  eeAddrBits = 0;
102  eeDataBits = 0;
103  eeOpcode = 0;
104 
105  // clear all 64 16 bit words of the eeprom
106  memset(&flash, 0, EEPROM_SIZE*2);
107 
108  // Set the MAC address
109  memcpy(flash, p->hardware_address.bytes(), ETH_ADDR_LEN);
110  for (int x = 0; x < ETH_ADDR_LEN/2; x++)
111  flash[x] = htobe(flash[x]);
112 
113  uint16_t csum = 0;
114  for (int x = 0; x < EEPROM_SIZE; x++)
115  csum += htobe(flash[x]);
116 
117 
118  // Magic happy checksum value
119  flash[EEPROM_SIZE-1] = htobe((uint16_t)(EEPROM_CSUM - csum));
120 
121  // Store the MAC address as queue ID
122  macAddr = p->hardware_address;
123 
124  rxFifo.clear();
125  txFifo.clear();
126 }
127 
129 {
130  delete etherInt;
131 }
132 
133 void
135 {
136  cpa = CPA::cpa();
137  PciDevice::init();
138 }
139 
140 Port &
141 IGbE::getPort(const std::string &if_name, PortID idx)
142 {
143  if (if_name == "interface")
144  return *etherInt;
145  return EtherDevice::getPort(if_name, idx);
146 }
147 
148 Tick
150 {
151  int offset = pkt->getAddr() & PCI_CONFIG_SIZE;
152  if (offset < PCI_DEVICE_SPECIFIC)
154  else
155  panic("Device specific PCI config space not implemented.\n");
156 
157  //
158  // Some work may need to be done here based for the pci COMMAND bits.
159  //
160 
161  return configDelay;
162 }
163 
164 // Handy macro for range-testing register access addresses
165 #define IN_RANGE(val, base, len) (val >= base && val < (base + len))
166 
167 Tick
169 {
170  int bar;
171  Addr daddr;
172 
173  if (!getBAR(pkt->getAddr(), bar, daddr))
174  panic("Invalid PCI memory access to unmapped memory.\n");
175 
176  // Only Memory register BAR is allowed
177  assert(bar == 0);
178 
179  // Only 32bit accesses allowed
180  assert(pkt->getSize() == 4);
181 
182  DPRINTF(Ethernet, "Read device register %#X\n", daddr);
183 
184  //
185  // Handle read of register here
186  //
187 
188 
189  switch (daddr) {
190  case REG_CTRL:
191  pkt->setLE<uint32_t>(regs.ctrl());
192  break;
193  case REG_STATUS:
194  pkt->setLE<uint32_t>(regs.sts());
195  break;
196  case REG_EECD:
197  pkt->setLE<uint32_t>(regs.eecd());
198  break;
199  case REG_EERD:
200  pkt->setLE<uint32_t>(regs.eerd());
201  break;
202  case REG_CTRL_EXT:
203  pkt->setLE<uint32_t>(regs.ctrl_ext());
204  break;
205  case REG_MDIC:
206  pkt->setLE<uint32_t>(regs.mdic());
207  break;
208  case REG_ICR:
209  DPRINTF(Ethernet, "Reading ICR. ICR=%#x IMR=%#x IAM=%#x IAME=%d\n",
210  regs.icr(), regs.imr, regs.iam, regs.ctrl_ext.iame());
211  pkt->setLE<uint32_t>(regs.icr());
212  if (regs.icr.int_assert() || regs.imr == 0) {
213  regs.icr = regs.icr() & ~mask(30);
214  DPRINTF(Ethernet, "Cleared ICR. ICR=%#x\n", regs.icr());
215  }
216  if (regs.ctrl_ext.iame() && regs.icr.int_assert())
217  regs.imr &= ~regs.iam;
218  chkInterrupt();
219  break;
220  case REG_EICR:
221  // This is only useful for MSI, but the driver reads it every time
222  // Just don't do anything
223  pkt->setLE<uint32_t>(0);
224  break;
225  case REG_ITR:
226  pkt->setLE<uint32_t>(regs.itr());
227  break;
228  case REG_RCTL:
229  pkt->setLE<uint32_t>(regs.rctl());
230  break;
231  case REG_FCTTV:
232  pkt->setLE<uint32_t>(regs.fcttv());
233  break;
234  case REG_TCTL:
235  pkt->setLE<uint32_t>(regs.tctl());
236  break;
237  case REG_PBA:
238  pkt->setLE<uint32_t>(regs.pba());
239  break;
240  case REG_WUC:
241  case REG_WUFC:
242  case REG_WUS:
243  case REG_LEDCTL:
244  pkt->setLE<uint32_t>(0); // We don't care, so just return 0
245  break;
246  case REG_FCRTL:
247  pkt->setLE<uint32_t>(regs.fcrtl());
248  break;
249  case REG_FCRTH:
250  pkt->setLE<uint32_t>(regs.fcrth());
251  break;
252  case REG_RDBAL:
253  pkt->setLE<uint32_t>(regs.rdba.rdbal());
254  break;
255  case REG_RDBAH:
256  pkt->setLE<uint32_t>(regs.rdba.rdbah());
257  break;
258  case REG_RDLEN:
259  pkt->setLE<uint32_t>(regs.rdlen());
260  break;
261  case REG_SRRCTL:
262  pkt->setLE<uint32_t>(regs.srrctl());
263  break;
264  case REG_RDH:
265  pkt->setLE<uint32_t>(regs.rdh());
266  break;
267  case REG_RDT:
268  pkt->setLE<uint32_t>(regs.rdt());
269  break;
270  case REG_RDTR:
271  pkt->setLE<uint32_t>(regs.rdtr());
272  if (regs.rdtr.fpd()) {
274  DPRINTF(EthernetIntr,
275  "Posting interrupt because of RDTR.FPD write\n");
277  regs.rdtr.fpd(0);
278  }
279  break;
280  case REG_RXDCTL:
281  pkt->setLE<uint32_t>(regs.rxdctl());
282  break;
283  case REG_RADV:
284  pkt->setLE<uint32_t>(regs.radv());
285  break;
286  case REG_TDBAL:
287  pkt->setLE<uint32_t>(regs.tdba.tdbal());
288  break;
289  case REG_TDBAH:
290  pkt->setLE<uint32_t>(regs.tdba.tdbah());
291  break;
292  case REG_TDLEN:
293  pkt->setLE<uint32_t>(regs.tdlen());
294  break;
295  case REG_TDH:
296  pkt->setLE<uint32_t>(regs.tdh());
297  break;
298  case REG_TXDCA_CTL:
299  pkt->setLE<uint32_t>(regs.txdca_ctl());
300  break;
301  case REG_TDT:
302  pkt->setLE<uint32_t>(regs.tdt());
303  break;
304  case REG_TIDV:
305  pkt->setLE<uint32_t>(regs.tidv());
306  break;
307  case REG_TXDCTL:
308  pkt->setLE<uint32_t>(regs.txdctl());
309  break;
310  case REG_TADV:
311  pkt->setLE<uint32_t>(regs.tadv());
312  break;
313  case REG_TDWBAL:
314  pkt->setLE<uint32_t>(regs.tdwba & mask(32));
315  break;
316  case REG_TDWBAH:
317  pkt->setLE<uint32_t>(regs.tdwba >> 32);
318  break;
319  case REG_RXCSUM:
320  pkt->setLE<uint32_t>(regs.rxcsum());
321  break;
322  case REG_RLPML:
323  pkt->setLE<uint32_t>(regs.rlpml);
324  break;
325  case REG_RFCTL:
326  pkt->setLE<uint32_t>(regs.rfctl());
327  break;
328  case REG_MANC:
329  pkt->setLE<uint32_t>(regs.manc());
330  break;
331  case REG_SWSM:
332  pkt->setLE<uint32_t>(regs.swsm());
333  regs.swsm.smbi(1);
334  break;
335  case REG_FWSM:
336  pkt->setLE<uint32_t>(regs.fwsm());
337  break;
338  case REG_SWFWSYNC:
339  pkt->setLE<uint32_t>(regs.sw_fw_sync);
340  break;
341  default:
342  if (!IN_RANGE(daddr, REG_VFTA, VLAN_FILTER_TABLE_SIZE*4) &&
344  !IN_RANGE(daddr, REG_MTA, MULTICAST_TABLE_SIZE*4) &&
346  panic("Read request to unknown register number: %#x\n", daddr);
347  else
348  pkt->setLE<uint32_t>(0);
349  };
350 
351  pkt->makeAtomicResponse();
352  return pioDelay;
353 }
354 
355 Tick
357 {
358  int bar;
359  Addr daddr;
360 
361 
362  if (!getBAR(pkt->getAddr(), bar, daddr))
363  panic("Invalid PCI memory access to unmapped memory.\n");
364 
365  // Only Memory register BAR is allowed
366  assert(bar == 0);
367 
368  // Only 32bit accesses allowed
369  assert(pkt->getSize() == sizeof(uint32_t));
370 
371  DPRINTF(Ethernet, "Wrote device register %#X value %#X\n",
372  daddr, pkt->getLE<uint32_t>());
373 
374  //
375  // Handle write of register here
376  //
377  uint32_t val = pkt->getLE<uint32_t>();
378 
379  Regs::RCTL oldrctl;
380  Regs::TCTL oldtctl;
381 
382  switch (daddr) {
383  case REG_CTRL:
384  regs.ctrl = val;
385  if (regs.ctrl.tfce())
386  warn("TX Flow control enabled, should implement\n");
387  if (regs.ctrl.rfce())
388  warn("RX Flow control enabled, should implement\n");
389  break;
390  case REG_CTRL_EXT:
391  regs.ctrl_ext = val;
392  break;
393  case REG_STATUS:
394  regs.sts = val;
395  break;
396  case REG_EECD:
397  int oldClk;
398  oldClk = regs.eecd.sk();
399  regs.eecd = val;
400  // See if this is a eeprom access and emulate accordingly
401  if (!oldClk && regs.eecd.sk()) {
402  if (eeOpBits < 8) {
403  eeOpcode = eeOpcode << 1 | regs.eecd.din();
404  eeOpBits++;
405  } else if (eeAddrBits < 8 && eeOpcode == EEPROM_READ_OPCODE_SPI) {
406  eeAddr = eeAddr << 1 | regs.eecd.din();
407  eeAddrBits++;
408  } else if (eeDataBits < 16 && eeOpcode == EEPROM_READ_OPCODE_SPI) {
409  assert(eeAddr>>1 < EEPROM_SIZE);
410  DPRINTF(EthernetEEPROM, "EEPROM bit read: %d word: %#X\n",
411  flash[eeAddr>>1] >> eeDataBits & 0x1,
412  flash[eeAddr>>1]);
413  regs.eecd.dout((flash[eeAddr>>1] >> (15-eeDataBits)) & 0x1);
414  eeDataBits++;
415  } else if (eeDataBits < 8 && eeOpcode == EEPROM_RDSR_OPCODE_SPI) {
416  regs.eecd.dout(0);
417  eeDataBits++;
418  } else
419  panic("What's going on with eeprom interface? opcode:"
420  " %#x:%d addr: %#x:%d, data: %d\n", (uint32_t)eeOpcode,
421  (uint32_t)eeOpBits, (uint32_t)eeAddr,
422  (uint32_t)eeAddrBits, (uint32_t)eeDataBits);
423 
424  // Reset everything for the next command
425  if ((eeDataBits == 16 && eeOpcode == EEPROM_READ_OPCODE_SPI) ||
426  (eeDataBits == 8 && eeOpcode == EEPROM_RDSR_OPCODE_SPI)) {
427  eeOpBits = 0;
428  eeAddrBits = 0;
429  eeDataBits = 0;
430  eeOpcode = 0;
431  eeAddr = 0;
432  }
433 
434  DPRINTF(EthernetEEPROM, "EEPROM: opcode: %#X:%d addr: %#X:%d\n",
435  (uint32_t)eeOpcode, (uint32_t) eeOpBits,
436  (uint32_t)eeAddr>>1, (uint32_t)eeAddrBits);
437  if (eeOpBits == 8 && !(eeOpcode == EEPROM_READ_OPCODE_SPI ||
438  eeOpcode == EEPROM_RDSR_OPCODE_SPI ))
439  panic("Unknown eeprom opcode: %#X:%d\n", (uint32_t)eeOpcode,
440  (uint32_t)eeOpBits);
441 
442 
443  }
444  // If driver requests eeprom access, immediately give it to it
445  regs.eecd.ee_gnt(regs.eecd.ee_req());
446  break;
447  case REG_EERD:
448  regs.eerd = val;
449  if (regs.eerd.start()) {
450  regs.eerd.done(1);
451  assert(regs.eerd.addr() < EEPROM_SIZE);
452  regs.eerd.data(flash[regs.eerd.addr()]);
453  regs.eerd.start(0);
454  DPRINTF(EthernetEEPROM, "EEPROM: read addr: %#X data %#x\n",
455  regs.eerd.addr(), regs.eerd.data());
456  }
457  break;
458  case REG_MDIC:
459  regs.mdic = val;
460  if (regs.mdic.i())
461  panic("No support for interrupt on mdic complete\n");
462  if (regs.mdic.phyadd() != 1)
463  panic("No support for reading anything but phy\n");
464  DPRINTF(Ethernet, "%s phy address %x\n",
465  regs.mdic.op() == 1 ? "Writing" : "Reading",
466  regs.mdic.regadd());
467  switch (regs.mdic.regadd()) {
468  case PHY_PSTATUS:
469  regs.mdic.data(0x796D); // link up
470  break;
471  case PHY_PID:
472  regs.mdic.data(params()->phy_pid);
473  break;
474  case PHY_EPID:
475  regs.mdic.data(params()->phy_epid);
476  break;
477  case PHY_GSTATUS:
478  regs.mdic.data(0x7C00);
479  break;
480  case PHY_EPSTATUS:
481  regs.mdic.data(0x3000);
482  break;
483  case PHY_AGC:
484  regs.mdic.data(0x180); // some random length
485  break;
486  default:
487  regs.mdic.data(0);
488  }
489  regs.mdic.r(1);
490  break;
491  case REG_ICR:
492  DPRINTF(Ethernet, "Writing ICR. ICR=%#x IMR=%#x IAM=%#x IAME=%d\n",
493  regs.icr(), regs.imr, regs.iam, regs.ctrl_ext.iame());
494  if (regs.ctrl_ext.iame())
495  regs.imr &= ~regs.iam;
496  regs.icr = ~bits(val,30,0) & regs.icr();
497  chkInterrupt();
498  break;
499  case REG_ITR:
500  regs.itr = val;
501  break;
502  case REG_ICS:
503  DPRINTF(EthernetIntr, "Posting interrupt because of ICS write\n");
504  postInterrupt((IntTypes)val);
505  break;
506  case REG_IMS:
507  regs.imr |= val;
508  chkInterrupt();
509  break;
510  case REG_IMC:
511  regs.imr &= ~val;
512  chkInterrupt();
513  break;
514  case REG_IAM:
515  regs.iam = val;
516  break;
517  case REG_RCTL:
518  oldrctl = regs.rctl;
519  regs.rctl = val;
520  if (regs.rctl.rst()) {
521  rxDescCache.reset();
522  DPRINTF(EthernetSM, "RXS: Got RESET!\n");
523  rxFifo.clear();
524  regs.rctl.rst(0);
525  }
526  if (regs.rctl.en())
527  rxTick = true;
528  restartClock();
529  break;
530  case REG_FCTTV:
531  regs.fcttv = val;
532  break;
533  case REG_TCTL:
534  regs.tctl = val;
535  oldtctl = regs.tctl;
536  regs.tctl = val;
537  if (regs.tctl.en())
538  txTick = true;
539  restartClock();
540  if (regs.tctl.en() && !oldtctl.en()) {
541  txDescCache.reset();
542  }
543  break;
544  case REG_PBA:
545  regs.pba.rxa(val);
546  regs.pba.txa(64 - regs.pba.rxa());
547  break;
548  case REG_WUC:
549  case REG_WUFC:
550  case REG_WUS:
551  case REG_LEDCTL:
552  case REG_FCAL:
553  case REG_FCAH:
554  case REG_FCT:
555  case REG_VET:
556  case REG_AIFS:
557  case REG_TIPG:
558  ; // We don't care, so don't store anything
559  break;
560  case REG_IVAR0:
561  warn("Writing to IVAR0, ignoring...\n");
562  break;
563  case REG_FCRTL:
564  regs.fcrtl = val;
565  break;
566  case REG_FCRTH:
567  regs.fcrth = val;
568  break;
569  case REG_RDBAL:
570  regs.rdba.rdbal( val & ~mask(4));
572  break;
573  case REG_RDBAH:
574  regs.rdba.rdbah(val);
576  break;
577  case REG_RDLEN:
578  regs.rdlen = val & ~mask(7);
580  break;
581  case REG_SRRCTL:
582  regs.srrctl = val;
583  break;
584  case REG_RDH:
585  regs.rdh = val;
587  break;
588  case REG_RDT:
589  regs.rdt = val;
590  DPRINTF(EthernetSM, "RXS: RDT Updated.\n");
591  if (drainState() == DrainState::Running) {
592  DPRINTF(EthernetSM, "RXS: RDT Fetching Descriptors!\n");
594  } else {
595  DPRINTF(EthernetSM, "RXS: RDT NOT Fetching Desc b/c draining!\n");
596  }
597  break;
598  case REG_RDTR:
599  regs.rdtr = val;
600  break;
601  case REG_RADV:
602  regs.radv = val;
603  break;
604  case REG_RXDCTL:
605  regs.rxdctl = val;
606  break;
607  case REG_TDBAL:
608  regs.tdba.tdbal( val & ~mask(4));
610  break;
611  case REG_TDBAH:
612  regs.tdba.tdbah(val);
614  break;
615  case REG_TDLEN:
616  regs.tdlen = val & ~mask(7);
618  break;
619  case REG_TDH:
620  regs.tdh = val;
622  break;
623  case REG_TXDCA_CTL:
624  regs.txdca_ctl = val;
625  if (regs.txdca_ctl.enabled())
626  panic("No support for DCA\n");
627  break;
628  case REG_TDT:
629  regs.tdt = val;
630  DPRINTF(EthernetSM, "TXS: TX Tail pointer updated\n");
631  if (drainState() == DrainState::Running) {
632  DPRINTF(EthernetSM, "TXS: TDT Fetching Descriptors!\n");
634  } else {
635  DPRINTF(EthernetSM, "TXS: TDT NOT Fetching Desc b/c draining!\n");
636  }
637  break;
638  case REG_TIDV:
639  regs.tidv = val;
640  break;
641  case REG_TXDCTL:
642  regs.txdctl = val;
643  break;
644  case REG_TADV:
645  regs.tadv = val;
646  break;
647  case REG_TDWBAL:
648  regs.tdwba &= ~mask(32);
649  regs.tdwba |= val;
651  regs.tdwba & mask(1));
652  break;
653  case REG_TDWBAH:
654  regs.tdwba &= mask(32);
655  regs.tdwba |= (uint64_t)val << 32;
657  regs.tdwba & mask(1));
658  break;
659  case REG_RXCSUM:
660  regs.rxcsum = val;
661  break;
662  case REG_RLPML:
663  regs.rlpml = val;
664  break;
665  case REG_RFCTL:
666  regs.rfctl = val;
667  if (regs.rfctl.exsten())
668  panic("Extended RX descriptors not implemented\n");
669  break;
670  case REG_MANC:
671  regs.manc = val;
672  break;
673  case REG_SWSM:
674  regs.swsm = val;
675  if (regs.fwsm.eep_fw_semaphore())
676  regs.swsm.swesmbi(0);
677  break;
678  case REG_SWFWSYNC:
679  regs.sw_fw_sync = val;
680  break;
681  default:
682  if (!IN_RANGE(daddr, REG_VFTA, VLAN_FILTER_TABLE_SIZE*4) &&
685  panic("Write request to unknown register number: %#x\n", daddr);
686  };
687 
688  pkt->makeAtomicResponse();
689  return pioDelay;
690 }
691 
692 void
694 {
695  assert(t);
696 
697  // Interrupt is already pending
698  if (t & regs.icr() && !now)
699  return;
700 
701  regs.icr = regs.icr() | t;
702 
703  Tick itr_interval = SimClock::Int::ns * 256 * regs.itr.interval();
704  DPRINTF(EthernetIntr,
705  "EINT: postInterrupt() curTick(): %d itr: %d interval: %d\n",
706  curTick(), regs.itr.interval(), itr_interval);
707 
708  if (regs.itr.interval() == 0 || now ||
709  lastInterrupt + itr_interval <= curTick()) {
710  if (interEvent.scheduled()) {
712  }
713  cpuPostInt();
714  } else {
715  Tick int_time = lastInterrupt + itr_interval;
716  assert(int_time > 0);
717  DPRINTF(EthernetIntr, "EINT: Scheduling timer interrupt for tick %d\n",
718  int_time);
719  if (!interEvent.scheduled()) {
720  schedule(interEvent, int_time);
721  }
722  }
723 }
724 
725 void
727 {
728  cpuPostInt();
729 }
730 
731 
732 void
734 {
735 
737 
738  if (!(regs.icr() & regs.imr)) {
739  DPRINTF(Ethernet, "Interrupt Masked. Not Posting\n");
740  return;
741  }
742 
743  DPRINTF(Ethernet, "Posting Interrupt\n");
744 
745 
746  if (interEvent.scheduled()) {
748  }
749 
750  if (rdtrEvent.scheduled()) {
751  regs.icr.rxt0(1);
753  }
754  if (radvEvent.scheduled()) {
755  regs.icr.rxt0(1);
757  }
758  if (tadvEvent.scheduled()) {
759  regs.icr.txdw(1);
761  }
762  if (tidvEvent.scheduled()) {
763  regs.icr.txdw(1);
765  }
766 
767  regs.icr.int_assert(1);
768  DPRINTF(EthernetIntr, "EINT: Posting interrupt to CPU now. Vector %#x\n",
769  regs.icr());
770 
771  intrPost();
772 
774 }
775 
776 void
778 {
779  if (regs.icr.int_assert()) {
780  regs.icr.int_assert(0);
781  DPRINTF(EthernetIntr,
782  "EINT: Clearing interrupt to CPU now. Vector %#x\n",
783  regs.icr());
784  intrClear();
785  }
786 }
787 
788 void
790 {
791  DPRINTF(Ethernet, "Checking interrupts icr: %#x imr: %#x\n", regs.icr(),
792  regs.imr);
793  // Check if we need to clear the cpu interrupt
794  if (!(regs.icr() & regs.imr)) {
795  DPRINTF(Ethernet, "Mask cleaned all interrupts\n");
796  if (interEvent.scheduled())
798  if (regs.icr.int_assert())
799  cpuClearInt();
800  }
801  DPRINTF(Ethernet, "ITR = %#X itr.interval = %#X\n",
802  regs.itr(), regs.itr.interval());
803 
804  if (regs.icr() & regs.imr) {
805  if (regs.itr.interval() == 0) {
806  cpuPostInt();
807  } else {
808  DPRINTF(Ethernet,
809  "Possibly scheduling interrupt because of imr write\n");
810  if (!interEvent.scheduled()) {
811  Tick t = curTick() + SimClock::Int::ns * 256 * regs.itr.interval();
812  DPRINTF(Ethernet, "Scheduling for %d\n", t);
813  schedule(interEvent, t);
814  }
815  }
816  }
817 }
818 
819 
821 
822 template<class T>
823 IGbE::DescCache<T>::DescCache(IGbE *i, const std::string n, int s)
824  : igbe(i), _name(n), cachePnt(0), size(s), curFetching(0),
825  wbOut(0), moreToWb(false), wbAlignment(0), pktPtr(NULL),
826  wbDelayEvent([this]{ writeback1(); }, n),
827  fetchDelayEvent([this]{ fetchDescriptors1(); }, n),
828  fetchEvent([this]{ fetchComplete(); }, n),
829  wbEvent([this]{ wbComplete(); }, n)
830 {
831  fetchBuf = new T[size];
832  wbBuf = new T[size];
833 }
834 
835 template<class T>
837 {
838  reset();
839  delete[] fetchBuf;
840  delete[] wbBuf;
841 }
842 
843 template<class T>
844 void
846 {
847  if (usedCache.size() > 0 || curFetching || wbOut)
848  panic("Descriptor Address, Length or Head changed. Bad\n");
849  reset();
850 
851 }
852 
853 template<class T>
854 void
856 {
857  int curHead = descHead();
858  int max_to_wb = usedCache.size();
859 
860  // Check if this writeback is less restrictive that the previous
861  // and if so setup another one immediately following it
862  if (wbOut) {
863  if (aMask < wbAlignment) {
864  moreToWb = true;
865  wbAlignment = aMask;
866  }
867  DPRINTF(EthernetDesc,
868  "Writing back already in process, returning\n");
869  return;
870  }
871 
872  moreToWb = false;
873  wbAlignment = aMask;
874 
875 
876  DPRINTF(EthernetDesc, "Writing back descriptors head: %d tail: "
877  "%d len: %d cachePnt: %d max_to_wb: %d descleft: %d\n",
878  curHead, descTail(), descLen(), cachePnt, max_to_wb,
879  descLeft());
880 
881  if (max_to_wb + curHead >= descLen()) {
882  max_to_wb = descLen() - curHead;
883  moreToWb = true;
884  // this is by definition aligned correctly
885  } else if (wbAlignment != 0) {
886  // align the wb point to the mask
887  max_to_wb = max_to_wb & ~wbAlignment;
888  }
889 
890  DPRINTF(EthernetDesc, "Writing back %d descriptors\n", max_to_wb);
891 
892  if (max_to_wb <= 0) {
893  if (usedCache.size())
894  igbe->anBegin(annSmWb, "Wait Alignment", CPA::FL_WAIT);
895  else
896  igbe->anWe(annSmWb, annUsedCacheQ);
897  return;
898  }
899 
900  wbOut = max_to_wb;
901 
902  assert(!wbDelayEvent.scheduled());
903  igbe->schedule(wbDelayEvent, curTick() + igbe->wbDelay);
904  igbe->anBegin(annSmWb, "Prepare Writeback Desc");
905 }
906 
907 template<class T>
908 void
910 {
911  // If we're draining delay issuing this DMA
912  if (igbe->drainState() != DrainState::Running) {
913  igbe->schedule(wbDelayEvent, curTick() + igbe->wbDelay);
914  return;
915  }
916 
917  DPRINTF(EthernetDesc, "Begining DMA of %d descriptors\n", wbOut);
918 
919  for (int x = 0; x < wbOut; x++) {
920  assert(usedCache.size());
921  memcpy(&wbBuf[x], usedCache[x], sizeof(T));
922  igbe->anPq(annSmWb, annUsedCacheQ);
923  igbe->anPq(annSmWb, annDescQ);
924  igbe->anQ(annSmWb, annUsedDescQ);
925  }
926 
927 
928  igbe->anBegin(annSmWb, "Writeback Desc DMA");
929 
930  assert(wbOut);
931  igbe->dmaWrite(pciToDma(descBase() + descHead() * sizeof(T)),
932  wbOut * sizeof(T), &wbEvent, (uint8_t*)wbBuf,
933  igbe->wbCompDelay);
934 }
935 
936 template<class T>
937 void
939 {
940  size_t max_to_fetch;
941 
942  if (curFetching) {
943  DPRINTF(EthernetDesc,
944  "Currently fetching %d descriptors, returning\n",
945  curFetching);
946  return;
947  }
948 
949  if (descTail() >= cachePnt)
950  max_to_fetch = descTail() - cachePnt;
951  else
952  max_to_fetch = descLen() - cachePnt;
953 
954  size_t free_cache = size - usedCache.size() - unusedCache.size();
955 
956  if (!max_to_fetch)
957  igbe->anWe(annSmFetch, annUnusedDescQ);
958  else
959  igbe->anPq(annSmFetch, annUnusedDescQ, max_to_fetch);
960 
961  if (max_to_fetch) {
962  if (!free_cache)
963  igbe->anWf(annSmFetch, annDescQ);
964  else
965  igbe->anRq(annSmFetch, annDescQ, free_cache);
966  }
967 
968  max_to_fetch = std::min(max_to_fetch, free_cache);
969 
970 
971  DPRINTF(EthernetDesc, "Fetching descriptors head: %d tail: "
972  "%d len: %d cachePnt: %d max_to_fetch: %d descleft: %d\n",
973  descHead(), descTail(), descLen(), cachePnt,
974  max_to_fetch, descLeft());
975 
976  // Nothing to do
977  if (max_to_fetch == 0)
978  return;
979 
980  // So we don't have two descriptor fetches going on at once
981  curFetching = max_to_fetch;
982 
983  assert(!fetchDelayEvent.scheduled());
984  igbe->schedule(fetchDelayEvent, curTick() + igbe->fetchDelay);
985  igbe->anBegin(annSmFetch, "Prepare Fetch Desc");
986 }
987 
988 template<class T>
989 void
991 {
992  // If we're draining delay issuing this DMA
993  if (igbe->drainState() != DrainState::Running) {
994  igbe->schedule(fetchDelayEvent, curTick() + igbe->fetchDelay);
995  return;
996  }
997 
998  igbe->anBegin(annSmFetch, "Fetch Desc");
999 
1000  DPRINTF(EthernetDesc, "Fetching descriptors at %#x (%#x), size: %#x\n",
1001  descBase() + cachePnt * sizeof(T),
1002  pciToDma(descBase() + cachePnt * sizeof(T)),
1003  curFetching * sizeof(T));
1004  assert(curFetching);
1005  igbe->dmaRead(pciToDma(descBase() + cachePnt * sizeof(T)),
1006  curFetching * sizeof(T), &fetchEvent, (uint8_t*)fetchBuf,
1007  igbe->fetchCompDelay);
1008 }
1009 
1010 template<class T>
1011 void
1013 {
1014  T *newDesc;
1015  igbe->anBegin(annSmFetch, "Fetch Complete");
1016  for (int x = 0; x < curFetching; x++) {
1017  newDesc = new T;
1018  memcpy(newDesc, &fetchBuf[x], sizeof(T));
1019  unusedCache.push_back(newDesc);
1020  igbe->anDq(annSmFetch, annUnusedDescQ);
1021  igbe->anQ(annSmFetch, annUnusedCacheQ);
1022  igbe->anQ(annSmFetch, annDescQ);
1023  }
1024 
1025 
1026 #ifndef NDEBUG
1027  int oldCp = cachePnt;
1028 #endif
1029 
1030  cachePnt += curFetching;
1031  assert(cachePnt <= descLen());
1032  if (cachePnt == descLen())
1033  cachePnt = 0;
1034 
1035  curFetching = 0;
1036 
1037  DPRINTF(EthernetDesc, "Fetching complete cachePnt %d -> %d\n",
1038  oldCp, cachePnt);
1039 
1040  if ((descTail() >= cachePnt ? (descTail() - cachePnt) : (descLen() -
1041  cachePnt)) == 0)
1042  {
1043  igbe->anWe(annSmFetch, annUnusedDescQ);
1044  } else if (!(size - usedCache.size() - unusedCache.size())) {
1045  igbe->anWf(annSmFetch, annDescQ);
1046  } else {
1047  igbe->anBegin(annSmFetch, "Wait", CPA::FL_WAIT);
1048  }
1049 
1050  enableSm();
1051  igbe->checkDrain();
1052 }
1053 
1054 template<class T>
1055 void
1057 {
1058 
1059  igbe->anBegin(annSmWb, "Finish Writeback");
1060 
1061  long curHead = descHead();
1062 #ifndef NDEBUG
1063  long oldHead = curHead;
1064 #endif
1065 
1066  for (int x = 0; x < wbOut; x++) {
1067  assert(usedCache.size());
1068  delete usedCache[0];
1069  usedCache.pop_front();
1070 
1071  igbe->anDq(annSmWb, annUsedCacheQ);
1072  igbe->anDq(annSmWb, annDescQ);
1073  }
1074 
1075  curHead += wbOut;
1076  wbOut = 0;
1077 
1078  if (curHead >= descLen())
1079  curHead -= descLen();
1080 
1081  // Update the head
1082  updateHead(curHead);
1083 
1084  DPRINTF(EthernetDesc, "Writeback complete curHead %d -> %d\n",
1085  oldHead, curHead);
1086 
1087  // If we still have more to wb, call wb now
1088  actionAfterWb();
1089  if (moreToWb) {
1090  moreToWb = false;
1091  DPRINTF(EthernetDesc, "Writeback has more todo\n");
1092  writeback(wbAlignment);
1093  }
1094 
1095  if (!wbOut) {
1096  igbe->checkDrain();
1097  if (usedCache.size())
1098  igbe->anBegin(annSmWb, "Wait", CPA::FL_WAIT);
1099  else
1100  igbe->anWe(annSmWb, annUsedCacheQ);
1101  }
1102  fetchAfterWb();
1103 }
1104 
1105 template<class T>
1106 void
1108 {
1109  DPRINTF(EthernetDesc, "Reseting descriptor cache\n");
1110  for (typename CacheType::size_type x = 0; x < usedCache.size(); x++)
1111  delete usedCache[x];
1112  for (typename CacheType::size_type x = 0; x < unusedCache.size(); x++)
1113  delete unusedCache[x];
1114 
1115  usedCache.clear();
1116  unusedCache.clear();
1117 
1118  cachePnt = 0;
1119 
1120 }
1121 
1122 template<class T>
1123 void
1125 {
1126  SERIALIZE_SCALAR(cachePnt);
1127  SERIALIZE_SCALAR(curFetching);
1128  SERIALIZE_SCALAR(wbOut);
1129  SERIALIZE_SCALAR(moreToWb);
1130  SERIALIZE_SCALAR(wbAlignment);
1131 
1132  typename CacheType::size_type usedCacheSize = usedCache.size();
1133  SERIALIZE_SCALAR(usedCacheSize);
1134  for (typename CacheType::size_type x = 0; x < usedCacheSize; x++) {
1135  arrayParamOut(cp, csprintf("usedCache_%d", x),
1136  (uint8_t*)usedCache[x],sizeof(T));
1137  }
1138 
1139  typename CacheType::size_type unusedCacheSize = unusedCache.size();
1140  SERIALIZE_SCALAR(unusedCacheSize);
1141  for (typename CacheType::size_type x = 0; x < unusedCacheSize; x++) {
1142  arrayParamOut(cp, csprintf("unusedCache_%d", x),
1143  (uint8_t*)unusedCache[x],sizeof(T));
1144  }
1145 
1146  Tick fetch_delay = 0, wb_delay = 0;
1147  if (fetchDelayEvent.scheduled())
1148  fetch_delay = fetchDelayEvent.when();
1149  SERIALIZE_SCALAR(fetch_delay);
1150  if (wbDelayEvent.scheduled())
1151  wb_delay = wbDelayEvent.when();
1152  SERIALIZE_SCALAR(wb_delay);
1153 
1154 
1155 }
1156 
1157 template<class T>
1158 void
1160 {
1161  UNSERIALIZE_SCALAR(cachePnt);
1162  UNSERIALIZE_SCALAR(curFetching);
1163  UNSERIALIZE_SCALAR(wbOut);
1164  UNSERIALIZE_SCALAR(moreToWb);
1165  UNSERIALIZE_SCALAR(wbAlignment);
1166 
1167  typename CacheType::size_type usedCacheSize;
1168  UNSERIALIZE_SCALAR(usedCacheSize);
1169  T *temp;
1170  for (typename CacheType::size_type x = 0; x < usedCacheSize; x++) {
1171  temp = new T;
1172  arrayParamIn(cp, csprintf("usedCache_%d", x),
1173  (uint8_t*)temp,sizeof(T));
1174  usedCache.push_back(temp);
1175  }
1176 
1177  typename CacheType::size_type unusedCacheSize;
1178  UNSERIALIZE_SCALAR(unusedCacheSize);
1179  for (typename CacheType::size_type x = 0; x < unusedCacheSize; x++) {
1180  temp = new T;
1181  arrayParamIn(cp, csprintf("unusedCache_%d", x),
1182  (uint8_t*)temp,sizeof(T));
1183  unusedCache.push_back(temp);
1184  }
1185  Tick fetch_delay = 0, wb_delay = 0;
1186  UNSERIALIZE_SCALAR(fetch_delay);
1187  UNSERIALIZE_SCALAR(wb_delay);
1188  if (fetch_delay)
1189  igbe->schedule(fetchDelayEvent, fetch_delay);
1190  if (wb_delay)
1191  igbe->schedule(wbDelayEvent, wb_delay);
1192 
1193 
1194 }
1195 
1197 
1198 IGbE::RxDescCache::RxDescCache(IGbE *i, const std::string n, int s)
1199  : DescCache<RxDesc>(i, n, s), pktDone(false), splitCount(0),
1200  pktEvent([this]{ pktComplete(); }, n),
1201  pktHdrEvent([this]{ pktSplitDone(); }, n),
1202  pktDataEvent([this]{ pktSplitDone(); }, n)
1203 
1204 {
1205  annSmFetch = "RX Desc Fetch";
1206  annSmWb = "RX Desc Writeback";
1207  annUnusedDescQ = "RX Unused Descriptors";
1208  annUnusedCacheQ = "RX Unused Descriptor Cache";
1209  annUsedCacheQ = "RX Used Descriptor Cache";
1210  annUsedDescQ = "RX Used Descriptors";
1211  annDescQ = "RX Descriptors";
1212 }
1213 
1214 void
1216 {
1217  splitCount++;
1218  DPRINTF(EthernetDesc,
1219  "Part of split packet done: splitcount now %d\n", splitCount);
1220  assert(splitCount <= 2);
1221  if (splitCount != 2)
1222  return;
1223  splitCount = 0;
1224  DPRINTF(EthernetDesc,
1225  "Part of split packet done: calling pktComplete()\n");
1226  pktComplete();
1227 }
1228 
1229 int
1231 {
1232  assert(unusedCache.size());
1233  //if (!unusedCache.size())
1234  // return false;
1235 
1236  pktPtr = packet;
1237  pktDone = false;
1238  unsigned buf_len, hdr_len;
1239 
1240  RxDesc *desc = unusedCache.front();
1241  switch (igbe->regs.srrctl.desctype()) {
1242  case RXDT_LEGACY:
1243  assert(pkt_offset == 0);
1244  bytesCopied = packet->length;
1245  DPRINTF(EthernetDesc, "Packet Length: %d Desc Size: %d\n",
1246  packet->length, igbe->regs.rctl.descSize());
1247  assert(packet->length < igbe->regs.rctl.descSize());
1248  igbe->dmaWrite(pciToDma(desc->legacy.buf),
1249  packet->length, &pktEvent, packet->data,
1250  igbe->rxWriteDelay);
1251  break;
1252  case RXDT_ADV_ONEBUF:
1253  assert(pkt_offset == 0);
1254  bytesCopied = packet->length;
1255  buf_len = igbe->regs.rctl.lpe() ? igbe->regs.srrctl.bufLen() :
1256  igbe->regs.rctl.descSize();
1257  DPRINTF(EthernetDesc, "Packet Length: %d srrctl: %#x Desc Size: %d\n",
1258  packet->length, igbe->regs.srrctl(), buf_len);
1259  assert(packet->length < buf_len);
1260  igbe->dmaWrite(pciToDma(desc->adv_read.pkt),
1261  packet->length, &pktEvent, packet->data,
1262  igbe->rxWriteDelay);
1263  desc->adv_wb.header_len = htole(0);
1264  desc->adv_wb.sph = htole(0);
1265  desc->adv_wb.pkt_len = htole((uint16_t)(pktPtr->length));
1266  break;
1267  case RXDT_ADV_SPLIT_A:
1268  int split_point;
1269 
1270  buf_len = igbe->regs.rctl.lpe() ? igbe->regs.srrctl.bufLen() :
1271  igbe->regs.rctl.descSize();
1272  hdr_len = igbe->regs.rctl.lpe() ? igbe->regs.srrctl.hdrLen() : 0;
1273  DPRINTF(EthernetDesc,
1274  "lpe: %d Packet Length: %d offset: %d srrctl: %#x "
1275  "hdr addr: %#x Hdr Size: %d desc addr: %#x Desc Size: %d\n",
1276  igbe->regs.rctl.lpe(), packet->length, pkt_offset,
1277  igbe->regs.srrctl(), desc->adv_read.hdr, hdr_len,
1278  desc->adv_read.pkt, buf_len);
1279 
1280  split_point = hsplit(pktPtr);
1281 
1282  if (packet->length <= hdr_len) {
1283  bytesCopied = packet->length;
1284  assert(pkt_offset == 0);
1285  DPRINTF(EthernetDesc, "Hdr split: Entire packet in header\n");
1286  igbe->dmaWrite(pciToDma(desc->adv_read.hdr),
1287  packet->length, &pktEvent, packet->data,
1288  igbe->rxWriteDelay);
1289  desc->adv_wb.header_len = htole((uint16_t)packet->length);
1290  desc->adv_wb.sph = htole(0);
1291  desc->adv_wb.pkt_len = htole(0);
1292  } else if (split_point) {
1293  if (pkt_offset) {
1294  // we are only copying some data, header/data has already been
1295  // copied
1296  int max_to_copy =
1297  std::min(packet->length - pkt_offset, buf_len);
1298  bytesCopied += max_to_copy;
1299  DPRINTF(EthernetDesc,
1300  "Hdr split: Continuing data buffer copy\n");
1301  igbe->dmaWrite(pciToDma(desc->adv_read.pkt),
1302  max_to_copy, &pktEvent,
1303  packet->data + pkt_offset, igbe->rxWriteDelay);
1304  desc->adv_wb.header_len = htole(0);
1305  desc->adv_wb.pkt_len = htole((uint16_t)max_to_copy);
1306  desc->adv_wb.sph = htole(0);
1307  } else {
1308  int max_to_copy =
1309  std::min(packet->length - split_point, buf_len);
1310  bytesCopied += max_to_copy + split_point;
1311 
1312  DPRINTF(EthernetDesc, "Hdr split: splitting at %d\n",
1313  split_point);
1314  igbe->dmaWrite(pciToDma(desc->adv_read.hdr),
1315  split_point, &pktHdrEvent,
1316  packet->data, igbe->rxWriteDelay);
1317  igbe->dmaWrite(pciToDma(desc->adv_read.pkt),
1318  max_to_copy, &pktDataEvent,
1319  packet->data + split_point, igbe->rxWriteDelay);
1320  desc->adv_wb.header_len = htole(split_point);
1321  desc->adv_wb.sph = 1;
1322  desc->adv_wb.pkt_len = htole((uint16_t)(max_to_copy));
1323  }
1324  } else {
1325  panic("Header split not fitting within header buffer or "
1326  "undecodable packet not fitting in header unsupported\n");
1327  }
1328  break;
1329  default:
1330  panic("Unimplemnted RX receive buffer type: %d\n",
1331  igbe->regs.srrctl.desctype());
1332  }
1333  return bytesCopied;
1334 
1335 }
1336 
1337 void
1339 {
1340  assert(unusedCache.size());
1341  RxDesc *desc;
1342  desc = unusedCache.front();
1343 
1344  igbe->anBegin("RXS", "Update Desc");
1345 
1346  uint16_t crcfixup = igbe->regs.rctl.secrc() ? 0 : 4 ;
1347  DPRINTF(EthernetDesc, "pktPtr->length: %d bytesCopied: %d "
1348  "stripcrc offset: %d value written: %d %d\n",
1349  pktPtr->length, bytesCopied, crcfixup,
1350  htole((uint16_t)(pktPtr->length + crcfixup)),
1351  (uint16_t)(pktPtr->length + crcfixup));
1352 
1353  // no support for anything but starting at 0
1354  assert(igbe->regs.rxcsum.pcss() == 0);
1355 
1356  DPRINTF(EthernetDesc, "Packet written to memory updating Descriptor\n");
1357 
1358  uint16_t status = RXDS_DD;
1359  uint8_t err = 0;
1360  uint16_t ext_err = 0;
1361  uint16_t csum = 0;
1362  uint16_t ptype = 0;
1363  uint16_t ip_id = 0;
1364 
1365  assert(bytesCopied <= pktPtr->length);
1366  if (bytesCopied == pktPtr->length)
1367  status |= RXDS_EOP;
1368 
1369  IpPtr ip(pktPtr);
1370  Ip6Ptr ip6(pktPtr);
1371 
1372  if (ip || ip6) {
1373  if (ip) {
1374  DPRINTF(EthernetDesc, "Proccesing Ip packet with Id=%d\n",
1375  ip->id());
1376  ptype |= RXDP_IPV4;
1377  ip_id = ip->id();
1378  }
1379  if (ip6)
1380  ptype |= RXDP_IPV6;
1381 
1382  if (ip && igbe->regs.rxcsum.ipofld()) {
1383  DPRINTF(EthernetDesc, "Checking IP checksum\n");
1384  status |= RXDS_IPCS;
1385  csum = htole(cksum(ip));
1386  igbe->rxIpChecksums++;
1387  if (cksum(ip) != 0) {
1388  err |= RXDE_IPE;
1389  ext_err |= RXDEE_IPE;
1390  DPRINTF(EthernetDesc, "Checksum is bad!!\n");
1391  }
1392  }
1393  TcpPtr tcp = ip ? TcpPtr(ip) : TcpPtr(ip6);
1394  if (tcp && igbe->regs.rxcsum.tuofld()) {
1395  DPRINTF(EthernetDesc, "Checking TCP checksum\n");
1396  status |= RXDS_TCPCS;
1397  ptype |= RXDP_TCP;
1398  csum = htole(cksum(tcp));
1399  igbe->rxTcpChecksums++;
1400  if (cksum(tcp) != 0) {
1401  DPRINTF(EthernetDesc, "Checksum is bad!!\n");
1402  err |= RXDE_TCPE;
1403  ext_err |= RXDEE_TCPE;
1404  }
1405  }
1406 
1407  UdpPtr udp = ip ? UdpPtr(ip) : UdpPtr(ip6);
1408  if (udp && igbe->regs.rxcsum.tuofld()) {
1409  DPRINTF(EthernetDesc, "Checking UDP checksum\n");
1410  status |= RXDS_UDPCS;
1411  ptype |= RXDP_UDP;
1412  csum = htole(cksum(udp));
1413  igbe->rxUdpChecksums++;
1414  if (cksum(udp) != 0) {
1415  DPRINTF(EthernetDesc, "Checksum is bad!!\n");
1416  ext_err |= RXDEE_TCPE;
1417  err |= RXDE_TCPE;
1418  }
1419  }
1420  } else { // if ip
1421  DPRINTF(EthernetSM, "Proccesing Non-Ip packet\n");
1422  }
1423 
1424  switch (igbe->regs.srrctl.desctype()) {
1425  case RXDT_LEGACY:
1426  desc->legacy.len = htole((uint16_t)(pktPtr->length + crcfixup));
1427  desc->legacy.status = htole(status);
1428  desc->legacy.errors = htole(err);
1429  // No vlan support at this point... just set it to 0
1430  desc->legacy.vlan = 0;
1431  break;
1432  case RXDT_ADV_SPLIT_A:
1433  case RXDT_ADV_ONEBUF:
1434  desc->adv_wb.rss_type = htole(0);
1435  desc->adv_wb.pkt_type = htole(ptype);
1436  if (igbe->regs.rxcsum.pcsd()) {
1437  // no rss support right now
1438  desc->adv_wb.rss_hash = htole(0);
1439  } else {
1440  desc->adv_wb.id = htole(ip_id);
1441  desc->adv_wb.csum = htole(csum);
1442  }
1443  desc->adv_wb.status = htole(status);
1444  desc->adv_wb.errors = htole(ext_err);
1445  // no vlan support
1446  desc->adv_wb.vlan_tag = htole(0);
1447  break;
1448  default:
1449  panic("Unimplemnted RX receive buffer type %d\n",
1450  igbe->regs.srrctl.desctype());
1451  }
1452 
1453  DPRINTF(EthernetDesc, "Descriptor complete w0: %#x w1: %#x\n",
1454  desc->adv_read.pkt, desc->adv_read.hdr);
1455 
1456  if (bytesCopied == pktPtr->length) {
1457  DPRINTF(EthernetDesc,
1458  "Packet completely written to descriptor buffers\n");
1459  // Deal with the rx timer interrupts
1460  if (igbe->regs.rdtr.delay()) {
1461  Tick delay = igbe->regs.rdtr.delay() * igbe->intClock();
1462  DPRINTF(EthernetSM, "RXS: Scheduling DTR for %d\n", delay);
1463  igbe->reschedule(igbe->rdtrEvent, curTick() + delay);
1464  }
1465 
1466  if (igbe->regs.radv.idv()) {
1467  Tick delay = igbe->regs.radv.idv() * igbe->intClock();
1468  DPRINTF(EthernetSM, "RXS: Scheduling ADV for %d\n", delay);
1469  if (!igbe->radvEvent.scheduled()) {
1470  igbe->schedule(igbe->radvEvent, curTick() + delay);
1471  }
1472  }
1473 
1474  // if neither radv or rdtr, maybe itr is set...
1475  if (!igbe->regs.rdtr.delay() && !igbe->regs.radv.idv()) {
1476  DPRINTF(EthernetSM,
1477  "RXS: Receive interrupt delay disabled, posting IT_RXT\n");
1479  }
1480 
1481  // If the packet is small enough, interrupt appropriately
1482  // I wonder if this is delayed or not?!
1483  if (pktPtr->length <= igbe->regs.rsrpd.idv()) {
1484  DPRINTF(EthernetSM,
1485  "RXS: Posting IT_SRPD beacuse small packet received\n");
1487  }
1488  bytesCopied = 0;
1489  }
1490 
1491  pktPtr = NULL;
1492  igbe->checkDrain();
1493  enableSm();
1494  pktDone = true;
1495 
1496  igbe->anBegin("RXS", "Done Updating Desc");
1497  DPRINTF(EthernetDesc, "Processing of this descriptor complete\n");
1498  igbe->anDq("RXS", annUnusedCacheQ);
1499  unusedCache.pop_front();
1500  igbe->anQ("RXS", annUsedCacheQ);
1501  usedCache.push_back(desc);
1502 }
1503 
1504 void
1506 {
1507  if (igbe->drainState() != DrainState::Draining) {
1508  igbe->rxTick = true;
1509  igbe->restartClock();
1510  }
1511 }
1512 
1513 bool
1515 {
1516  if (pktDone) {
1517  pktDone = false;
1518  return true;
1519  }
1520  return false;
1521 }
1522 
1523 bool
1525 {
1526  return pktEvent.scheduled() || wbEvent.scheduled() ||
1529 
1530 }
1531 
1532 void
1534 {
1539 }
1540 
1541 void
1543 {
1548 }
1549 
1550 
1552 
1553 IGbE::TxDescCache::TxDescCache(IGbE *i, const std::string n, int s)
1554  : DescCache<TxDesc>(i,n, s), pktDone(false), isTcp(false),
1555  pktWaiting(false), pktMultiDesc(false),
1556  completionAddress(0), completionEnabled(false),
1557  useTso(false), tsoHeaderLen(0), tsoMss(0), tsoTotalLen(0), tsoUsedLen(0),
1558  tsoPrevSeq(0), tsoPktPayloadBytes(0), tsoLoadedHeader(false),
1559  tsoPktHasHeader(false), tsoDescBytesUsed(0), tsoCopyBytes(0), tsoPkts(0),
1560  pktEvent([this]{ pktComplete(); }, n),
1561  headerEvent([this]{ headerComplete(); }, n),
1562  nullEvent([this]{ nullCallback(); }, n)
1563 {
1564  annSmFetch = "TX Desc Fetch";
1565  annSmWb = "TX Desc Writeback";
1566  annUnusedDescQ = "TX Unused Descriptors";
1567  annUnusedCacheQ = "TX Unused Descriptor Cache";
1568  annUsedCacheQ = "TX Used Descriptor Cache";
1569  annUsedDescQ = "TX Used Descriptors";
1570  annDescQ = "TX Descriptors";
1571 }
1572 
1573 void
1575 {
1576  assert(unusedCache.size());
1577  TxDesc *desc;
1578 
1579  DPRINTF(EthernetDesc, "Checking and processing context descriptors\n");
1580 
1581  while (!useTso && unusedCache.size() &&
1582  TxdOp::isContext(unusedCache.front())) {
1583  DPRINTF(EthernetDesc, "Got context descriptor type...\n");
1584 
1585  desc = unusedCache.front();
1586  DPRINTF(EthernetDesc, "Descriptor upper: %#x lower: %#X\n",
1587  desc->d1, desc->d2);
1588 
1589 
1590  // is this going to be a tcp or udp packet?
1591  isTcp = TxdOp::tcp(desc) ? true : false;
1592 
1593  // setup all the TSO variables, they'll be ignored if we don't use
1594  // tso for this connection
1595  tsoHeaderLen = TxdOp::hdrlen(desc);
1596  tsoMss = TxdOp::mss(desc);
1597 
1598  if (TxdOp::isType(desc, TxdOp::TXD_CNXT) && TxdOp::tse(desc)) {
1599  DPRINTF(EthernetDesc, "TCP offload enabled for packet hdrlen: "
1600  "%d mss: %d paylen %d\n", TxdOp::hdrlen(desc),
1601  TxdOp::mss(desc), TxdOp::getLen(desc));
1602  useTso = true;
1603  tsoTotalLen = TxdOp::getLen(desc);
1604  tsoLoadedHeader = false;
1605  tsoDescBytesUsed = 0;
1606  tsoUsedLen = 0;
1607  tsoPrevSeq = 0;
1608  tsoPktHasHeader = false;
1609  tsoPkts = 0;
1610  tsoCopyBytes = 0;
1611  }
1612 
1613  TxdOp::setDd(desc);
1614  unusedCache.pop_front();
1615  igbe->anDq("TXS", annUnusedCacheQ);
1616  usedCache.push_back(desc);
1617  igbe->anQ("TXS", annUsedCacheQ);
1618  }
1619 
1620  if (!unusedCache.size())
1621  return;
1622 
1623  desc = unusedCache.front();
1624  if (!useTso && TxdOp::isType(desc, TxdOp::TXD_ADVDATA) &&
1625  TxdOp::tse(desc)) {
1626  DPRINTF(EthernetDesc, "TCP offload(adv) enabled for packet "
1627  "hdrlen: %d mss: %d paylen %d\n",
1629  useTso = true;
1630  tsoTotalLen = TxdOp::getTsoLen(desc);
1631  tsoLoadedHeader = false;
1632  tsoDescBytesUsed = 0;
1633  tsoUsedLen = 0;
1634  tsoPrevSeq = 0;
1635  tsoPktHasHeader = false;
1636  tsoPkts = 0;
1637  }
1638 
1639  if (useTso && !tsoLoadedHeader) {
1640  // we need to fetch a header
1641  DPRINTF(EthernetDesc, "Starting DMA of TSO header\n");
1642  assert(TxdOp::isData(desc) && TxdOp::getLen(desc) >= tsoHeaderLen);
1643  pktWaiting = true;
1644  assert(tsoHeaderLen <= 256);
1647  }
1648 }
1649 
1650 void
1652 {
1653  DPRINTF(EthernetDesc, "TSO: Fetching TSO header complete\n");
1654  pktWaiting = false;
1655 
1656  assert(unusedCache.size());
1657  TxDesc *desc = unusedCache.front();
1658  DPRINTF(EthernetDesc, "TSO: len: %d tsoHeaderLen: %d\n",
1659  TxdOp::getLen(desc), tsoHeaderLen);
1660 
1661  if (TxdOp::getLen(desc) == tsoHeaderLen) {
1662  tsoDescBytesUsed = 0;
1663  tsoLoadedHeader = true;
1664  unusedCache.pop_front();
1665  usedCache.push_back(desc);
1666  } else {
1667  DPRINTF(EthernetDesc, "TSO: header part of larger payload\n");
1669  tsoLoadedHeader = true;
1670  }
1671  enableSm();
1672  igbe->checkDrain();
1673 }
1674 
1675 unsigned
1677 {
1678  if (!unusedCache.size())
1679  return 0;
1680 
1681  DPRINTF(EthernetDesc, "Starting processing of descriptor\n");
1682 
1683  assert(!useTso || tsoLoadedHeader);
1684  TxDesc *desc = unusedCache.front();
1685 
1686  if (useTso) {
1687  DPRINTF(EthernetDesc, "getPacket(): TxDescriptor data "
1688  "d1: %#llx d2: %#llx\n", desc->d1, desc->d2);
1689  DPRINTF(EthernetDesc, "TSO: use: %d hdrlen: %d mss: %d total: %d "
1690  "used: %d loaded hdr: %d\n", useTso, tsoHeaderLen, tsoMss,
1692 
1693  if (tsoPktHasHeader)
1694  tsoCopyBytes = std::min((tsoMss + tsoHeaderLen) - p->length,
1696  else
1697  tsoCopyBytes = std::min(tsoMss,
1699  unsigned pkt_size =
1701 
1702  DPRINTF(EthernetDesc, "TSO: descBytesUsed: %d copyBytes: %d "
1703  "this descLen: %d\n",
1705  DPRINTF(EthernetDesc, "TSO: pktHasHeader: %d\n", tsoPktHasHeader);
1706  DPRINTF(EthernetDesc, "TSO: Next packet is %d bytes\n", pkt_size);
1707  return pkt_size;
1708  }
1709 
1710  DPRINTF(EthernetDesc, "Next TX packet is %d bytes\n",
1711  TxdOp::getLen(unusedCache.front()));
1712  return TxdOp::getLen(desc);
1713 }
1714 
1715 void
1717 {
1718  assert(unusedCache.size());
1719 
1720  TxDesc *desc;
1721  desc = unusedCache.front();
1722 
1723  DPRINTF(EthernetDesc, "getPacketData(): TxDescriptor data "
1724  "d1: %#llx d2: %#llx\n", desc->d1, desc->d2);
1725  assert((TxdOp::isLegacy(desc) || TxdOp::isData(desc)) &&
1726  TxdOp::getLen(desc));
1727 
1728  pktPtr = p;
1729 
1730  pktWaiting = true;
1731 
1732  DPRINTF(EthernetDesc, "Starting DMA of packet at offset %d\n", p->length);
1733 
1734  if (useTso) {
1735  assert(tsoLoadedHeader);
1736  if (!tsoPktHasHeader) {
1737  DPRINTF(EthernetDesc,
1738  "Loading TSO header (%d bytes) into start of packet\n",
1739  tsoHeaderLen);
1740  memcpy(p->data, &tsoHeader,tsoHeaderLen);
1741  p->length +=tsoHeaderLen;
1742  tsoPktHasHeader = true;
1743  }
1744  }
1745 
1746  if (useTso) {
1747  DPRINTF(EthernetDesc,
1748  "Starting DMA of packet at offset %d length: %d\n",
1749  p->length, tsoCopyBytes);
1751  + tsoDescBytesUsed,
1752  tsoCopyBytes, &pktEvent, p->data + p->length,
1753  igbe->txReadDelay);
1755  assert(tsoDescBytesUsed <= TxdOp::getLen(desc));
1756  } else {
1758  TxdOp::getLen(desc), &pktEvent, p->data + p->length,
1759  igbe->txReadDelay);
1760  }
1761 }
1762 
1763 void
1765 {
1766 
1767  TxDesc *desc;
1768  assert(unusedCache.size());
1769  assert(pktPtr);
1770 
1771  igbe->anBegin("TXS", "Update Desc");
1772 
1773  DPRINTF(EthernetDesc, "DMA of packet complete\n");
1774 
1775 
1776  desc = unusedCache.front();
1777  assert((TxdOp::isLegacy(desc) || TxdOp::isData(desc)) &&
1778  TxdOp::getLen(desc));
1779 
1780  DPRINTF(EthernetDesc, "TxDescriptor data d1: %#llx d2: %#llx\n",
1781  desc->d1, desc->d2);
1782 
1783  // Set the length of the data in the EtherPacket
1784  if (useTso) {
1785  DPRINTF(EthernetDesc, "TSO: use: %d hdrlen: %d mss: %d total: %d "
1786  "used: %d loaded hdr: %d\n", useTso, tsoHeaderLen, tsoMss,
1788  pktPtr->simLength += tsoCopyBytes;
1789  pktPtr->length += tsoCopyBytes;
1791  DPRINTF(EthernetDesc, "TSO: descBytesUsed: %d copyBytes: %d\n",
1793  } else {
1794  pktPtr->simLength += TxdOp::getLen(desc);
1795  pktPtr->length += TxdOp::getLen(desc);
1796  }
1797 
1798 
1799 
1800  if ((!TxdOp::eop(desc) && !useTso) ||
1801  (pktPtr->length < ( tsoMss + tsoHeaderLen) &&
1802  tsoTotalLen != tsoUsedLen && useTso)) {
1803  assert(!useTso || (tsoDescBytesUsed == TxdOp::getLen(desc)));
1804  igbe->anDq("TXS", annUnusedCacheQ);
1805  unusedCache.pop_front();
1806  igbe->anQ("TXS", annUsedCacheQ);
1807  usedCache.push_back(desc);
1808 
1809  tsoDescBytesUsed = 0;
1810  pktDone = true;
1811  pktWaiting = false;
1812  pktMultiDesc = true;
1813 
1814  DPRINTF(EthernetDesc, "Partial Packet Descriptor of %d bytes Done\n",
1815  pktPtr->length);
1816  pktPtr = NULL;
1817 
1818  enableSm();
1819  igbe->checkDrain();
1820  return;
1821  }
1822 
1823 
1824  pktMultiDesc = false;
1825  // no support for vlans
1826  assert(!TxdOp::vle(desc));
1827 
1828  // we only support single packet descriptors at this point
1829  if (!useTso)
1830  assert(TxdOp::eop(desc));
1831 
1832  // set that this packet is done
1833  if (TxdOp::rs(desc))
1834  TxdOp::setDd(desc);
1835 
1836  DPRINTF(EthernetDesc, "TxDescriptor data d1: %#llx d2: %#llx\n",
1837  desc->d1, desc->d2);
1838 
1839  if (useTso) {
1840  IpPtr ip(pktPtr);
1841  Ip6Ptr ip6(pktPtr);
1842  if (ip) {
1843  DPRINTF(EthernetDesc, "TSO: Modifying IP header. Id + %d\n",
1844  tsoPkts);
1845  ip->id(ip->id() + tsoPkts++);
1846  ip->len(pktPtr->length - EthPtr(pktPtr)->size());
1847  }
1848  if (ip6)
1849  ip6->plen(pktPtr->length - EthPtr(pktPtr)->size());
1850  TcpPtr tcp = ip ? TcpPtr(ip) : TcpPtr(ip6);
1851  if (tcp) {
1852  DPRINTF(EthernetDesc,
1853  "TSO: Modifying TCP header. old seq %d + %d\n",
1854  tcp->seq(), tsoPrevSeq);
1855  tcp->seq(tcp->seq() + tsoPrevSeq);
1856  if (tsoUsedLen != tsoTotalLen)
1857  tcp->flags(tcp->flags() & ~9); // clear fin & psh
1858  }
1859  UdpPtr udp = ip ? UdpPtr(ip) : UdpPtr(ip6);
1860  if (udp) {
1861  DPRINTF(EthernetDesc, "TSO: Modifying UDP header.\n");
1862  udp->len(pktPtr->length - EthPtr(pktPtr)->size());
1863  }
1865  }
1866 
1867  if (DTRACE(EthernetDesc)) {
1868  IpPtr ip(pktPtr);
1869  if (ip)
1870  DPRINTF(EthernetDesc, "Proccesing Ip packet with Id=%d\n",
1871  ip->id());
1872  else
1873  DPRINTF(EthernetSM, "Proccesing Non-Ip packet\n");
1874  }
1875 
1876  // Checksums are only ofloaded for new descriptor types
1877  if (TxdOp::isData(desc) && (TxdOp::ixsm(desc) || TxdOp::txsm(desc))) {
1878  DPRINTF(EthernetDesc, "Calculating checksums for packet\n");
1879  IpPtr ip(pktPtr);
1880  Ip6Ptr ip6(pktPtr);
1881  assert(ip || ip6);
1882  if (ip && TxdOp::ixsm(desc)) {
1883  ip->sum(0);
1884  ip->sum(cksum(ip));
1885  igbe->txIpChecksums++;
1886  DPRINTF(EthernetDesc, "Calculated IP checksum\n");
1887  }
1888  if (TxdOp::txsm(desc)) {
1889  TcpPtr tcp = ip ? TcpPtr(ip) : TcpPtr(ip6);
1890  UdpPtr udp = ip ? UdpPtr(ip) : UdpPtr(ip6);
1891  if (tcp) {
1892  tcp->sum(0);
1893  tcp->sum(cksum(tcp));
1894  igbe->txTcpChecksums++;
1895  DPRINTF(EthernetDesc, "Calculated TCP checksum\n");
1896  } else if (udp) {
1897  assert(udp);
1898  udp->sum(0);
1899  udp->sum(cksum(udp));
1900  igbe->txUdpChecksums++;
1901  DPRINTF(EthernetDesc, "Calculated UDP checksum\n");
1902  } else {
1903  panic("Told to checksum, but don't know how\n");
1904  }
1905  }
1906  }
1907 
1908  if (TxdOp::ide(desc)) {
1909  // Deal with the rx timer interrupts
1910  DPRINTF(EthernetDesc, "Descriptor had IDE set\n");
1911  if (igbe->regs.tidv.idv()) {
1912  Tick delay = igbe->regs.tidv.idv() * igbe->intClock();
1913  DPRINTF(EthernetDesc, "setting tidv\n");
1914  igbe->reschedule(igbe->tidvEvent, curTick() + delay, true);
1915  }
1916 
1917  if (igbe->regs.tadv.idv() && igbe->regs.tidv.idv()) {
1918  Tick delay = igbe->regs.tadv.idv() * igbe->intClock();
1919  DPRINTF(EthernetDesc, "setting tadv\n");
1920  if (!igbe->tadvEvent.scheduled()) {
1921  igbe->schedule(igbe->tadvEvent, curTick() + delay);
1922  }
1923  }
1924  }
1925 
1926 
1927  if (!useTso || TxdOp::getLen(desc) == tsoDescBytesUsed) {
1928  DPRINTF(EthernetDesc, "Descriptor Done\n");
1929  igbe->anDq("TXS", annUnusedCacheQ);
1930  unusedCache.pop_front();
1931  igbe->anQ("TXS", annUsedCacheQ);
1932  usedCache.push_back(desc);
1933  tsoDescBytesUsed = 0;
1934  }
1935 
1936  if (useTso && tsoUsedLen == tsoTotalLen)
1937  useTso = false;
1938 
1939 
1940  DPRINTF(EthernetDesc,
1941  "------Packet of %d bytes ready for transmission-------\n",
1942  pktPtr->length);
1943  pktDone = true;
1944  pktWaiting = false;
1945  pktPtr = NULL;
1946  tsoPktHasHeader = false;
1947 
1948  if (igbe->regs.txdctl.wthresh() == 0) {
1949  igbe->anBegin("TXS", "Desc Writeback");
1950  DPRINTF(EthernetDesc, "WTHRESH == 0, writing back descriptor\n");
1951  writeback(0);
1952  } else if (!igbe->regs.txdctl.gran() && igbe->regs.txdctl.wthresh() <=
1953  descInBlock(usedCache.size())) {
1954  DPRINTF(EthernetDesc, "used > WTHRESH, writing back descriptor\n");
1955  igbe->anBegin("TXS", "Desc Writeback");
1956  writeback((igbe->cacheBlockSize()-1)>>4);
1957  } else if (igbe->regs.txdctl.wthresh() <= usedCache.size()) {
1958  DPRINTF(EthernetDesc, "used > WTHRESH, writing back descriptor\n");
1959  igbe->anBegin("TXS", "Desc Writeback");
1960  writeback((igbe->cacheBlockSize()-1)>>4);
1961  }
1962 
1963  enableSm();
1964  igbe->checkDrain();
1965 }
1966 
1967 void
1969 {
1970  DPRINTF(EthernetDesc, "actionAfterWb() completionEnabled: %d\n",
1973  if (completionEnabled) {
1974  descEnd = igbe->regs.tdh();
1975  DPRINTF(EthernetDesc,
1976  "Completion writing back value: %d to addr: %#x\n", descEnd,
1979  sizeof(descEnd), &nullEvent, (uint8_t*)&descEnd, 0);
1980  }
1981 }
1982 
1983 void
1985 {
1987 
1992 
2002  SERIALIZE_ARRAY(tsoHeader, 256);
2006 
2010 }
2011 
2012 void
2014 {
2016 
2021 
2035 
2039 }
2040 
2041 bool
2043 {
2044  if (pktDone) {
2045  pktDone = false;
2046  return true;
2047  }
2048  return false;
2049 }
2050 
2051 void
2053 {
2054  if (igbe->drainState() != DrainState::Draining) {
2055  igbe->txTick = true;
2056  igbe->restartClock();
2057  }
2058 }
2059 
2060 bool
2062 {
2063  return pktEvent.scheduled() || wbEvent.scheduled() ||
2065 }
2066 
2067 
2069 
2070 void
2072 {
2073  if (!tickEvent.scheduled() && (rxTick || txTick || txFifoTick) &&
2076 }
2077 
2078 DrainState
2080 {
2081  unsigned int count(0);
2084  count++;
2085  }
2086 
2087  txFifoTick = false;
2088  txTick = false;
2089  rxTick = false;
2090 
2091  if (tickEvent.scheduled())
2093 
2094  if (count) {
2095  DPRINTF(Drain, "IGbE not drained\n");
2096  return DrainState::Draining;
2097  } else
2098  return DrainState::Drained;
2099 }
2100 
2101 void
2103 {
2105 
2106  txFifoTick = true;
2107  txTick = true;
2108  rxTick = true;
2109 
2110  restartClock();
2111  DPRINTF(EthernetSM, "resuming from drain");
2112 }
2113 
2114 void
2116 {
2118  return;
2119 
2120  txFifoTick = false;
2121  txTick = false;
2122  rxTick = false;
2125  DPRINTF(Drain, "IGbE done draining, processing drain event\n");
2126  signalDrainDone();
2127  }
2128 }
2129 
2130 void
2132 {
2133  if (!regs.tctl.en()) {
2134  txTick = false;
2135  DPRINTF(EthernetSM, "TXS: TX disabled, stopping ticking\n");
2136  return;
2137  }
2138 
2139  // If we have a packet available and it's length is not 0 (meaning it's not
2140  // a multidescriptor packet) put it in the fifo, otherwise an the next
2141  // iteration we'll get the rest of the data
2143  && !txDescCache.packetMultiDesc() && txPacket->length) {
2144  anQ("TXS", "TX FIFO Q");
2145  DPRINTF(EthernetSM, "TXS: packet placed in TX FIFO\n");
2146 #ifndef NDEBUG
2147  bool success =
2148 #endif
2149  txFifo.push(txPacket);
2151  assert(success);
2152  txPacket = NULL;
2153  anBegin("TXS", "Desc Writeback");
2155  return;
2156  }
2157 
2158  // Only support descriptor granularity
2159  if (regs.txdctl.lwthresh() &&
2160  txDescCache.descLeft() < (regs.txdctl.lwthresh() * 8)) {
2161  DPRINTF(EthernetSM, "TXS: LWTHRESH caused posting of TXDLOW\n");
2163  }
2164 
2165  if (!txPacket) {
2166  txPacket = std::make_shared<EthPacketData>(16384);
2167  }
2168 
2169  if (!txDescCache.packetWaiting()) {
2170  if (txDescCache.descLeft() == 0) {
2172  anBegin("TXS", "Desc Writeback");
2174  anBegin("TXS", "Desc Fetch");
2177  DPRINTF(EthernetSM, "TXS: No descriptors left in ring, forcing "
2178  "writeback stopping ticking and posting TXQE\n");
2179  txTick = false;
2180  return;
2181  }
2182 
2183 
2184  if (!(txDescCache.descUnused())) {
2185  anBegin("TXS", "Desc Fetch");
2188  DPRINTF(EthernetSM, "TXS: No descriptors available in cache, "
2189  "fetching and stopping ticking\n");
2190  txTick = false;
2191  return;
2192  }
2194 
2195 
2197  if (txDescCache.packetWaiting()) {
2198  DPRINTF(EthernetSM,
2199  "TXS: Fetching TSO header, stopping ticking\n");
2200  txTick = false;
2201  return;
2202  }
2203 
2204  unsigned size = txDescCache.getPacketSize(txPacket);
2205  if (size > 0 && txFifo.avail() > size) {
2206  anRq("TXS", "TX FIFO Q");
2207  anBegin("TXS", "DMA Packet");
2208  DPRINTF(EthernetSM, "TXS: Reserving %d bytes in FIFO and "
2209  "beginning DMA of next packet\n", size);
2210  txFifo.reserve(size);
2212  } else if (size == 0) {
2213  DPRINTF(EthernetSM, "TXS: getPacketSize returned: %d\n", size);
2214  DPRINTF(EthernetSM,
2215  "TXS: No packets to get, writing back used descriptors\n");
2216  anBegin("TXS", "Desc Writeback");
2218  } else {
2219  anWf("TXS", "TX FIFO Q");
2220  DPRINTF(EthernetSM, "TXS: FIFO full, stopping ticking until space "
2221  "available in FIFO\n");
2222  txTick = false;
2223  }
2224 
2225 
2226  return;
2227  }
2228  DPRINTF(EthernetSM, "TXS: Nothing to do, stopping ticking\n");
2229  txTick = false;
2230 }
2231 
2232 bool
2234 {
2235  rxBytes += pkt->length;
2236  rxPackets++;
2237 
2238  DPRINTF(Ethernet, "RxFIFO: Receiving pcakte from wire\n");
2239  anBegin("RXQ", "Wire Recv");
2240 
2241 
2242  if (!regs.rctl.en()) {
2243  DPRINTF(Ethernet, "RxFIFO: RX not enabled, dropping\n");
2244  anBegin("RXQ", "FIFO Drop", CPA::FL_BAD);
2245  return true;
2246  }
2247 
2248  // restart the state machines if they are stopped
2249  rxTick = true && drainState() != DrainState::Draining;
2250  if ((rxTick || txTick) && !tickEvent.scheduled()) {
2251  DPRINTF(EthernetSM,
2252  "RXS: received packet into fifo, starting ticking\n");
2253  restartClock();
2254  }
2255 
2256  if (!rxFifo.push(pkt)) {
2257  DPRINTF(Ethernet, "RxFIFO: Packet won't fit in fifo... dropped\n");
2258  postInterrupt(IT_RXO, true);
2259  anBegin("RXQ", "FIFO Drop", CPA::FL_BAD);
2260  return false;
2261  }
2262 
2263  if (CPA::available() && cpa->enabled()) {
2264  assert(sys->numSystemsRunning <= 2);
2265  System *other_sys;
2266  if (sys->systemList[0] == sys)
2267  other_sys = sys->systemList[1];
2268  else
2269  other_sys = sys->systemList[0];
2270 
2271  cpa->hwDq(CPA::FL_NONE, sys, macAddr, "RXQ", "WireQ", 0, other_sys);
2272  anQ("RXQ", "RX FIFO Q");
2273  cpa->hwWe(CPA::FL_NONE, sys, macAddr, "RXQ", "WireQ", 0, other_sys);
2274  }
2275 
2276  return true;
2277 }
2278 
2279 
2280 void
2282 {
2283  if (!regs.rctl.en()) {
2284  rxTick = false;
2285  DPRINTF(EthernetSM, "RXS: RX disabled, stopping ticking\n");
2286  return;
2287  }
2288 
2289  // If the packet is done check for interrupts/descriptors/etc
2290  if (rxDescCache.packetDone()) {
2291  rxDmaPacket = false;
2292  DPRINTF(EthernetSM, "RXS: Packet completed DMA to memory\n");
2293  int descLeft = rxDescCache.descLeft();
2294  DPRINTF(EthernetSM, "RXS: descLeft: %d rdmts: %d rdlen: %d\n",
2295  descLeft, regs.rctl.rdmts(), regs.rdlen());
2296 
2297  // rdmts 2->1/8, 1->1/4, 0->1/2
2298  int ratio = (1ULL << (regs.rctl.rdmts() + 1));
2299  if (descLeft * ratio <= regs.rdlen()) {
2300  DPRINTF(Ethernet, "RXS: Interrupting (RXDMT) "
2301  "because of descriptors left\n");
2303  }
2304 
2305  if (rxFifo.empty())
2307 
2308  if (descLeft == 0) {
2309  anBegin("RXS", "Writeback Descriptors");
2311  DPRINTF(EthernetSM, "RXS: No descriptors left in ring, forcing"
2312  " writeback and stopping ticking\n");
2313  rxTick = false;
2314  }
2315 
2316  // only support descriptor granulaties
2317  assert(regs.rxdctl.gran());
2318 
2319  if (regs.rxdctl.wthresh() >= rxDescCache.descUsed()) {
2320  DPRINTF(EthernetSM,
2321  "RXS: Writing back because WTHRESH >= descUsed\n");
2322  anBegin("RXS", "Writeback Descriptors");
2323  if (regs.rxdctl.wthresh() < (cacheBlockSize()>>4))
2324  rxDescCache.writeback(regs.rxdctl.wthresh()-1);
2325  else
2327  }
2328 
2329  if ((rxDescCache.descUnused() < regs.rxdctl.pthresh()) &&
2331  regs.rxdctl.hthresh())) {
2332  DPRINTF(EthernetSM, "RXS: Fetching descriptors because "
2333  "descUnused < PTHRESH\n");
2334  anBegin("RXS", "Fetch Descriptors");
2336  }
2337 
2338  if (rxDescCache.descUnused() == 0) {
2339  anBegin("RXS", "Fetch Descriptors");
2342  DPRINTF(EthernetSM, "RXS: No descriptors available in cache, "
2343  "fetching descriptors and stopping ticking\n");
2344  rxTick = false;
2345  }
2346  return;
2347  }
2348 
2349  if (rxDmaPacket) {
2350  DPRINTF(EthernetSM,
2351  "RXS: stopping ticking until packet DMA completes\n");
2352  rxTick = false;
2353  return;
2354  }
2355 
2356  if (!rxDescCache.descUnused()) {
2357  anBegin("RXS", "Fetch Descriptors");
2360  DPRINTF(EthernetSM, "RXS: No descriptors available in cache, "
2361  "stopping ticking\n");
2362  rxTick = false;
2363  DPRINTF(EthernetSM, "RXS: No descriptors available, fetching\n");
2364  return;
2365  }
2367 
2368  if (rxFifo.empty()) {
2369  anWe("RXS", "RX FIFO Q");
2370  DPRINTF(EthernetSM, "RXS: RxFIFO empty, stopping ticking\n");
2371  rxTick = false;
2372  return;
2373  }
2374  anPq("RXS", "RX FIFO Q");
2375  anBegin("RXS", "Get Desc");
2376 
2377  EthPacketPtr pkt;
2378  pkt = rxFifo.front();
2379 
2380 
2382  DPRINTF(EthernetSM, "RXS: Writing packet into memory\n");
2383  if (pktOffset == pkt->length) {
2384  anBegin( "RXS", "FIFO Dequeue");
2385  DPRINTF(EthernetSM, "RXS: Removing packet from FIFO\n");
2386  pktOffset = 0;
2387  anDq("RXS", "RX FIFO Q");
2388  rxFifo.pop();
2389  }
2390 
2391  DPRINTF(EthernetSM, "RXS: stopping ticking until packet DMA completes\n");
2392  rxTick = false;
2393  rxDmaPacket = true;
2394  anBegin("RXS", "DMA Packet");
2395 }
2396 
2397 void
2399 {
2400  txFifoTick = false;
2401 
2402  if (txFifo.empty()) {
2403  anWe("TXQ", "TX FIFO Q");
2404  return;
2405  }
2406 
2407 
2408  anPq("TXQ", "TX FIFO Q");
2409  if (etherInt->sendPacket(txFifo.front())) {
2410  anQ("TXQ", "WireQ");
2411  if (DTRACE(EthernetSM)) {
2412  IpPtr ip(txFifo.front());
2413  if (ip)
2414  DPRINTF(EthernetSM, "Transmitting Ip packet with Id=%d\n",
2415  ip->id());
2416  else
2417  DPRINTF(EthernetSM, "Transmitting Non-Ip packet\n");
2418  }
2419  anDq("TXQ", "TX FIFO Q");
2420  anBegin("TXQ", "Wire Send");
2421  DPRINTF(EthernetSM,
2422  "TxFIFO: Successful transmit, bytes available in fifo: %d\n",
2423  txFifo.avail());
2424 
2425  txBytes += txFifo.front()->length;
2426  txPackets++;
2427 
2428  txFifo.pop();
2429  }
2430 }
2431 
2432 void
2434 {
2435  DPRINTF(EthernetSM, "IGbE: -------------- Cycle --------------\n");
2436 
2437  inTick = true;
2438 
2439  if (rxTick)
2440  rxStateMachine();
2441 
2442  if (txTick)
2443  txStateMachine();
2444 
2445  // If txWire returns and txFifoTick is still set, that means the data we
2446  // sent to the other end was already accepted and we can send another
2447  // frame right away. This is consistent with the previous behavior which
2448  // would send another frame if one was ready in ethTxDone. This version
2449  // avoids growing the stack with each frame sent which can cause stack
2450  // overflow.
2451  while (txFifoTick)
2452  txWire();
2453 
2454  if (rxTick || txTick || txFifoTick)
2456 
2457  inTick = false;
2458 }
2459 
2460 void
2462 {
2463  anBegin("TXQ", "Send Done");
2464  // restart the tx state machines if they are stopped
2465  // fifo to send another packet
2466  // tx sm to put more data into the fifo
2469  txTick = true;
2470 
2471  if (!inTick)
2472  restartClock();
2473  DPRINTF(EthernetSM, "TxFIFO: Transmission complete\n");
2474 }
2475 
2476 void
2478 {
2480 
2481  regs.serialize(cp);
2489 
2490  rxFifo.serialize("rxfifo", cp);
2491  txFifo.serialize("txfifo", cp);
2492 
2493  bool txPktExists = txPacket != nullptr;
2494  SERIALIZE_SCALAR(txPktExists);
2495  if (txPktExists)
2496  txPacket->serialize("txpacket", cp);
2497 
2498  Tick rdtr_time = 0, radv_time = 0, tidv_time = 0, tadv_time = 0,
2499  inter_time = 0;
2500 
2501  if (rdtrEvent.scheduled())
2502  rdtr_time = rdtrEvent.when();
2503  SERIALIZE_SCALAR(rdtr_time);
2504 
2505  if (radvEvent.scheduled())
2506  radv_time = radvEvent.when();
2507  SERIALIZE_SCALAR(radv_time);
2508 
2509  if (tidvEvent.scheduled())
2510  tidv_time = tidvEvent.when();
2511  SERIALIZE_SCALAR(tidv_time);
2512 
2513  if (tadvEvent.scheduled())
2514  tadv_time = tadvEvent.when();
2515  SERIALIZE_SCALAR(tadv_time);
2516 
2517  if (interEvent.scheduled())
2518  inter_time = interEvent.when();
2519  SERIALIZE_SCALAR(inter_time);
2520 
2522 
2523  txDescCache.serializeSection(cp, "TxDescCache");
2524  rxDescCache.serializeSection(cp, "RxDescCache");
2525 }
2526 
2527 void
2529 {
2531 
2532  regs.unserialize(cp);
2540 
2541  rxFifo.unserialize("rxfifo", cp);
2542  txFifo.unserialize("txfifo", cp);
2543 
2544  bool txPktExists;
2545  UNSERIALIZE_SCALAR(txPktExists);
2546  if (txPktExists) {
2547  txPacket = std::make_shared<EthPacketData>(16384);
2548  txPacket->unserialize("txpacket", cp);
2549  }
2550 
2551  rxTick = true;
2552  txTick = true;
2553  txFifoTick = true;
2554 
2555  Tick rdtr_time, radv_time, tidv_time, tadv_time, inter_time;
2556  UNSERIALIZE_SCALAR(rdtr_time);
2557  UNSERIALIZE_SCALAR(radv_time);
2558  UNSERIALIZE_SCALAR(tidv_time);
2559  UNSERIALIZE_SCALAR(tadv_time);
2560  UNSERIALIZE_SCALAR(inter_time);
2561 
2562  if (rdtr_time)
2563  schedule(rdtrEvent, rdtr_time);
2564 
2565  if (radv_time)
2566  schedule(radvEvent, radv_time);
2567 
2568  if (tidv_time)
2569  schedule(tidvEvent, tidv_time);
2570 
2571  if (tadv_time)
2572  schedule(tadvEvent, tadv_time);
2573 
2574  if (inter_time)
2575  schedule(interEvent, inter_time);
2576 
2578 
2579  txDescCache.unserializeSection(cp, "TxDescCache");
2580  rxDescCache.unserializeSection(cp, "RxDescCache");
2581 }
2582 
2583 IGbE *
2584 IGbEParams::create()
2585 {
2586  return new IGbE(this);
2587 }
count
Definition: misc.hh:703
EventFunctionWrapper interEvent
Definition: i8254xGBe.hh:158
const uint32_t REG_VFTA
#define panic(...)
This implements a cprintf based panic() function.
Definition: logging.hh:163
const uint32_t REG_IMC
const uint8_t MULTICAST_TABLE_SIZE
#define DPRINTF(x,...)
Definition: trace.hh:225
void anQ(std::string sm, std::string q)
Definition: i8254xGBe.hh:180
EventFunctionWrapper pktHdrEvent
Definition: i8254xGBe.hh:385
uint16_t plen() const
Definition: inet.hh:362
EthPacketPtr front()
Definition: pktfifo.hh:118
Ports are used to interface objects to each other.
Definition: port.hh:56
void hwDq(flags f, System *sys, uint64_t frame, std::string sm, std::string q, uint64_t qid, System *q_sys=NULL, int32_t count=1)
Definition: cp_annotate.hh:119
void processContextDesc()
Definition: i8254xGBe.cc:1574
const uint16_t RXDEE_TCPE
Addr getLen(TxDesc *d)
TxDescCache txDescCache
Definition: i8254xGBe.hh:507
const uint32_t REG_TADV
void pktComplete()
Called by event when dma to write packet is completed.
Definition: i8254xGBe.cc:1338
const uint32_t REG_CRCERRS
IGbEInt * etherInt
Definition: i8254xGBe.hh:57
const uint32_t REG_FCAL
const uint8_t RCV_ADDRESS_TABLE_SIZE
unsigned descUnused() const
Definition: i8254xGBe.hh:319
unsigned pktOffset
Definition: i8254xGBe.hh:84
const uint32_t REG_TDT
Cycles is a wrapper class for representing cycle counts, i.e.
Definition: types.hh:81
void unserialize(CheckpointIn &cp) override
Reconstruct the state of this object from a checkpoint.
Definition: device.cc:507
static bool available()
Definition: cp_annotate.hh:83
uint64_t macAddr
Definition: i8254xGBe.hh:135
void rdtrProcess()
Definition: i8254xGBe.hh:92
void txStateMachine()
Definition: i8254xGBe.cc:2131
const uint32_t REG_ICR
virtual void drainResume()
Resume execution after a successful drain.
Definition: drain.hh:277
uint16_t id() const
Definition: inet.hh:254
void unserialize(const std::string &base, CheckpointIn &cp)
Definition: pktfifo.cc:99
const uint8_t PHY_GSTATUS
Bitfield< 7 > i
void setDd(TxDesc *d)
unsigned descInBlock(unsigned num_desc)
Return the number of dsecriptors in a cache block for threshold operations.
Definition: i8254xGBe.hh:453
uint16_t sum() const
Definition: inet.hh:513
uint32_t sw_fw_sync
Addr getBuf(TxDesc *d)
void dmaWrite(Addr addr, int size, Event *event, uint8_t *data, uint32_t sid, uint32_t ssid, Tick delay=0)
Definition: dma_device.hh:175
void chkInterrupt()
Check and see if changes to the mask register have caused an interrupt to need to be sent or perhaps ...
Definition: i8254xGBe.cc:789
int hdrlen(TxDesc *d)
const uint8_t PHY_EPSTATUS
Port & getPort(const std::string &if_name, PortID idx=InvalidPortID) override
Get a port with a given name and index.
Definition: i8254xGBe.cc:141
const uint32_t REG_RXCSUM
unsigned avail() const
Definition: pktfifo.hh:100
void serialize(CheckpointOut &cp) const override
Serialize an object.
Definition: i8254xGBe.cc:1124
uint16_t cksum(const IpPtr &ptr)
Definition: inet.cc:204
bool tse(TxDesc *d)
#define PCI_CONFIG_SIZE
Definition: pcireg.h:149
void serialize(CheckpointOut &cp) const override
Serialize an object.
EventFunctionWrapper tickEvent
Definition: i8254xGBe.hh:132
TxDescCache(IGbE *i, std::string n, int s)
Definition: i8254xGBe.cc:1553
int hsplit(const EthPacketPtr &ptr)
Definition: inet.cc:376
EventFunctionWrapper pktEvent
Definition: i8254xGBe.hh:380
unsigned bytesCopied
Bytes of packet that have been copied, so we know when to set EOP.
Definition: i8254xGBe.hh:357
Stats::Scalar rxIpChecksums
Definition: etherdevice.hh:68
const uint8_t PHY_PID
const uint32_t REG_SRRCTL
unsigned descLeft() const
Definition: i8254xGBe.hh:303
Stats::Scalar rxUdpChecksums
Definition: etherdevice.hh:72
bool empty() const
Definition: pktfifo.hh:101
void enableSm() override
Definition: i8254xGBe.cc:1505
const uint8_t EEPROM_READ_OPCODE_SPI
void unserialize(CheckpointIn &cp) override
Unserialize an object.
Definition: i8254xGBe.cc:1159
const uint16_t RXDS_DD
const uint32_t REG_WUC
const uint32_t REG_CTRL_EXT
void reset()
Definition: statistics.cc:569
bool isType(TxDesc *d, uint8_t type)
Definition: system.hh:72
void restartClock()
This function is used to restart the clock so it can handle things like draining and resume in one pl...
Definition: i8254xGBe.cc:2071
Bitfield< 23, 0 > offset
Definition: types.hh:152
const uint32_t REG_FCT
const uint32_t REG_TIPG
int eeOpBits
Definition: i8254xGBe.hh:64
EventFunctionWrapper radvEvent
Definition: i8254xGBe.hh:109
const uint32_t REG_VET
Stats::Scalar rxTcpChecksums
Definition: etherdevice.hh:70
void hwWe(flags f, System *sys, uint64_t frame, std::string sm, std::string q, uint64_t qid, System *q_sys=NULL, int32_t count=1)
Definition: cp_annotate.hh:131
Definition: cprintf.cc:40
DescCache(IGbE *i, const std::string n, int s)
Definition: i8254xGBe.cc:823
void rxStateMachine()
Definition: i8254xGBe.cc:2281
bool packetDone()
Check if the dma on the packet has completed and RX state machine can continue.
Definition: i8254xGBe.cc:1514
void writeback(Addr aMask)
Definition: i8254xGBe.cc:855
const uint32_t REG_RDT
Stats::Scalar txBytes
Definition: etherdevice.hh:63
const uint32_t REG_RFCTL
Tick clockPeriod() const
bool vle(TxDesc *d)
const uint8_t RXDT_ADV_SPLIT_A
EventFunctionWrapper wbEvent
Definition: i8254xGBe.hh:297
unsigned int size_type
Definition: types.hh:54
struct iGbReg::RxDesc::@84::@87 adv_read
const uint32_t REG_RLPML
DrainState
Object drain/handover states.
Definition: drain.hh:71
Tick rxWriteDelay
Definition: i8254xGBe.hh:89
std::string annSmFetch
Annotate sm.
Definition: i8254xGBe.hh:264
void serializeSection(CheckpointOut &cp, const char *name) const
Serialize an object into a new section.
Definition: serialize.cc:171
int mss(TxDesc *d)
Bitfield< 63 > val
Definition: misc.hh:769
PacketFifo rxFifo
Definition: i8254xGBe.hh:69
void setLE(T v)
Set the value in the data pointer to v as little endian.
unsigned getPacketSize(EthPacketPtr p)
Tell the cache to DMA a packet from main memory into its buffer and return the size the of the packet...
Definition: i8254xGBe.cc:1676
Bitfield< 31 > n
const uint16_t RXDP_IPV6
void wbComplete()
Called by event when dma to writeback descriptors is completed.
Definition: i8254xGBe.cc:1056
const uint8_t RXDE_TCPE
void init() override
init() is called after all C++ SimObjects have been created and all ports are connected.
Definition: dma_device.cc:122
uint16_t sum() const
Definition: inet.hh:613
const uint32_t STATS_REGS_SIZE
Bitfield< 3 > x
Definition: pagetable.hh:69
DrainState drainState() const
Return the current drain state of an object.
Definition: drain.hh:308
void anRq(std::string sm, std::string q, int num=1)
Definition: i8254xGBe.hh:195
Bitfield< 5, 0 > status
uint16_t len() const
Definition: inet.hh:612
void delayIntEvent()
Send an interrupt to the cpu.
Definition: i8254xGBe.cc:726
const uint32_t REG_RDBAL
unsigned getSize() const
Definition: packet.hh:730
const uint32_t REG_RXDCTL
const uint32_t REG_AIFS
void serialize(CheckpointOut &cp) const override
Serialize an object.
Definition: i8254xGBe.cc:1984
EventFunctionWrapper pktEvent
Definition: i8254xGBe.hh:480
Stats::Scalar rxPackets
Definition: etherdevice.hh:66
const uint32_t REG_TDBAH
#define UNSERIALIZE_SCALAR(scalar)
Definition: serialize.hh:770
void drainResume() override
Resume execution after a successful drain.
Definition: i8254xGBe.cc:2102
void anWf(std::string sm, std::string q)
Definition: i8254xGBe.hh:205
const uint32_t REG_ICS
T htole(T value)
Definition: byteswap.hh:140
Draining buffers pending serialization/handover.
uint8_t eeAddr
Definition: i8254xGBe.hh:65
uint8_t eeOpcode
Definition: i8254xGBe.hh:65
Tick curTick()
The current simulated tick.
Definition: core.hh:44
void postInterrupt(iGbReg::IntTypes t, bool now=false)
Write an interrupt into the interrupt pending register and check mask and interrupt limit timer befor...
Definition: i8254xGBe.cc:693
void anWe(std::string sm, std::string q)
Definition: i8254xGBe.hh:200
std::string csprintf(const char *format, const Args &...args)
Definition: cprintf.hh:158
const uint16_t RXDS_UDPCS
const uint32_t REG_LEDCTL
#define DTRACE(x)
Definition: trace.hh:223
Bitfield< 4 > s
Definition: inet.cc:54
unsigned descUsed() const
Definition: i8254xGBe.hh:316
const uint32_t REG_STATUS
static CPA * cpa()
Definition: cp_annotate.hh:82
uint8_t tsoHeader[256]
Definition: i8254xGBe.hh:433
const uint32_t REG_WUFC
const uint16_t RXDEE_IPE
bool tcp(TxDesc *d)
TXDCA_CTL txdca_ctl
struct iGbReg::RxDesc::@84::@88 adv_wb
void makeAtomicResponse()
Definition: packet.hh:943
DmaDeviceParams Params
Definition: dma_device.hh:171
uint64_t Tick
Tick count type.
Definition: types.hh:61
void dmaRead(Addr addr, int size, Event *event, uint8_t *data, uint32_t sid, uint32_t ssid, Tick delay=0)
Definition: dma_device.hh:188
const uint8_t RXDT_LEGACY
bool packetWaiting()
Ask if we are still waiting for the packet to be transfered.
Definition: i8254xGBe.hh:467
const uint8_t EEPROM_SIZE
Definition: ns_gige.hh:53
bool txFifoTick
Definition: i8254xGBe.hh:79
CTRL_EXT ctrl_ext
virtual Tick writeConfig(PacketPtr pkt)
Write to the PCI config space data that is stored locally.
Definition: device.cc:284
void writeback1()
Definition: i8254xGBe.cc:909
const uint32_t REG_MANC
bool txTick
Definition: i8254xGBe.hh:78
void checkDrain()
Check if all the draining things that need to occur have occured and handle the drain event if so...
Definition: i8254xGBe.cc:2115
uint16_t len() const
Definition: inet.hh:253
const uint32_t REG_CTRL
const uint32_t REG_TDH
void anBegin(std::string sm, std::string st, int flags=CPA::FL_NONE)
Definition: i8254xGBe.hh:175
void deschedule(Event &event)
Definition: eventq.hh:943
PacketFifo txFifo
Definition: i8254xGBe.hh:70
const uint32_t REG_TDWBAL
Addr getAddr() const
Definition: packet.hh:720
const uint32_t REG_SWFWSYNC
uint8_t flags() const
Definition: inet.hh:511
uint16_t sum() const
Definition: inet.hh:259
Stats::Scalar txIpChecksums
Definition: etherdevice.hh:67
std::shared_ptr< EthPacketData > EthPacketPtr
Definition: etherpkt.hh:87
const uint32_t REG_TDLEN
void pktComplete()
Called by event when dma to write packet is completed.
Definition: i8254xGBe.cc:1764
void schedule(Event &event, Tick when)
Definition: eventq.hh:934
bool isData(TxDesc *d)
~IGbE()
Definition: i8254xGBe.cc:128
int getBAR(Addr addr)
Which base address register (if any) maps the given address?
Definition: device.hh:139
EventFunctionWrapper fetchEvent
Definition: i8254xGBe.hh:292
const uint32_t REG_IMS
#define PCI_DEVICE_SPECIFIC
Definition: pcireg.h:148
unsigned reserve(unsigned len=0)
Definition: pktfifo.hh:105
Tick pioDelay
Definition: device.hh:190
const uint32_t REG_TCTL
const uint32_t REG_RDBAH
void tadvProcess()
Definition: i8254xGBe.hh:112
void unserialize(CheckpointIn &cp) override
Unserialize an object.
void arrayParamOut(CheckpointOut &cp, const std::string &name, const CircleBuf< T > &param)
Definition: circlebuf.hh:174
void reschedule(Event &event, Tick when, bool always=false)
Definition: eventq.hh:952
Port & getPort(const std::string &if_name, PortID idx=InvalidPortID) override
Get a port with a given name and index.
Definition: dma_device.cc:277
bool isContext(TxDesc *d)
const uint16_t EEPROM_CSUM
Tick configDelay
Definition: device.hh:191
const uint32_t REG_FWSM
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
Definition: types.hh:140
#define ULL(N)
uint64_t constant
Definition: types.hh:48
bool enabled()
Definition: cp_annotate.hh:84
System * sys
Definition: io_device.hh:102
EventFunctionWrapper pktDataEvent
Definition: i8254xGBe.hh:386
const uint32_t REG_RADV
A Packet is used to encapsulate a transfer between two objects in the memory system (e...
Definition: packet.hh:249
void areaChanged()
If the address/len/head change when we&#39;ve got descriptors that are dirty that is very bad...
Definition: i8254xGBe.cc:845
#define SERIALIZE_ARRAY(member, size)
Definition: serialize.hh:805
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...
bool isLegacy(TxDesc *d)
void tick()
Definition: i8254xGBe.cc:2433
iGbReg::Regs regs
Definition: i8254xGBe.hh:61
bool rxDmaPacket
Definition: i8254xGBe.hh:81
RxDescCache(IGbE *i, std::string n, int s)
Definition: i8254xGBe.cc:1198
struct iGbReg::RxDesc::@84::@86 legacy
void txWire()
Definition: i8254xGBe.cc:2398
const Params * params() const
Definition: i8254xGBe.hh:512
Tick txReadDelay
Definition: i8254xGBe.hh:89
void serialize(CheckpointOut &cp) const override
Serialize an object.
Definition: i8254xGBe.cc:1533
DrainState drain() override
Notify an object that it needs to drain its state.
Definition: i8254xGBe.cc:2079
const uint32_t REG_EECD
Bitfield< 21 > writeback
Definition: types.hh:134
bool ethRxPkt(EthPacketPtr packet)
Definition: i8254xGBe.cc:2233
Tick write(PacketPtr pkt) override
Pure virtual function that the device must implement.
Definition: i8254xGBe.cc:356
void init() override
init() is called after all C++ SimObjects have been created and all ports are connected.
Definition: i8254xGBe.cc:134
const uint32_t REG_EERD
Stats::Scalar rxBytes
Definition: etherdevice.hh:64
#define SERIALIZE_SCALAR(scalar)
Definition: serialize.hh:763
const uint8_t PHY_PSTATUS
Addr pciToDma(Addr a)
Shortcut for DMA address translation.
Definition: i8254xGBe.hh:260
const uint32_t REG_FCAH
RxDescCache rxDescCache
Definition: i8254xGBe.hh:395
const uint32_t REG_RDLEN
IGbE(const Params *params)
Definition: i8254xGBe.cc:58
const uint32_t REG_IVAR0
const uint8_t EEPROM_RDSR_OPCODE_SPI
const uint32_t REG_TDBAL
bool scheduled() const
Determine if the current event is scheduled.
Definition: eventq.hh:459
EventFunctionWrapper headerEvent
Definition: i8254xGBe.hh:483
const uint16_t RXDS_EOP
bool sendPacket(EthPacketPtr packet)
Definition: etherint.hh:70
bool hasOutstandingEvents() override
Definition: i8254xGBe.cc:1524
Stats::Scalar txUdpChecksums
Definition: etherdevice.hh:71
const uint32_t REG_MDIC
void actionAfterWb() override
Definition: i8254xGBe.cc:1968
virtual const std::string name() const
Definition: sim_object.hh:129
#define UNSERIALIZE_ARRAY(member, size)
Definition: serialize.hh:813
const uint32_t REG_RCTL
bool ixsm(TxDesc *d)
void completionWriteback(Addr a, bool enabled)
Definition: i8254xGBe.hh:486
CPA * cpa
Definition: i8254xGBe.hh:58
const uint32_t REG_FCRTL
Declaration of the Packet class.
T htobe(T value)
Definition: byteswap.hh:142
std::ostream CheckpointOut
Definition: serialize.hh:63
static int numSystemsRunning
Definition: system.hh:491
unsigned int cacheBlockSize() const
Definition: dma_device.hh:205
bool txsm(TxDesc *d)
const uint32_t REG_TIDV
void anDq(std::string sm, std::string q)
Definition: i8254xGBe.hh:185
const uint32_t REG_EICR
const uint32_t REG_WUS
int writePacket(EthPacketPtr packet, int pkt_offset)
Write the given packet into the buffer(s) pointed to by the descriptor and update the book keeping...
Definition: i8254xGBe.cc:1230
void unserialize(CheckpointIn &cp) override
Unserialize an object.
Definition: i8254xGBe.cc:2528
const uint32_t REG_ITR
void signalDrainDone() const
Signal that an object is drained.
Definition: drain.hh:289
void anPq(std::string sm, std::string q, int num=1)
Definition: i8254xGBe.hh:190
EventFunctionWrapper tadvEvent
Definition: i8254xGBe.hh:119
const uint16_t RXDP_IPV4
int getTsoLen(TxDesc *d)
const uint16_t RXDS_IPCS
const uint32_t REG_FCRTH
const uint32_t REG_MTA
Tick ns
nanosecond
Definition: core.cc:65
const uint8_t PHY_AGC
EthPacketPtr txPacket
Definition: i8254xGBe.hh:73
const uint16_t RXDS_TCPCS
T getLE() const
Get the data in the packet byte swapped from little endian to host endian.
const uint32_t REG_FCTTV
EventFunctionWrapper tidvEvent
Definition: i8254xGBe.hh:128
const uint8_t TXD_CNXT
void arrayParamIn(CheckpointIn &cp, const std::string &name, CircleBuf< T > &param)
Definition: circlebuf.hh:184
const uint8_t EEPROM_SIZE
void ethTxDone()
Definition: i8254xGBe.cc:2461
void fetchDescriptors()
Fetch a chunk of descriptors into the descriptor cache.
Definition: i8254xGBe.cc:938
const uint8_t RXDE_IPE
const uint16_t RXDP_TCP
void fetchComplete()
Called by event when dma to read descriptors is completed.
Definition: i8254xGBe.cc:1012
int eeAddrBits
Definition: i8254xGBe.hh:64
Bitfield< 3, 0 > mask
Definition: types.hh:62
const uint32_t REG_TXDCA_CTL
int16_t PortID
Port index/ID type, and a symbolic name for an invalid port id.
Definition: types.hh:235
uint8_t length
Definition: inet.hh:329
const uint32_t REG_RDH
void radvProcess()
Definition: i8254xGBe.hh:102
Tick lastInterrupt
Definition: i8254xGBe.hh:523
#define IN_RANGE(val, base, len)
Definition: i8254xGBe.cc:165
#define warn(...)
Definition: logging.hh:208
void cpuPostInt()
Definition: i8254xGBe.cc:733
bool ip(TxDesc *d)
Tick intClock()
Definition: i8254xGBe.hh:164
Bitfield< 5 > t
const uint8_t VLAN_FILTER_TABLE_SIZE
Bitfield< 15 > ide
uint32_t seq() const
Definition: inet.hh:508
void enableSm() override
Definition: i8254xGBe.cc:2052
bool packetMultiDesc()
Ask if this packet is composed of multiple descriptors so even if we&#39;ve got data, we need to wait for...
Definition: i8254xGBe.hh:475
const uint32_t REG_SWSM
EventFunctionWrapper rdtrEvent
Definition: i8254xGBe.hh:99
T mbits(T val, int first, int last)
Mask off the given bits in place like bits() but without shifting.
Definition: bitfield.hh:95
T bits(T val, int first, int last)
Extract the bitfield from position &#39;first&#39; to &#39;last&#39; (inclusive) from &#39;val&#39; and right justify it...
Definition: bitfield.hh:71
void pop()
Definition: pktfifo.hh:137
void cpuClearInt()
Clear the interupt line to the cpu.
Definition: i8254xGBe.cc:777
const uint32_t REG_RAL
void clear()
Definition: pktfifo.hh:149
const uint32_t REG_RDTR
void intrPost()
Definition: device.hh:198
uint32_t descEnd
Definition: i8254xGBe.hh:420
uint16_t flash[iGbReg::EEPROM_SIZE]
Definition: i8254xGBe.hh:66
bool push(EthPacketPtr ptr)
Definition: pktfifo.hh:120
EthPacketPtr pktPtr
The packet that is currently being dmad to memory if any.
Definition: i8254xGBe.hh:257
void serialize(const std::string &base, CheckpointOut &cp) const
Serialization stuff.
Definition: pktfifo.cc:86
Stats::Scalar postedInterrupts
Definition: etherdevice.hh:110
const uint16_t RXDP_UDP
Bitfield< 0 > p
Running normally.
Bitfield< 9, 8 > rs
bool packetAvailable()
Ask if the packet has been transfered so the state machine can give it to the fifo.
Definition: i8254xGBe.cc:2042
Tick when() const
Get the time that the event is scheduled.
Definition: eventq.hh:499
bool inTick
Definition: i8254xGBe.hh:76
void unserialize(CheckpointIn &cp) override
Unserialize an object.
Definition: i8254xGBe.cc:1542
bool eop(TxDesc *d)
EventFunctionWrapper nullEvent
Definition: i8254xGBe.hh:499
const uint32_t REG_IAM
int eeDataBits
Definition: i8254xGBe.hh:64
void getPacketData(EthPacketPtr p)
Definition: i8254xGBe.cc:1716
void intrClear()
Definition: device.hh:199
const uint8_t TXD_ADVDATA
const uint32_t REG_TXDCTL
int splitCount
Variable to head with header/data completion events.
Definition: i8254xGBe.hh:353
virtual ~DescCache()
Definition: i8254xGBe.cc:836
Bitfield< 14 > ip6
Tick read(PacketPtr pkt) override
Pure virtual function that the device must implement.
Definition: i8254xGBe.cc:168
bool hasOutstandingEvents() override
Definition: i8254xGBe.cc:2061
const uint8_t PHY_EPID
void serialize(CheckpointOut &cp) const override
Serialize an object.
Definition: i8254xGBe.cc:2477
void serialize(CheckpointOut &cp) const override
Serialize this object to the given output stream.
Definition: device.cc:442
Stats::Scalar txTcpChecksums
Definition: etherdevice.hh:69
void tidvProcess()
Definition: i8254xGBe.hh:122
const uint32_t REG_PBA
bool rxTick
Definition: i8254xGBe.hh:77
void fetchDescriptors1()
Definition: i8254xGBe.cc:990
void unserializeSection(CheckpointIn &cp, const char *name)
Unserialize an a child object.
Definition: serialize.cc:178
Stats::Scalar txPackets
Definition: etherdevice.hh:65
const uint8_t RXDT_ADV_ONEBUF
const uint32_t REG_TDWBAH
Tick writeConfig(PacketPtr pkt) override
Write to the PCI config space data that is stored locally.
Definition: i8254xGBe.cc:149
static std::vector< System * > systemList
Definition: system.hh:490
void unserialize(CheckpointIn &cp) override
Unserialize an object.
Definition: i8254xGBe.cc:2013

Generated on Thu May 28 2020 16:21:32 for gem5 by doxygen 1.8.13