47#include "debug/Drain.hh"
48#include "debug/EthernetAll.hh"
51#include "params/IGbE.hh"
58using namespace igbreg;
59using namespace networking;
63 rxFifo(
p.rx_fifo_size), txFifo(
p.tx_fifo_size), inTick(false),
64 rxTick(false), txTick(false), txFifoTick(false), rxDmaPacket(false),
65 pktOffset(0), fetchDelay(
p.fetch_delay), wbDelay(
p.wb_delay),
66 fetchCompDelay(
p.fetch_comp_delay), wbCompDelay(
p.wb_comp_delay),
67 rxWriteDelay(
p.rx_write_delay), txReadDelay(
p.tx_read_delay),
69 radvEvent([
this]{ radvProcess(); },
name()),
70 tadvEvent([
this]{ tadvProcess(); },
name()),
71 tidvEvent([
this]{ tidvProcess(); },
name()),
72 tickEvent([
this]{ tick(); },
name()),
73 interEvent([
this]{ delayIntEvent(); },
name()),
74 rxDescCache(
this,
name()+
".RxDesc",
p.rx_desc_cache_size),
75 txDescCache(
this,
name()+
".TxDesc",
p.tx_desc_cache_size),
112 memcpy(
flash,
p.hardware_address.bytes(), ETH_ADDR_LEN);
113 for (
int x = 0;
x < ETH_ADDR_LEN / 2;
x++)
145 if (if_name ==
"interface")
157 panic(
"Device specific PCI config space not implemented.\n");
167#define IN_RANGE(val, base, len) (val >= base && val < (base + len))
176 panic(
"Invalid PCI memory access to unmapped memory.\n");
184 DPRINTF(Ethernet,
"Read device register %#X\n", daddr);
211 DPRINTF(Ethernet,
"Reading ICR. ICR=%#x IMR=%#x IAM=%#x IAME=%d\n",
225 pkt->
setLE<uint32_t>(0);
246 pkt->
setLE<uint32_t>(0);
277 "Posting interrupt because of RDTR.FPD write\n");
348 panic(
"Read request to unknown register number: %#x\n", daddr);
350 pkt->
setLE<uint32_t>(0);
365 panic(
"Invalid PCI memory access to unmapped memory.\n");
371 assert(pkt->
getSize() ==
sizeof(uint32_t));
373 DPRINTF(Ethernet,
"Wrote device register %#X value %#X\n",
374 daddr, pkt->
getLE<uint32_t>());
379 uint32_t
val = pkt->
getLE<uint32_t>();
388 warn(
"TX Flow control enabled, should implement\n");
390 warn(
"RX Flow control enabled, should implement\n");
412 DPRINTF(EthernetEEPROM,
"EEPROM bit read: %d word: %#X\n",
422 panic(
"What's going on with eeprom interface? opcode:"
423 " %#x:%d addr: %#x:%d, data: %d\n", (uint32_t)
eeOpcode,
437 DPRINTF(EthernetEEPROM,
"EEPROM: opcode: %#X:%d addr: %#X:%d\n",
457 DPRINTF(EthernetEEPROM,
"EEPROM: read addr: %#X data %#x\n",
464 panic(
"No support for interrupt on mdic complete\n");
466 panic(
"No support for reading anything but phy\n");
467 DPRINTF(Ethernet,
"%s phy address %x\n",
468 regs.
mdic.op() == 1 ?
"Writing" :
"Reading",
495 DPRINTF(Ethernet,
"Writing ICR. ICR=%#x IMR=%#x IAM=%#x IAME=%d\n",
506 DPRINTF(EthernetIntr,
"Posting interrupt because of ICS write\n");
525 DPRINTF(EthernetSM,
"RXS: Got RESET!\n");
543 if (
regs.
tctl.en() && !oldtctl.en()) {
564 warn(
"Writing to IVAR0, ignoring...\n");
593 DPRINTF(EthernetSM,
"RXS: RDT Updated.\n");
595 DPRINTF(EthernetSM,
"RXS: RDT Fetching Descriptors!\n");
598 DPRINTF(EthernetSM,
"RXS: RDT NOT Fetching Desc b/c draining!\n");
629 panic(
"No support for DCA\n");
633 DPRINTF(EthernetSM,
"TXS: TX Tail pointer updated\n");
635 DPRINTF(EthernetSM,
"TXS: TDT Fetching Descriptors!\n");
638 DPRINTF(EthernetSM,
"TXS: TDT NOT Fetching Desc b/c draining!\n");
671 panic(
"Extended RX descriptors not implemented\n");
688 panic(
"Write request to unknown register number: %#x\n", daddr);
708 "EINT: postInterrupt() curTick(): %d itr: %d interval: %d\n",
711 if (
regs.
itr.interval() == 0 || now ||
719 assert(int_time > 0);
720 DPRINTF(EthernetIntr,
"EINT: Scheduling timer interrupt for tick %d\n",
742 DPRINTF(Ethernet,
"Interrupt Masked. Not Posting\n");
746 DPRINTF(Ethernet,
"Posting Interrupt\n");
771 DPRINTF(EthernetIntr,
"EINT: Posting interrupt to CPU now. Vector %#x\n",
785 "EINT: Clearing interrupt to CPU now. Vector %#x\n",
794 DPRINTF(Ethernet,
"Checking interrupts icr: %#x imr: %#x\n",
regs.
icr(),
798 DPRINTF(Ethernet,
"Mask cleaned all interrupts\n");
804 DPRINTF(Ethernet,
"ITR = %#X itr.interval = %#X\n",
808 if (
regs.
itr.interval() == 0) {
812 "Possibly scheduling interrupt because of imr write\n");
816 DPRINTF(Ethernet,
"Scheduling for %d\n",
t);
828 : igbe(
i), _name(
n), cachePnt(0), size(
s), curFetching(0),
829 wbOut(0), moreToWb(false), wbAlignment(0), pktPtr(NULL),
831 fetchDelayEvent([
this]{ fetchDescriptors1(); },
n),
832 fetchEvent([
this]{ fetchComplete(); },
n),
833 wbEvent([
this]{ wbComplete(); },
n)
835 fetchBuf =
new T[size];
851 if (usedCache.size() > 0 || curFetching || wbOut)
852 panic(
"Descriptor Address, Length or Head changed. Bad\n");
861 int curHead = descHead();
862 int max_to_wb = usedCache.size();
867 if (aMask < wbAlignment) {
872 "Writing back already in process, returning\n");
880 DPRINTF(EthernetDesc,
"Writing back descriptors head: %d tail: "
881 "%d len: %d cachePnt: %d max_to_wb: %d descleft: %d\n",
882 curHead, descTail(), descLen(), cachePnt, max_to_wb,
885 if (max_to_wb + curHead >= descLen()) {
886 max_to_wb = descLen() - curHead;
889 }
else if (wbAlignment != 0) {
891 max_to_wb = max_to_wb & ~wbAlignment;
894 DPRINTF(EthernetDesc,
"Writing back %d descriptors\n", max_to_wb);
901 assert(!wbDelayEvent.scheduled());
902 igbe->schedule(wbDelayEvent,
curTick() + igbe->wbDelay);
911 igbe->schedule(wbDelayEvent,
curTick() + igbe->wbDelay);
915 DPRINTF(EthernetDesc,
"Begining DMA of %d descriptors\n", wbOut);
917 for (
int x = 0;
x < wbOut;
x++) {
918 assert(usedCache.size());
919 memcpy(&wbBuf[
x], usedCache[
x],
sizeof(T));
924 igbe->dmaWrite(
pciToDma(descBase() + descHead() *
sizeof(T)),
925 wbOut *
sizeof(T), &wbEvent, (uint8_t *)wbBuf,
937 "Currently fetching %d descriptors, returning\n",
942 if (descTail() >= cachePnt)
943 max_to_fetch = descTail() - cachePnt;
945 max_to_fetch = descLen() - cachePnt;
947 size_t free_cache = size - usedCache.size() - unusedCache.size();
949 max_to_fetch = std::min(max_to_fetch, free_cache);
952 DPRINTF(EthernetDesc,
"Fetching descriptors head: %d tail: "
953 "%d len: %d cachePnt: %d max_to_fetch: %d descleft: %d\n",
954 descHead(), descTail(), descLen(), cachePnt,
955 max_to_fetch, descLeft());
958 if (max_to_fetch == 0)
962 curFetching = max_to_fetch;
964 assert(!fetchDelayEvent.scheduled());
965 igbe->schedule(fetchDelayEvent,
curTick() + igbe->fetchDelay);
974 igbe->schedule(fetchDelayEvent,
curTick() + igbe->fetchDelay);
978 DPRINTF(EthernetDesc,
"Fetching descriptors at %#x (%#x), size: %#x\n",
979 descBase() + cachePnt *
sizeof(T),
980 pciToDma(descBase() + cachePnt *
sizeof(T)),
981 curFetching *
sizeof(T));
983 igbe->dmaRead(
pciToDma(descBase() + cachePnt *
sizeof(T)),
984 curFetching *
sizeof(T), &fetchEvent, (uint8_t *)fetchBuf,
985 igbe->fetchCompDelay);
993 for (
int x = 0;
x < curFetching;
x++) {
995 memcpy(newDesc, &fetchBuf[
x],
sizeof(T));
996 unusedCache.push_back(newDesc);
1000 int oldCp = cachePnt;
1002 cachePnt += curFetching;
1003 assert(cachePnt <= descLen());
1004 if (cachePnt == descLen())
1009 DPRINTF(EthernetDesc,
"Fetching complete cachePnt %d -> %d\n",
1021 long curHead = descHead();
1022 long oldHead = curHead;
1024 for (
int x = 0;
x < wbOut;
x++) {
1025 assert(usedCache.size());
1026 delete usedCache[0];
1027 usedCache.pop_front();
1033 if (curHead >= descLen())
1034 curHead -= descLen();
1037 updateHead(curHead);
1039 DPRINTF(EthernetDesc,
"Writeback complete curHead %d -> %d\n",
1046 DPRINTF(EthernetDesc,
"Writeback has more todo\n");
1059 DPRINTF(EthernetDesc,
"Reseting descriptor cache\n");
1060 for (
typename CacheType::size_type
x = 0;
x < usedCache.size();
x++)
1061 delete usedCache[
x];
1062 for (
typename CacheType::size_type
x = 0;
x < unusedCache.size();
x++)
1063 delete unusedCache[
x];
1066 unusedCache.clear();
1082 typename CacheType::size_type usedCacheSize = usedCache.size();
1084 for (
typename CacheType::size_type
x = 0;
x < usedCacheSize;
x++) {
1086 (uint8_t *)usedCache[
x],
sizeof(T));
1089 typename CacheType::size_type unusedCacheSize = unusedCache.size();
1091 for (
typename CacheType::size_type
x = 0;
x < unusedCacheSize;
x++) {
1093 (uint8_t *)unusedCache[
x],
sizeof(T));
1096 Tick fetch_delay = 0, wb_delay = 0;
1097 if (fetchDelayEvent.scheduled())
1098 fetch_delay = fetchDelayEvent.when();
1100 if (wbDelayEvent.scheduled())
1101 wb_delay = wbDelayEvent.when();
1117 typename CacheType::size_type usedCacheSize;
1120 for (
typename CacheType::size_type
x = 0;
x < usedCacheSize;
x++) {
1123 (uint8_t *)temp,
sizeof(T));
1124 usedCache.push_back(temp);
1127 typename CacheType::size_type unusedCacheSize;
1129 for (
typename CacheType::size_type
x = 0;
x < unusedCacheSize;
x++) {
1132 (uint8_t *)temp,
sizeof(T));
1133 unusedCache.push_back(temp);
1135 Tick fetch_delay = 0, wb_delay = 0;
1139 igbe->schedule(fetchDelayEvent, fetch_delay);
1141 igbe->schedule(wbDelayEvent, wb_delay);
1151 pktHdrEvent([
this]{ pktSplitDone(); },
n),
1152 pktDataEvent([
this]{ pktSplitDone(); },
n)
1155 annSmFetch =
"RX Desc Fetch";
1156 annSmWb =
"RX Desc Writeback";
1157 annUnusedDescQ =
"RX Unused Descriptors";
1158 annUnusedCacheQ =
"RX Unused Descriptor Cache";
1159 annUsedCacheQ =
"RX Used Descriptor Cache";
1160 annUsedDescQ =
"RX Used Descriptors";
1161 annDescQ =
"RX Descriptors";
1169 "Part of split packet done: splitcount now %d\n", splitCount);
1170 assert(splitCount <= 2);
1171 if (splitCount != 2)
1175 "Part of split packet done: calling pktComplete()\n");
1182 assert(unusedCache.size());
1188 unsigned buf_len, hdr_len;
1190 RxDesc *desc = unusedCache.front();
1191 switch (igbe->regs.srrctl.desctype()) {
1193 assert(pkt_offset == 0);
1194 bytesCopied = packet->length;
1195 DPRINTF(EthernetDesc,
"Packet Length: %d Desc Size: %d\n",
1196 packet->length, igbe->regs.rctl.descSize());
1197 assert(packet->length < igbe->regs.rctl.descSize());
1199 packet->length, &pktEvent, packet->data,
1200 igbe->rxWriteDelay);
1203 assert(pkt_offset == 0);
1204 bytesCopied = packet->length;
1205 buf_len = igbe->regs.rctl.lpe() ? igbe->regs.srrctl.bufLen() :
1206 igbe->regs.rctl.descSize();
1207 DPRINTF(EthernetDesc,
"Packet Length: %d srrctl: %#x Desc Size: %d\n",
1208 packet->length, igbe->regs.srrctl(), buf_len);
1209 assert(packet->length < buf_len);
1211 packet->length, &pktEvent, packet->data,
1212 igbe->rxWriteDelay);
1220 buf_len = igbe->regs.rctl.lpe() ? igbe->regs.srrctl.bufLen() :
1221 igbe->regs.rctl.descSize();
1222 hdr_len = igbe->regs.rctl.lpe() ? igbe->regs.srrctl.hdrLen() : 0;
1224 "lpe: %d Packet Length: %d offset: %d srrctl: %#x "
1225 "hdr addr: %#x Hdr Size: %d desc addr: %#x Desc Size: %d\n",
1226 igbe->regs.rctl.lpe(), packet->length, pkt_offset,
1230 split_point =
hsplit(pktPtr);
1232 if (packet->length <= hdr_len) {
1233 bytesCopied = packet->length;
1234 assert(pkt_offset == 0);
1235 DPRINTF(EthernetDesc,
"Hdr split: Entire packet in header\n");
1237 packet->length, &pktEvent, packet->data,
1238 igbe->rxWriteDelay);
1242 }
else if (split_point) {
1247 std::min(packet->length - pkt_offset, buf_len);
1248 bytesCopied += max_to_copy;
1250 "Hdr split: Continuing data buffer copy\n");
1252 max_to_copy, &pktEvent,
1253 packet->data + pkt_offset, igbe->rxWriteDelay);
1259 std::min(packet->length - split_point, buf_len);
1260 bytesCopied += max_to_copy + split_point;
1262 DPRINTF(EthernetDesc,
"Hdr split: splitting at %d\n",
1265 split_point, &pktHdrEvent,
1266 packet->data, igbe->rxWriteDelay);
1268 max_to_copy, &pktDataEvent,
1269 packet->data + split_point, igbe->rxWriteDelay);
1275 panic(
"Header split not fitting within header buffer or "
1276 "undecodable packet not fitting in header unsupported\n");
1280 panic(
"Unimplemnted RX receive buffer type: %d\n",
1281 igbe->regs.srrctl.desctype());
1290 assert(unusedCache.size());
1292 desc = unusedCache.front();
1294 uint16_t crcfixup = igbe->regs.rctl.secrc() ? 0 : 4 ;
1295 DPRINTF(EthernetDesc,
"pktPtr->length: %d bytesCopied: %d "
1296 "stripcrc offset: %d value written: %d %d\n",
1297 pktPtr->length, bytesCopied, crcfixup,
1298 htole((uint16_t)(pktPtr->length + crcfixup)),
1299 (uint16_t)(pktPtr->length + crcfixup));
1302 assert(igbe->regs.rxcsum.pcss() == 0);
1304 DPRINTF(EthernetDesc,
"Packet written to memory updating Descriptor\n");
1308 uint16_t ext_err = 0;
1313 assert(bytesCopied <= pktPtr->length);
1314 if (bytesCopied == pktPtr->length)
1322 DPRINTF(EthernetDesc,
"Proccesing Ip packet with Id=%d\n",
1330 if (ip && igbe->regs.rxcsum.ipofld()) {
1331 DPRINTF(EthernetDesc,
"Checking IP checksum\n");
1334 igbe->etherDeviceStats.rxIpChecksums++;
1335 if (
cksum(ip) != 0) {
1338 DPRINTF(EthernetDesc,
"Checksum is bad!!\n");
1342 if (tcp && igbe->regs.rxcsum.tuofld()) {
1343 DPRINTF(EthernetDesc,
"Checking TCP checksum\n");
1347 igbe->etherDeviceStats.rxTcpChecksums++;
1348 if (
cksum(tcp) != 0) {
1349 DPRINTF(EthernetDesc,
"Checksum is bad!!\n");
1356 if (udp && igbe->regs.rxcsum.tuofld()) {
1357 DPRINTF(EthernetDesc,
"Checking UDP checksum\n");
1361 igbe->etherDeviceStats.rxUdpChecksums++;
1362 if (
cksum(udp) != 0) {
1363 DPRINTF(EthernetDesc,
"Checksum is bad!!\n");
1369 DPRINTF(EthernetSM,
"Proccesing Non-Ip packet\n");
1372 switch (igbe->regs.srrctl.desctype()) {
1384 if (igbe->regs.rxcsum.pcsd()) {
1397 panic(
"Unimplemnted RX receive buffer type %d\n",
1398 igbe->regs.srrctl.desctype());
1401 DPRINTF(EthernetDesc,
"Descriptor complete w0: %#x w1: %#x\n",
1404 if (bytesCopied == pktPtr->length) {
1406 "Packet completely written to descriptor buffers\n");
1408 if (igbe->regs.rdtr.delay()) {
1409 Tick delay = igbe->regs.rdtr.delay() * igbe->intClock();
1410 DPRINTF(EthernetSM,
"RXS: Scheduling DTR for %d\n", delay);
1411 igbe->reschedule(igbe->rdtrEvent,
curTick() + delay);
1414 if (igbe->regs.radv.idv()) {
1415 Tick delay = igbe->regs.radv.idv() * igbe->intClock();
1416 DPRINTF(EthernetSM,
"RXS: Scheduling ADV for %d\n", delay);
1417 if (!igbe->radvEvent.scheduled()) {
1418 igbe->schedule(igbe->radvEvent,
curTick() + delay);
1423 if (!igbe->regs.rdtr.delay() && !igbe->regs.radv.idv()) {
1425 "RXS: Receive interrupt delay disabled, posting IT_RXT\n");
1426 igbe->postInterrupt(
IT_RXT);
1431 if (pktPtr->length <= igbe->regs.rsrpd.idv()) {
1433 "RXS: Posting IT_SRPD beacuse small packet received\n");
1444 DPRINTF(EthernetDesc,
"Processing of this descriptor complete\n");
1445 unusedCache.pop_front();
1446 usedCache.push_back(desc);
1453 igbe->rxTick =
true;
1454 igbe->restartClock();
1471 return pktEvent.scheduled() || wbEvent.scheduled() ||
1472 fetchEvent.scheduled() || pktHdrEvent.scheduled() ||
1473 pktDataEvent.scheduled();
1500 pktWaiting(false), pktMultiDesc(false),
1501 completionAddress(0), completionEnabled(false),
1502 useTso(false), tsoHeaderLen(0), tsoMss(0), tsoTotalLen(0), tsoUsedLen(0),
1503 tsoPrevSeq(0), tsoPktPayloadBytes(0), tsoLoadedHeader(false),
1504 tsoPktHasHeader(false), tsoDescBytesUsed(0), tsoCopyBytes(0), tsoPkts(0),
1506 headerEvent([
this]{ headerComplete(); },
n),
1507 nullEvent([
this]{ nullCallback(); },
n)
1509 annSmFetch =
"TX Desc Fetch";
1510 annSmWb =
"TX Desc Writeback";
1511 annUnusedDescQ =
"TX Unused Descriptors";
1512 annUnusedCacheQ =
"TX Unused Descriptor Cache";
1513 annUsedCacheQ =
"TX Used Descriptor Cache";
1514 annUsedDescQ =
"TX Used Descriptors";
1515 annDescQ =
"TX Descriptors";
1521 assert(unusedCache.size());
1524 DPRINTF(EthernetDesc,
"Checking and processing context descriptors\n");
1526 while (!useTso && unusedCache.size() &&
1528 DPRINTF(EthernetDesc,
"Got context descriptor type...\n");
1530 desc = unusedCache.front();
1531 DPRINTF(EthernetDesc,
"Descriptor upper: %#x lower: %#X\n",
1532 desc->
d1, desc->
d2);
1544 DPRINTF(EthernetDesc,
"TCP offload enabled for packet hdrlen: "
1549 tsoLoadedHeader =
false;
1550 tsoDescBytesUsed = 0;
1553 tsoPktHasHeader =
false;
1559 unusedCache.pop_front();
1560 usedCache.push_back(desc);
1563 if (!unusedCache.size())
1566 desc = unusedCache.front();
1569 DPRINTF(EthernetDesc,
"TCP offload(adv) enabled for packet "
1570 "hdrlen: %d mss: %d paylen %d\n",
1574 tsoLoadedHeader =
false;
1575 tsoDescBytesUsed = 0;
1578 tsoPktHasHeader =
false;
1582 if (useTso && !tsoLoadedHeader) {
1584 DPRINTF(EthernetDesc,
"Starting DMA of TSO header\n");
1587 assert(tsoHeaderLen <= 256);
1589 tsoHeaderLen, &headerEvent, tsoHeader, 0);
1596 DPRINTF(EthernetDesc,
"TSO: Fetching TSO header complete\n");
1599 assert(unusedCache.size());
1600 TxDesc *desc = unusedCache.front();
1601 DPRINTF(EthernetDesc,
"TSO: len: %d tsoHeaderLen: %d\n",
1605 tsoDescBytesUsed = 0;
1606 tsoLoadedHeader =
true;
1607 unusedCache.pop_front();
1608 usedCache.push_back(desc);
1610 DPRINTF(EthernetDesc,
"TSO: header part of larger payload\n");
1611 tsoDescBytesUsed = tsoHeaderLen;
1612 tsoLoadedHeader =
true;
1621 if (!unusedCache.size())
1624 DPRINTF(EthernetDesc,
"Starting processing of descriptor\n");
1626 assert(!useTso || tsoLoadedHeader);
1627 TxDesc *desc = unusedCache.front();
1630 DPRINTF(EthernetDesc,
"getPacket(): TxDescriptor data "
1631 "d1: %#llx d2: %#llx\n", desc->
d1, desc->
d2);
1632 DPRINTF(EthernetDesc,
"TSO: use: %d hdrlen: %d mss: %d total: %d "
1633 "used: %d loaded hdr: %d\n", useTso, tsoHeaderLen, tsoMss,
1634 tsoTotalLen, tsoUsedLen, tsoLoadedHeader);
1636 if (tsoPktHasHeader)
1637 tsoCopyBytes = std::min((tsoMss + tsoHeaderLen) -
p->length,
1640 tsoCopyBytes = std::min(tsoMss,
1643 tsoCopyBytes + (tsoPktHasHeader ? 0 : tsoHeaderLen);
1645 DPRINTF(EthernetDesc,
"TSO: descBytesUsed: %d copyBytes: %d "
1646 "this descLen: %d\n",
1648 DPRINTF(EthernetDesc,
"TSO: pktHasHeader: %d\n", tsoPktHasHeader);
1649 DPRINTF(EthernetDesc,
"TSO: Next packet is %d bytes\n", pkt_size);
1653 DPRINTF(EthernetDesc,
"Next TX packet is %d bytes\n",
1661 assert(unusedCache.size());
1664 desc = unusedCache.front();
1666 DPRINTF(EthernetDesc,
"getPacketData(): TxDescriptor data "
1667 "d1: %#llx d2: %#llx\n", desc->
d1, desc->
d2);
1675 DPRINTF(EthernetDesc,
"Starting DMA of packet at offset %d\n",
p->length);
1678 assert(tsoLoadedHeader);
1679 if (!tsoPktHasHeader) {
1681 "Loading TSO header (%d bytes) into start of packet\n",
1683 memcpy(
p->data, &tsoHeader, tsoHeaderLen);
1684 p->length +=tsoHeaderLen;
1685 tsoPktHasHeader =
true;
1691 "Starting DMA of packet at offset %d length: %d\n",
1692 p->length, tsoCopyBytes);
1695 tsoCopyBytes, &pktEvent,
p->data +
p->length,
1697 tsoDescBytesUsed += tsoCopyBytes;
1711 assert(unusedCache.size());
1714 DPRINTF(EthernetDesc,
"DMA of packet complete\n");
1717 desc = unusedCache.front();
1721 DPRINTF(EthernetDesc,
"TxDescriptor data d1: %#llx d2: %#llx\n",
1722 desc->
d1, desc->
d2);
1726 DPRINTF(EthernetDesc,
"TSO: use: %d hdrlen: %d mss: %d total: %d "
1727 "used: %d loaded hdr: %d\n", useTso, tsoHeaderLen, tsoMss,
1728 tsoTotalLen, tsoUsedLen, tsoLoadedHeader);
1729 pktPtr->simLength += tsoCopyBytes;
1730 pktPtr->length += tsoCopyBytes;
1731 tsoUsedLen += tsoCopyBytes;
1732 DPRINTF(EthernetDesc,
"TSO: descBytesUsed: %d copyBytes: %d\n",
1733 tsoDescBytesUsed, tsoCopyBytes);
1742 (pktPtr->length < (tsoMss + tsoHeaderLen) &&
1743 tsoTotalLen != tsoUsedLen && useTso)) {
1745 unusedCache.pop_front();
1746 usedCache.push_back(desc);
1748 tsoDescBytesUsed = 0;
1751 pktMultiDesc =
true;
1753 DPRINTF(EthernetDesc,
"Partial Packet Descriptor of %d bytes Done\n",
1763 pktMultiDesc =
false;
1775 DPRINTF(EthernetDesc,
"TxDescriptor data d1: %#llx d2: %#llx\n",
1776 desc->
d1, desc->
d2);
1782 DPRINTF(EthernetDesc,
"TSO: Modifying IP header. Id + %d\n",
1784 ip->id(ip->id() + tsoPkts++);
1785 ip->len(pktPtr->length -
EthPtr(pktPtr)->size());
1788 ip6->plen(pktPtr->length -
EthPtr(pktPtr)->size());
1792 "TSO: Modifying TCP header. old seq %d + %d\n",
1793 tcp->seq(), tsoPrevSeq);
1794 tcp->seq(tcp->seq() + tsoPrevSeq);
1795 if (tsoUsedLen != tsoTotalLen)
1796 tcp->flags(tcp->flags() & ~9);
1800 DPRINTF(EthernetDesc,
"TSO: Modifying UDP header.\n");
1801 udp->
len(pktPtr->length -
EthPtr(pktPtr)->size());
1803 tsoPrevSeq = tsoUsedLen;
1806 if (debug::EthernetDesc) {
1809 DPRINTF(EthernetDesc,
"Proccesing Ip packet with Id=%d\n",
1812 DPRINTF(EthernetSM,
"Proccesing Non-Ip packet\n");
1817 DPRINTF(EthernetDesc,
"Calculating checksums for packet\n");
1824 igbe->etherDeviceStats.txIpChecksums++;
1825 DPRINTF(EthernetDesc,
"Calculated IP checksum\n");
1832 tcp->sum(
cksum(tcp));
1833 igbe->etherDeviceStats.txTcpChecksums++;
1834 DPRINTF(EthernetDesc,
"Calculated TCP checksum\n");
1839 igbe->etherDeviceStats.txUdpChecksums++;
1840 DPRINTF(EthernetDesc,
"Calculated UDP checksum\n");
1842 panic(
"Told to checksum, but don't know how\n");
1849 DPRINTF(EthernetDesc,
"Descriptor had IDE set\n");
1850 if (igbe->regs.tidv.idv()) {
1851 Tick delay = igbe->regs.tidv.idv() * igbe->intClock();
1852 DPRINTF(EthernetDesc,
"setting tidv\n");
1853 igbe->reschedule(igbe->tidvEvent,
curTick() + delay,
true);
1856 if (igbe->regs.tadv.idv() && igbe->regs.tidv.idv()) {
1857 Tick delay = igbe->regs.tadv.idv() * igbe->intClock();
1858 DPRINTF(EthernetDesc,
"setting tadv\n");
1859 if (!igbe->tadvEvent.scheduled()) {
1860 igbe->schedule(igbe->tadvEvent,
curTick() + delay);
1867 DPRINTF(EthernetDesc,
"Descriptor Done\n");
1868 unusedCache.pop_front();
1869 usedCache.push_back(desc);
1870 tsoDescBytesUsed = 0;
1873 if (useTso && tsoUsedLen == tsoTotalLen)
1878 "------Packet of %d bytes ready for transmission-------\n",
1883 tsoPktHasHeader =
false;
1885 if (igbe->regs.txdctl.wthresh() == 0) {
1886 DPRINTF(EthernetDesc,
"WTHRESH == 0, writing back descriptor\n");
1888 }
else if (!igbe->regs.txdctl.gran() && igbe->regs.txdctl.wthresh() <=
1889 descInBlock(usedCache.size())) {
1890 DPRINTF(EthernetDesc,
"used > WTHRESH, writing back descriptor\n");
1891 writeback((igbe->cacheBlockSize()-1)>>4);
1892 }
else if (igbe->regs.txdctl.wthresh() <= usedCache.size()) {
1893 DPRINTF(EthernetDesc,
"used > WTHRESH, writing back descriptor\n");
1894 writeback((igbe->cacheBlockSize()-1)>>4);
1904 DPRINTF(EthernetDesc,
"actionAfterWb() completionEnabled: %d\n",
1907 if (completionEnabled) {
1908 descEnd = igbe->regs.tdh();
1910 "Completion writing back value: %d to addr: %#x\n", descEnd,
1913 sizeof(descEnd), &nullEvent, (uint8_t *)&descEnd, 0);
1989 igbe->txTick =
true;
1990 igbe->restartClock();
1997 return pktEvent.scheduled() || wbEvent.scheduled() ||
1998 fetchEvent.scheduled();
2015 unsigned int count(0);
2029 DPRINTF(Drain,
"IGbE not drained\n");
2045 DPRINTF(EthernetSM,
"resuming from drain");
2059 DPRINTF(Drain,
"IGbE done draining, processing drain event\n");
2069 DPRINTF(EthernetSM,
"TXS: TX disabled, stopping ticking\n");
2078 DPRINTF(EthernetSM,
"TXS: packet placed in TX FIFO\n");
2093 DPRINTF(EthernetSM,
"TXS: LWTHRESH caused posting of TXDLOW\n");
2098 txPacket = std::make_shared<EthPacketData>(16384);
2106 DPRINTF(EthernetSM,
"TXS: No descriptors left in ring, forcing "
2107 "writeback stopping ticking and posting TXQE\n");
2115 DPRINTF(EthernetSM,
"TXS: No descriptors available in cache, "
2116 "fetching and stopping ticking\n");
2125 "TXS: Fetching TSO header, stopping ticking\n");
2132 DPRINTF(EthernetSM,
"TXS: Reserving %d bytes in FIFO and "
2133 "beginning DMA of next packet\n", size);
2136 }
else if (size == 0) {
2137 DPRINTF(EthernetSM,
"TXS: getPacketSize returned: %d\n", size);
2139 "TXS: No packets to get, writing back used descriptors\n");
2142 DPRINTF(EthernetSM,
"TXS: FIFO full, stopping ticking until space "
2143 "available in FIFO\n");
2150 DPRINTF(EthernetSM,
"TXS: Nothing to do, stopping ticking\n");
2160 DPRINTF(Ethernet,
"RxFIFO: Receiving pcakte from wire\n");
2164 DPRINTF(Ethernet,
"RxFIFO: RX not enabled, dropping\n");
2172 "RXS: received packet into fifo, starting ticking\n");
2177 DPRINTF(Ethernet,
"RxFIFO: Packet won't fit in fifo... dropped\n");
2191 DPRINTF(EthernetSM,
"RXS: RX disabled, stopping ticking\n");
2198 DPRINTF(EthernetSM,
"RXS: Packet completed DMA to memory\n");
2200 DPRINTF(EthernetSM,
"RXS: descLeft: %d rdmts: %d rdlen: %d\n",
2204 int ratio = (1ULL << (
regs.
rctl.rdmts() + 1));
2206 DPRINTF(Ethernet,
"RXS: Interrupting (RXDMT) "
2207 "because of descriptors left\n");
2214 if (descLeft == 0) {
2216 DPRINTF(EthernetSM,
"RXS: No descriptors left in ring, forcing"
2217 " writeback and stopping ticking\n");
2226 "RXS: Writing back because WTHRESH >= descUsed\n");
2236 DPRINTF(EthernetSM,
"RXS: Fetching descriptors because "
2237 "descUnused < PTHRESH\n");
2243 DPRINTF(EthernetSM,
"RXS: No descriptors available in cache, "
2244 "fetching descriptors and stopping ticking\n");
2252 "RXS: stopping ticking until packet DMA completes\n");
2259 DPRINTF(EthernetSM,
"RXS: No descriptors available in cache, "
2260 "stopping ticking\n");
2262 DPRINTF(EthernetSM,
"RXS: No descriptors available, fetching\n");
2267 DPRINTF(EthernetSM,
"RXS: RxFIFO empty, stopping ticking\n");
2277 DPRINTF(EthernetSM,
"RXS: Writing packet into memory\n");
2279 DPRINTF(EthernetSM,
"RXS: Removing packet from FIFO\n");
2284 DPRINTF(EthernetSM,
"RXS: stopping ticking until packet DMA completes\n");
2299 if (debug::EthernetSM) {
2302 DPRINTF(EthernetSM,
"Transmitting Ip packet with Id=%d\n",
2305 DPRINTF(EthernetSM,
"Transmitting Non-Ip packet\n");
2308 "TxFIFO: Successful transmit, bytes available in fifo: %d\n",
2321 DPRINTF(EthernetSM,
"IGbE: -------------- Cycle --------------\n");
2358 DPRINTF(EthernetSM,
"TxFIFO: Transmission complete\n");
2378 bool txPktExists =
txPacket !=
nullptr;
2381 txPacket->serialize(
"txpacket", cp);
2383 Tick rdtr_time = 0, radv_time = 0, tidv_time = 0, tadv_time = 0,
2432 txPacket = std::make_shared<EthPacketData>(16384);
2433 txPacket->unserialize(
"txpacket", cp);
2440 Tick rdtr_time, radv_time, tidv_time, tadv_time, inter_time;
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...
Cycles is a wrapper class for representing cycle counts, i.e.
Port & getPort(const std::string &if_name, PortID idx=InvalidPortID) override
Get a port with a given name and index.
void init() override
init() is called after all C++ SimObjects have been created and all ports are connected.
Addr cacheBlockSize() const
gem5::EtherDevice::EtherDeviceStats etherDeviceStats
bool sendPacket(EthPacketPtr packet)
void wbComplete()
Called by event when dma to writeback descriptors is completed.
unsigned descUsed() const
void unserialize(CheckpointIn &cp) override
Unserialize an object.
void areaChanged()
If the address/len/head change when we've got descriptors that are dirty that is very bad.
unsigned descUnused() const
void fetchComplete()
Called by event when dma to read descriptors is completed.
unsigned descLeft() const
void serialize(CheckpointOut &cp) const override
Serialize an object.
void writeback(Addr aMask)
void fetchDescriptors()
Fetch a chunk of descriptors into the descriptor cache.
DescCache(IGbE *i, const std::string n, int s)
bool hasOutstandingEvents() override
void pktComplete()
Called by event when dma to write packet is completed.
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.
void serialize(CheckpointOut &cp) const override
Serialize an object.
void unserialize(CheckpointIn &cp) override
Unserialize an object.
bool packetDone()
Check if the dma on the packet has completed and RX state machine can continue.
RxDescCache(IGbE *i, std::string n, int s)
bool packetMultiDesc()
Ask if this packet is composed of multiple descriptors so even if we've got data, we need to wait for...
void completionWriteback(Addr a, bool enabled)
bool packetAvailable()
Ask if the packet has been transfered so the state machine can give it to the fifo.
bool packetWaiting()
Ask if we are still waiting for the packet to be transfered.
void getPacketData(EthPacketPtr p)
void processContextDesc()
TxDescCache(IGbE *i, std::string n, int s)
bool hasOutstandingEvents() override
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...
void unserialize(CheckpointIn &cp) override
Unserialize an object.
void pktComplete()
Called by event when dma to write packet is completed.
void actionAfterWb() override
void serialize(CheckpointOut &cp) const override
Serialize an object.
EventFunctionWrapper interEvent
void postInterrupt(igbreg::IntTypes t, bool now=false)
Write an interrupt into the interrupt pending register and check mask and interrupt limit timer befor...
Tick write(PacketPtr pkt) override
Pure virtual function that the device must implement.
void chkInterrupt()
Check and see if changes to the mask register have caused an interrupt to need to be sent or perhaps ...
EventFunctionWrapper tickEvent
DrainState drain() override
Draining is the process of clearing out the states of SimObjects.These are the SimObjects that are pa...
IGbE(const Params ¶ms)
uint16_t flash[igbreg::EEPROM_SIZE]
void drainResume() override
Resume execution after a successful drain.
void cpuClearInt()
Clear the interupt line to the cpu.
EventFunctionWrapper radvEvent
Tick read(PacketPtr pkt) override
Pure virtual function that the device must implement.
Port & getPort(const std::string &if_name, PortID idx=InvalidPortID) override
Get a port with a given name and index.
EventFunctionWrapper tidvEvent
void serialize(CheckpointOut &cp) const override
Serialize an object.
Tick writeConfig(PacketPtr pkt) override
Write to the PCI config space data that is stored locally.
void unserialize(CheckpointIn &cp) override
Unserialize an object.
EventFunctionWrapper tadvEvent
void checkDrain()
Check if all the draining things that need to occur have occured and handle the drain event if so.
bool ethRxPkt(EthPacketPtr packet)
void delayIntEvent()
Send an interrupt to the cpu.
void init() override
init() is called after all C++ SimObjects have been created and all ports are connected.
void restartClock()
This function is used to restart the clock so it can handle things like draining and resume in one pl...
EventFunctionWrapper rdtrEvent
void serialize(const std::string &base, CheckpointOut &cp) const
Serialization stuff.
unsigned reserve(unsigned len=0)
void unserialize(const std::string &base, CheckpointIn &cp)
bool push(EthPacketPtr ptr)
A Packet is used to encapsulate a transfer between two objects in the memory system (e....
void setLE(T v)
Set the value in the data pointer to v as little endian.
void makeAtomicResponse()
T getLE() const
Get the data in the packet byte swapped from little endian to host endian.
void unserialize(CheckpointIn &cp) override
Reconstruct the state of this object from a checkpoint.
void serialize(CheckpointOut &cp) const override
Serialize this object to the given output stream.
bool getBAR(Addr addr, int &num, Addr &offs)
Which base address register (if any) maps the given address?
Addr pciToDma(Addr pci_addr) const
virtual Tick writeConfig(PacketPtr pkt)
Write to the PCI config space data that is stored locally.
Ports are used to interface objects to each other.
constexpr T mbits(T val, unsigned first, unsigned last)
Mask off the given bits in place like bits() but without shifting.
virtual void drainResume()
Resume execution after a successful drain.
void signalDrainDone() const
Signal that an object is drained.
DrainState drainState() const
Return the current drain state of an object.
DrainState
Object drain/handover states.
@ Draining
Draining buffers pending serialization/handover.
@ Running
Running normally.
@ Drained
Buffers drained, ready for serialization/handover.
void deschedule(Event &event)
bool scheduled() const
Determine if the current event is scheduled.
void schedule(Event &event, Tick when)
Tick when() const
Get the time that the event is scheduled.
uint16_t cksum(const IpPtr &ptr)
int hsplit(const EthPacketPtr &ptr)
#define panic(...)
This implements a cprintf based panic() function.
void serializeSection(CheckpointOut &cp, const char *name) const
Serialize an object into a new section.
#define UNSERIALIZE_ARRAY(member, size)
#define SERIALIZE_ARRAY(member, size)
void unserializeSection(CheckpointIn &cp, const char *name)
Unserialize an a child object.
const Params & params() const
#define IN_RANGE(val, base, len)
const uint8_t TXD_ADVDATA
bool isContext(TxDesc *d)
bool isType(TxDesc *d, uint8_t type)
const uint8_t RCV_ADDRESS_TABLE_SIZE
const uint32_t REG_CTRL_EXT
const uint32_t REG_CRCERRS
const uint16_t RXDS_UDPCS
const uint32_t STATS_REGS_SIZE
const uint32_t REG_TXDCTL
const uint32_t REG_TDWBAL
const uint8_t PHY_PSTATUS
const uint32_t REG_RXDCTL
const uint32_t REG_RXCSUM
const uint16_t RXDS_TCPCS
const uint8_t EEPROM_SIZE
const uint32_t REG_SWFWSYNC
const uint8_t VLAN_FILTER_TABLE_SIZE
const uint8_t RXDT_ADV_SPLIT_A
const uint16_t RXDEE_TCPE
const uint8_t EEPROM_READ_OPCODE_SPI
const uint8_t PHY_EPSTATUS
const uint8_t MULTICAST_TABLE_SIZE
const uint32_t REG_STATUS
const uint8_t RXDT_ADV_ONEBUF
const uint32_t REG_LEDCTL
const uint32_t REG_TXDCA_CTL
const uint32_t REG_SRRCTL
const uint16_t EEPROM_CSUM
const uint8_t RXDT_LEGACY
const uint8_t EEPROM_RDSR_OPCODE_SPI
const uint32_t REG_TDWBAH
const uint8_t PHY_GSTATUS
Copyright (c) 2024 - Pranith Kumar Copyright (c) 2020 Inria All rights reserved.
Tick curTick()
The universal simulation clock.
std::ostream CheckpointOut
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
int16_t PortID
Port index/ID type, and a symbolic name for an invalid port id.
void arrayParamOut(CheckpointOut &cp, const std::string &name, const CircleBuf< T > ¶m)
uint64_t Tick
Tick count type.
std::string csprintf(const char *format, const Args &...args)
void arrayParamIn(CheckpointIn &cp, const std::string &name, CircleBuf< T > ¶m)
std::shared_ptr< EthPacketData > EthPacketPtr
Declaration of the Packet class.
#define PCI_DEVICE_SPECIFIC
#define UNSERIALIZE_SCALAR(scalar)
#define SERIALIZE_SCALAR(scalar)
statistics::Scalar txPackets
statistics::Scalar txBytes
statistics::Scalar rxPackets
statistics::Scalar postedInterrupts
statistics::Scalar rxBytes
void unserialize(CheckpointIn &cp) override
Unserialize an object.
void serialize(CheckpointOut &cp) const override
Serialize an object.
struct gem5::igbreg::RxDesc::@340::@342 legacy
struct gem5::igbreg::RxDesc::@340::@344 adv_wb
struct gem5::igbreg::RxDesc::@340::@343 adv_read
const std::string & name()