49 #include "debug/Drain.hh"
50 #include "debug/EthernetAll.hh"
53 #include "params/IGbE.hh"
57 using namespace iGbReg;
62 rxFifo(p->rx_fifo_size), txFifo(p->tx_fifo_size), rxTick(false),
63 txTick(false), txFifoTick(false), rxDmaPacket(false), pktOffset(0),
64 fetchDelay(p->fetch_delay), wbDelay(p->wb_delay),
65 fetchCompDelay(p->fetch_comp_delay), wbCompDelay(p->wb_comp_delay),
66 rxWriteDelay(p->rx_write_delay), txReadDelay(p->tx_read_delay),
67 rdtrEvent(this), radvEvent(this),
68 tadvEvent(this), tidvEvent(this), tickEvent(this), interEvent(this),
69 rxDescCache(this,
name()+
".RxDesc", p->rx_desc_cache_size),
70 txDescCache(this,
name()+
".TxDesc", p->tx_desc_cache_size),
107 memcpy(
flash, p->hardware_address.bytes(), ETH_ADDR_LEN);
108 for (
int x = 0;
x < ETH_ADDR_LEN/2;
x++)
142 if (if_name ==
"interface") {
144 panic(
"Port already connected to\n");
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->
set<uint32_t>(0);
246 pkt->
set<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->
set<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->
get<uint32_t>());
379 uint32_t
val = pkt->
get<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",
421 panic(
"What's going on with eeprom interface? opcode:"
422 " %#x:%d addr: %#x:%d, data: %d\n", (uint32_t)
eeOpcode,
436 DPRINTF(EthernetEEPROM,
"EEPROM: opcode: %#X:%d addr: %#X:%d\n",
437 (uint32_t)eeOpcode, (uint32_t) eeOpBits,
438 (uint32_t)eeAddr>>1, (uint32_t)eeAddrBits);
441 panic(
"Unknown eeprom opcode: %#X:%d\n", (uint32_t)eeOpcode,
456 DPRINTF(EthernetEEPROM,
"EEPROM: read addr: %#X data %#x\n",
463 panic(
"No support for interrupt on mdic complete\n");
465 panic(
"No support for reading anything but phy\n");
466 DPRINTF(Ethernet,
"%s phy address %x\n",
467 regs.
mdic.op() == 1 ?
"Writing" :
"Reading",
494 DPRINTF(Ethernet,
"Writing ICR. ICR=%#x IMR=%#x IAM=%#x IAME=%d\n",
505 DPRINTF(EthernetIntr,
"Posting interrupt because of ICS write\n");
524 DPRINTF(EthernetSM,
"RXS: Got RESET!\n");
542 if (
regs.
tctl.en() && !oldtctl.en()) {
563 warn(
"Writing to IVAR0, ignoring...\n");
592 DPRINTF(EthernetSM,
"RXS: RDT Updated.\n");
594 DPRINTF(EthernetSM,
"RXS: RDT Fetching Descriptors!\n");
597 DPRINTF(EthernetSM,
"RXS: RDT NOT Fetching Desc b/c draining!\n");
628 panic(
"No support for DCA\n");
632 DPRINTF(EthernetSM,
"TXS: TX Tail pointer updated\n");
634 DPRINTF(EthernetSM,
"TXS: TDT Fetching Descriptors!\n");
637 DPRINTF(EthernetSM,
"TXS: TDT NOT Fetching Desc b/c draining!\n");
670 panic(
"Extended RX descriptors not implemented\n");
687 panic(
"Write request to unknown register number: %#x\n", daddr);
707 "EINT: postInterrupt() curTick(): %d itr: %d interval: %d\n",
710 if (
regs.
itr.interval() == 0 || now ||
718 assert(int_time > 0);
719 DPRINTF(EthernetIntr,
"EINT: Scheduling timer interrupt for tick %d\n",
741 DPRINTF(Ethernet,
"Interrupt Masked. Not Posting\n");
745 DPRINTF(Ethernet,
"Posting Interrupt\n");
770 DPRINTF(EthernetIntr,
"EINT: Posting interrupt to CPU now. Vector %#x\n",
784 "EINT: Clearing interrupt to CPU now. Vector %#x\n",
793 DPRINTF(Ethernet,
"Checking interrupts icr: %#x imr: %#x\n",
regs.
icr(),
797 DPRINTF(Ethernet,
"Mask cleaned all interrupts\n");
803 DPRINTF(Ethernet,
"ITR = %#X itr.interval = %#X\n",
807 if (
regs.
itr.interval() == 0) {
811 "Possibly scheduling interrupt because of imr write\n");
814 DPRINTF(Ethernet,
"Scheduling for %d\n", t);
826 : igbe(i), _name(n), cachePnt(0),
size(s), curFetching(0),
827 wbOut(0), moreToWb(false), wbAlignment(0), pktPtr(NULL),
828 wbDelayEvent(this), fetchDelayEvent(this), fetchEvent(this),
847 if (usedCache.size() > 0 || curFetching || wbOut)
848 panic(
"Descriptor Address, Length or Head changed. Bad\n");
857 int curHead = descHead();
858 int max_to_wb = usedCache.size();
863 if (aMask < wbAlignment) {
868 "Writing back already in process, returning\n");
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,
881 if (max_to_wb + curHead >= descLen()) {
882 max_to_wb = descLen() - curHead;
885 }
else if (wbAlignment != 0) {
887 max_to_wb = max_to_wb & ~wbAlignment;
890 DPRINTF(EthernetDesc,
"Writing back %d descriptors\n", max_to_wb);
892 if (max_to_wb <= 0) {
893 if (usedCache.size())
896 igbe->anWe(annSmWb, annUsedCacheQ);
902 assert(!wbDelayEvent.scheduled());
903 igbe->schedule(wbDelayEvent,
curTick() + igbe->wbDelay);
904 igbe->anBegin(annSmWb,
"Prepare Writeback Desc");
913 igbe->schedule(wbDelayEvent,
curTick() + igbe->wbDelay);
917 DPRINTF(EthernetDesc,
"Begining DMA of %d descriptors\n", wbOut);
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);
928 igbe->anBegin(annSmWb,
"Writeback Desc DMA");
931 igbe->dmaWrite(
pciToDma(descBase() + descHead() *
sizeof(T)),
932 wbOut *
sizeof(T), &wbEvent, (uint8_t*)wbBuf,
944 "Currently fetching %d descriptors, returning\n",
949 if (descTail() >= cachePnt)
950 max_to_fetch = descTail() - cachePnt;
952 max_to_fetch = descLen() - cachePnt;
954 size_t free_cache =
size - usedCache.size() - unusedCache.size();
957 igbe->anWe(annSmFetch, annUnusedDescQ);
959 igbe->anPq(annSmFetch, annUnusedDescQ, max_to_fetch);
963 igbe->anWf(annSmFetch, annDescQ);
965 igbe->anRq(annSmFetch, annDescQ, free_cache);
968 max_to_fetch = std::min(max_to_fetch, free_cache);
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());
977 if (max_to_fetch == 0)
981 curFetching = max_to_fetch;
983 assert(!fetchDelayEvent.scheduled());
984 igbe->schedule(fetchDelayEvent,
curTick() + igbe->fetchDelay);
985 igbe->anBegin(annSmFetch,
"Prepare Fetch Desc");
994 igbe->schedule(fetchDelayEvent,
curTick() + igbe->fetchDelay);
998 igbe->anBegin(annSmFetch,
"Fetch Desc");
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);
1015 igbe->anBegin(annSmFetch,
"Fetch Complete");
1016 for (
int x = 0;
x < curFetching;
x++) {
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);
1027 int oldCp = cachePnt;
1030 cachePnt += curFetching;
1031 assert(cachePnt <= descLen());
1032 if (cachePnt == descLen())
1037 DPRINTF(EthernetDesc,
"Fetching complete cachePnt %d -> %d\n",
1040 if ((descTail() >= cachePnt ? (descTail() - cachePnt) : (descLen() -
1043 igbe->anWe(annSmFetch, annUnusedDescQ);
1044 }
else if (!(
size - usedCache.size() - unusedCache.size())) {
1045 igbe->anWf(annSmFetch, annDescQ);
1059 igbe->anBegin(annSmWb,
"Finish Writeback");
1061 long curHead = descHead();
1063 long oldHead = curHead;
1066 for (
int x = 0;
x < wbOut;
x++) {
1067 assert(usedCache.size());
1068 delete usedCache[0];
1069 usedCache.pop_front();
1071 igbe->anDq(annSmWb, annUsedCacheQ);
1072 igbe->anDq(annSmWb, annDescQ);
1078 if (curHead >= descLen())
1079 curHead -= descLen();
1082 updateHead(curHead);
1084 DPRINTF(EthernetDesc,
"Writeback complete curHead %d -> %d\n",
1091 DPRINTF(EthernetDesc,
"Writeback has more todo\n");
1097 if (usedCache.size())
1100 igbe->anWe(annSmWb, annUsedCacheQ);
1109 DPRINTF(EthernetDesc,
"Reseting descriptor cache\n");
1111 delete usedCache[
x];
1113 delete unusedCache[
x];
1116 unusedCache.clear();
1136 (uint8_t*)usedCache[
x],
sizeof(T));
1143 (uint8_t*)unusedCache[
x],
sizeof(T));
1146 Tick fetch_delay = 0, wb_delay = 0;
1147 if (fetchDelayEvent.scheduled())
1148 fetch_delay = fetchDelayEvent.when();
1150 if (wbDelayEvent.scheduled())
1151 wb_delay = wbDelayEvent.when();
1173 (uint8_t*)temp,
sizeof(T));
1174 usedCache.push_back(temp);
1182 (uint8_t*)temp,
sizeof(T));
1183 unusedCache.push_back(temp);
1185 Tick fetch_delay = 0, wb_delay = 0;
1189 igbe->schedule(fetchDelayEvent, fetch_delay);
1191 igbe->schedule(wbDelayEvent, wb_delay);
1200 pktEvent(this), pktHdrEvent(this), pktDataEvent(this)
1204 annSmWb =
"RX Desc Writeback";
1217 "Part of split packet done: splitcount now %d\n", splitCount);
1218 assert(splitCount <= 2);
1219 if (splitCount != 2)
1223 "Part of split packet done: calling pktComplete()\n");
1230 assert(unusedCache.size());
1236 unsigned buf_len, hdr_len;
1238 RxDesc *desc = unusedCache.front();
1239 switch (igbe->regs.srrctl.desctype()) {
1241 assert(pkt_offset == 0);
1242 bytesCopied = packet->length;
1243 DPRINTF(EthernetDesc,
"Packet Length: %d Desc Size: %d\n",
1244 packet->length, igbe->regs.rctl.descSize());
1245 assert(packet->length < igbe->regs.rctl.descSize());
1247 packet->length, &pktEvent, packet->data,
1248 igbe->rxWriteDelay);
1251 assert(pkt_offset == 0);
1252 bytesCopied = packet->length;
1253 buf_len = igbe->regs.rctl.lpe() ? igbe->regs.srrctl.bufLen() :
1254 igbe->regs.rctl.descSize();
1255 DPRINTF(EthernetDesc,
"Packet Length: %d srrctl: %#x Desc Size: %d\n",
1256 packet->length, igbe->regs.srrctl(), buf_len);
1257 assert(packet->length < buf_len);
1259 packet->length, &pktEvent, packet->data,
1260 igbe->rxWriteDelay);
1263 desc->
adv_wb.pkt_len =
htole((uint16_t)(pktPtr->length));
1268 buf_len = igbe->regs.rctl.lpe() ? igbe->regs.srrctl.bufLen() :
1269 igbe->regs.rctl.descSize();
1270 hdr_len = igbe->regs.rctl.lpe() ? igbe->regs.srrctl.hdrLen() : 0;
1272 "lpe: %d Packet Length: %d offset: %d srrctl: %#x "
1273 "hdr addr: %#x Hdr Size: %d desc addr: %#x Desc Size: %d\n",
1274 igbe->regs.rctl.lpe(), packet->length, pkt_offset,
1275 igbe->regs.srrctl(), desc->
adv_read.hdr, hdr_len,
1278 split_point =
hsplit(pktPtr);
1280 if (packet->length <= hdr_len) {
1281 bytesCopied = packet->length;
1282 assert(pkt_offset == 0);
1283 DPRINTF(EthernetDesc,
"Hdr split: Entire packet in header\n");
1285 packet->length, &pktEvent, packet->data,
1286 igbe->rxWriteDelay);
1287 desc->
adv_wb.header_len =
htole((uint16_t)packet->length);
1290 }
else if (split_point) {
1295 std::min(packet->length - pkt_offset, buf_len);
1296 bytesCopied += max_to_copy;
1298 "Hdr split: Continuing data buffer copy\n");
1300 max_to_copy, &pktEvent,
1301 packet->data + pkt_offset, igbe->rxWriteDelay);
1303 desc->
adv_wb.pkt_len =
htole((uint16_t)max_to_copy);
1307 std::min(packet->length - split_point, buf_len);
1308 bytesCopied += max_to_copy + split_point;
1310 DPRINTF(EthernetDesc,
"Hdr split: splitting at %d\n",
1313 split_point, &pktHdrEvent,
1314 packet->data, igbe->rxWriteDelay);
1316 max_to_copy, &pktDataEvent,
1317 packet->data + split_point, igbe->rxWriteDelay);
1320 desc->
adv_wb.pkt_len =
htole((uint16_t)(max_to_copy));
1323 panic(
"Header split not fitting within header buffer or "
1324 "undecodable packet not fitting in header unsupported\n");
1328 panic(
"Unimplemnted RX receive buffer type: %d\n",
1329 igbe->regs.srrctl.desctype());
1338 assert(unusedCache.size());
1340 desc = unusedCache.front();
1342 igbe->anBegin(
"RXS",
"Update Desc");
1344 uint16_t crcfixup = igbe->regs.rctl.secrc() ? 0 : 4 ;
1345 DPRINTF(EthernetDesc,
"pktPtr->length: %d bytesCopied: %d "
1346 "stripcrc offset: %d value written: %d %d\n",
1347 pktPtr->length, bytesCopied, crcfixup,
1348 htole((uint16_t)(pktPtr->length + crcfixup)),
1349 (uint16_t)(pktPtr->length + crcfixup));
1352 assert(igbe->regs.rxcsum.pcss() == 0);
1354 DPRINTF(EthernetDesc,
"Packet written to memory updating Descriptor\n");
1358 uint16_t ext_err = 0;
1363 assert(bytesCopied <= pktPtr->
length);
1364 if (bytesCopied == pktPtr->length)
1370 DPRINTF(EthernetDesc,
"Proccesing Ip packet with Id=%d\n", ip->
id());
1374 if (igbe->regs.rxcsum.ipofld()) {
1375 DPRINTF(EthernetDesc,
"Checking IP checksum\n");
1378 igbe->rxIpChecksums++;
1379 if (
cksum(ip) != 0) {
1382 DPRINTF(EthernetDesc,
"Checksum is bad!!\n");
1386 if (tcp && igbe->regs.rxcsum.tuofld()) {
1387 DPRINTF(EthernetDesc,
"Checking TCP checksum\n");
1391 igbe->rxTcpChecksums++;
1392 if (
cksum(tcp) != 0) {
1393 DPRINTF(EthernetDesc,
"Checksum is bad!!\n");
1400 if (udp && igbe->regs.rxcsum.tuofld()) {
1401 DPRINTF(EthernetDesc,
"Checking UDP checksum\n");
1405 igbe->rxUdpChecksums++;
1406 if (
cksum(udp) != 0) {
1407 DPRINTF(EthernetDesc,
"Checksum is bad!!\n");
1413 DPRINTF(EthernetSM,
"Proccesing Non-Ip packet\n");
1416 switch (igbe->regs.srrctl.desctype()) {
1418 desc->legacy.len =
htole((uint16_t)(pktPtr->length + crcfixup));
1419 desc->legacy.status =
htole(status);
1420 desc->legacy.errors =
htole(err);
1422 desc->legacy.vlan = 0;
1426 desc->adv_wb.rss_type =
htole(0);
1427 desc->adv_wb.pkt_type =
htole(ptype);
1428 if (igbe->regs.rxcsum.pcsd()) {
1430 desc->adv_wb.rss_hash =
htole(0);
1432 desc->adv_wb.id =
htole(ip_id);
1433 desc->adv_wb.csum =
htole(csum);
1435 desc->adv_wb.status =
htole(status);
1436 desc->adv_wb.errors =
htole(ext_err);
1438 desc->adv_wb.vlan_tag =
htole(0);
1441 panic(
"Unimplemnted RX receive buffer type %d\n",
1442 igbe->regs.srrctl.desctype());
1445 DPRINTF(EthernetDesc,
"Descriptor complete w0: %#x w1: %#x\n",
1446 desc->adv_read.pkt, desc->adv_read.hdr);
1448 if (bytesCopied == pktPtr->length) {
1450 "Packet completely written to descriptor buffers\n");
1452 if (igbe->regs.rdtr.delay()) {
1453 Tick delay = igbe->regs.rdtr.delay() * igbe->intClock();
1454 DPRINTF(EthernetSM,
"RXS: Scheduling DTR for %d\n", delay);
1455 igbe->reschedule(igbe->rdtrEvent,
curTick() + delay);
1458 if (igbe->regs.radv.idv()) {
1459 Tick delay = igbe->regs.radv.idv() * igbe->intClock();
1460 DPRINTF(EthernetSM,
"RXS: Scheduling ADV for %d\n", delay);
1461 if (!igbe->radvEvent.scheduled()) {
1462 igbe->schedule(igbe->radvEvent,
curTick() + delay);
1467 if (!igbe->regs.rdtr.delay() && !igbe->regs.radv.idv()) {
1469 "RXS: Receive interrupt delay disabled, posting IT_RXT\n");
1470 igbe->postInterrupt(
IT_RXT);
1475 if (pktPtr->length <= igbe->regs.rsrpd.idv()) {
1477 "RXS: Posting IT_SRPD beacuse small packet received\n");
1488 igbe->anBegin(
"RXS",
"Done Updating Desc");
1489 DPRINTF(EthernetDesc,
"Processing of this descriptor complete\n");
1490 igbe->anDq(
"RXS", annUnusedCacheQ);
1491 unusedCache.pop_front();
1492 igbe->anQ(
"RXS", annUsedCacheQ);
1493 usedCache.push_back(desc);
1500 igbe->rxTick =
true;
1501 igbe->restartClock();
1518 return pktEvent.scheduled() || wbEvent.scheduled() ||
1519 fetchEvent.scheduled() || pktHdrEvent.scheduled() ||
1520 pktDataEvent.scheduled();
1547 pktWaiting(false), pktMultiDesc(false),
1548 completionAddress(0), completionEnabled(false),
1549 useTso(false), tsoHeaderLen(0), tsoMss(0), tsoTotalLen(0), tsoUsedLen(0),
1550 tsoPrevSeq(0), tsoPktPayloadBytes(0), tsoLoadedHeader(false),
1551 tsoPktHasHeader(false), tsoDescBytesUsed(0), tsoCopyBytes(0), tsoPkts(0),
1552 pktEvent(this), headerEvent(this), nullEvent(this)
1555 annSmWb =
"TX Desc Writeback";
1566 assert(unusedCache.size());
1569 DPRINTF(EthernetDesc,
"Checking and processing context descriptors\n");
1571 while (!useTso && unusedCache.size() &&
1573 DPRINTF(EthernetDesc,
"Got context descriptor type...\n");
1575 desc = unusedCache.front();
1576 DPRINTF(EthernetDesc,
"Descriptor upper: %#x lower: %#X\n",
1577 desc->d1, desc->d2);
1589 DPRINTF(EthernetDesc,
"TCP offload enabled for packet hdrlen: "
1594 tsoLoadedHeader =
false;
1595 tsoDescBytesUsed = 0;
1598 tsoPktHasHeader =
false;
1604 unusedCache.pop_front();
1605 igbe->anDq(
"TXS", annUnusedCacheQ);
1606 usedCache.push_back(desc);
1607 igbe->anQ(
"TXS", annUsedCacheQ);
1610 if (!unusedCache.size())
1613 desc = unusedCache.front();
1616 DPRINTF(EthernetDesc,
"TCP offload(adv) enabled for packet "
1617 "hdrlen: %d mss: %d paylen %d\n",
1621 tsoLoadedHeader =
false;
1622 tsoDescBytesUsed = 0;
1625 tsoPktHasHeader =
false;
1629 if (useTso && !tsoLoadedHeader) {
1631 DPRINTF(EthernetDesc,
"Starting DMA of TSO header\n");
1634 assert(tsoHeaderLen <= 256);
1636 tsoHeaderLen, &headerEvent, tsoHeader, 0);
1643 DPRINTF(EthernetDesc,
"TSO: Fetching TSO header complete\n");
1646 assert(unusedCache.size());
1647 TxDesc *desc = unusedCache.front();
1648 DPRINTF(EthernetDesc,
"TSO: len: %d tsoHeaderLen: %d\n",
1652 tsoDescBytesUsed = 0;
1653 tsoLoadedHeader =
true;
1654 unusedCache.pop_front();
1655 usedCache.push_back(desc);
1657 DPRINTF(EthernetDesc,
"TSO: header part of larger payload\n");
1658 tsoDescBytesUsed = tsoHeaderLen;
1659 tsoLoadedHeader =
true;
1668 if (!unusedCache.size())
1671 DPRINTF(EthernetDesc,
"Starting processing of descriptor\n");
1673 assert(!useTso || tsoLoadedHeader);
1674 TxDesc *desc = unusedCache.front();
1677 DPRINTF(EthernetDesc,
"getPacket(): TxDescriptor data "
1678 "d1: %#llx d2: %#llx\n", desc->
d1, desc->
d2);
1679 DPRINTF(EthernetDesc,
"TSO: use: %d hdrlen: %d mss: %d total: %d "
1680 "used: %d loaded hdr: %d\n", useTso, tsoHeaderLen, tsoMss,
1681 tsoTotalLen, tsoUsedLen, tsoLoadedHeader);
1683 if (tsoPktHasHeader)
1684 tsoCopyBytes = std::min((tsoMss + tsoHeaderLen) - p->length,
1687 tsoCopyBytes = std::min(tsoMss,
1690 tsoCopyBytes + (tsoPktHasHeader ? 0 : tsoHeaderLen);
1692 DPRINTF(EthernetDesc,
"TSO: descBytesUsed: %d copyBytes: %d "
1693 "this descLen: %d\n",
1695 DPRINTF(EthernetDesc,
"TSO: pktHasHeader: %d\n", tsoPktHasHeader);
1696 DPRINTF(EthernetDesc,
"TSO: Next packet is %d bytes\n", pkt_size);
1700 DPRINTF(EthernetDesc,
"Next TX packet is %d bytes\n",
1708 assert(unusedCache.size());
1711 desc = unusedCache.front();
1713 DPRINTF(EthernetDesc,
"getPacketData(): TxDescriptor data "
1714 "d1: %#llx d2: %#llx\n", desc->d1, desc->d2);
1722 DPRINTF(EthernetDesc,
"Starting DMA of packet at offset %d\n", p->length);
1725 assert(tsoLoadedHeader);
1726 if (!tsoPktHasHeader) {
1728 "Loading TSO header (%d bytes) into start of packet\n",
1730 memcpy(p->data, &tsoHeader,tsoHeaderLen);
1731 p->length +=tsoHeaderLen;
1732 tsoPktHasHeader =
true;
1738 "Starting DMA of packet at offset %d length: %d\n",
1739 p->length, tsoCopyBytes);
1742 tsoCopyBytes, &pktEvent, p->data + p->length,
1744 tsoDescBytesUsed += tsoCopyBytes;
1758 assert(unusedCache.size());
1761 igbe->anBegin(
"TXS",
"Update Desc");
1763 DPRINTF(EthernetDesc,
"DMA of packet complete\n");
1766 desc = unusedCache.front();
1770 DPRINTF(EthernetDesc,
"TxDescriptor data d1: %#llx d2: %#llx\n",
1771 desc->
d1, desc->
d2);
1775 DPRINTF(EthernetDesc,
"TSO: use: %d hdrlen: %d mss: %d total: %d "
1776 "used: %d loaded hdr: %d\n", useTso, tsoHeaderLen, tsoMss,
1777 tsoTotalLen, tsoUsedLen, tsoLoadedHeader);
1778 pktPtr->simLength += tsoCopyBytes;
1779 pktPtr->length += tsoCopyBytes;
1780 tsoUsedLen += tsoCopyBytes;
1781 DPRINTF(EthernetDesc,
"TSO: descBytesUsed: %d copyBytes: %d\n",
1782 tsoDescBytesUsed, tsoCopyBytes);
1791 (pktPtr->length < ( tsoMss + tsoHeaderLen) &&
1792 tsoTotalLen != tsoUsedLen && useTso)) {
1793 assert(!useTso || (tsoDescBytesUsed ==
TxdOp::getLen(desc)));
1794 igbe->anDq(
"TXS", annUnusedCacheQ);
1795 unusedCache.pop_front();
1796 igbe->anQ(
"TXS", annUsedCacheQ);
1797 usedCache.push_back(desc);
1799 tsoDescBytesUsed = 0;
1802 pktMultiDesc =
true;
1804 DPRINTF(EthernetDesc,
"Partial Packet Descriptor of %d bytes Done\n",
1814 pktMultiDesc =
false;
1826 DPRINTF(EthernetDesc,
"TxDescriptor data d1: %#llx d2: %#llx\n",
1827 desc->
d1, desc->
d2);
1832 DPRINTF(EthernetDesc,
"TSO: Modifying IP header. Id + %d\n",
1834 ip->
id(ip->
id() + tsoPkts++);
1840 "TSO: Modifying TCP header. old seq %d + %d\n",
1841 tcp->
seq(), tsoPrevSeq);
1842 tcp->
seq(tcp->
seq() + tsoPrevSeq);
1843 if (tsoUsedLen != tsoTotalLen)
1848 DPRINTF(EthernetDesc,
"TSO: Modifying UDP header.\n");
1852 tsoPrevSeq = tsoUsedLen;
1855 if (
DTRACE(EthernetDesc)) {
1858 DPRINTF(EthernetDesc,
"Proccesing Ip packet with Id=%d\n",
1861 DPRINTF(EthernetSM,
"Proccesing Non-Ip packet\n");
1866 DPRINTF(EthernetDesc,
"Calculating checksums for packet\n");
1872 igbe->txIpChecksums++;
1873 DPRINTF(EthernetDesc,
"Calculated IP checksum\n");
1881 igbe->txTcpChecksums++;
1882 DPRINTF(EthernetDesc,
"Calculated TCP checksum\n");
1887 igbe->txUdpChecksums++;
1888 DPRINTF(EthernetDesc,
"Calculated UDP checksum\n");
1890 panic(
"Told to checksum, but don't know how\n");
1897 DPRINTF(EthernetDesc,
"Descriptor had IDE set\n");
1898 if (igbe->regs.tidv.idv()) {
1899 Tick delay = igbe->regs.tidv.idv() * igbe->intClock();
1900 DPRINTF(EthernetDesc,
"setting tidv\n");
1901 igbe->reschedule(igbe->tidvEvent,
curTick() + delay,
true);
1904 if (igbe->regs.tadv.idv() && igbe->regs.tidv.idv()) {
1905 Tick delay = igbe->regs.tadv.idv() * igbe->intClock();
1906 DPRINTF(EthernetDesc,
"setting tadv\n");
1907 if (!igbe->tadvEvent.scheduled()) {
1908 igbe->schedule(igbe->tadvEvent,
curTick() + delay);
1915 DPRINTF(EthernetDesc,
"Descriptor Done\n");
1916 igbe->anDq(
"TXS", annUnusedCacheQ);
1917 unusedCache.pop_front();
1918 igbe->anQ(
"TXS", annUsedCacheQ);
1919 usedCache.push_back(desc);
1920 tsoDescBytesUsed = 0;
1923 if (useTso && tsoUsedLen == tsoTotalLen)
1928 "------Packet of %d bytes ready for transmission-------\n",
1933 tsoPktHasHeader =
false;
1935 if (igbe->regs.txdctl.wthresh() == 0) {
1936 igbe->anBegin(
"TXS",
"Desc Writeback");
1937 DPRINTF(EthernetDesc,
"WTHRESH == 0, writing back descriptor\n");
1939 }
else if (!igbe->regs.txdctl.gran() && igbe->regs.txdctl.wthresh() <=
1940 descInBlock(usedCache.size())) {
1941 DPRINTF(EthernetDesc,
"used > WTHRESH, writing back descriptor\n");
1942 igbe->anBegin(
"TXS",
"Desc Writeback");
1943 writeback((igbe->cacheBlockSize()-1)>>4);
1944 }
else if (igbe->regs.txdctl.wthresh() <= usedCache.size()) {
1945 DPRINTF(EthernetDesc,
"used > WTHRESH, writing back descriptor\n");
1946 igbe->anBegin(
"TXS",
"Desc Writeback");
1947 writeback((igbe->cacheBlockSize()-1)>>4);
1957 DPRINTF(EthernetDesc,
"actionAfterWb() completionEnabled: %d\n",
1960 if (completionEnabled) {
1961 descEnd = igbe->regs.tdh();
1963 "Completion writing back value: %d to addr: %#x\n", descEnd,
1966 sizeof(descEnd), &nullEvent, (uint8_t*)&descEnd, 0);
2042 igbe->txTick =
true;
2043 igbe->restartClock();
2050 return pktEvent.scheduled() || wbEvent.scheduled() ||
2051 fetchEvent.scheduled();
2068 unsigned int count(0);
2082 DPRINTF(Drain,
"IGbE not drained\n");
2098 DPRINTF(EthernetSM,
"resuming from drain");
2112 DPRINTF(Drain,
"IGbE done draining, processing drain event\n");
2122 DPRINTF(EthernetSM,
"TXS: TX disabled, stopping ticking\n");
2131 anQ(
"TXS",
"TX FIFO Q");
2132 DPRINTF(EthernetSM,
"TXS: packet placed in TX FIFO\n");
2140 anBegin(
"TXS",
"Desc Writeback");
2148 DPRINTF(EthernetSM,
"TXS: LWTHRESH caused posting of TXDLOW\n");
2153 txPacket = std::make_shared<EthPacketData>(16384);
2159 anBegin(
"TXS",
"Desc Writeback");
2164 DPRINTF(EthernetSM,
"TXS: No descriptors left in ring, forcing "
2165 "writeback stopping ticking and posting TXQE\n");
2175 DPRINTF(EthernetSM,
"TXS: No descriptors available in cache, "
2176 "fetching and stopping ticking\n");
2186 "TXS: Fetching TSO header, stopping ticking\n");
2193 anRq(
"TXS",
"TX FIFO Q");
2195 DPRINTF(EthernetSM,
"TXS: Reserving %d bytes in FIFO and "
2196 "beginning DMA of next packet\n", size);
2199 }
else if (size == 0) {
2200 DPRINTF(EthernetSM,
"TXS: getPacketSize returned: %d\n", size);
2202 "TXS: No packets to get, writing back used descriptors\n");
2203 anBegin(
"TXS",
"Desc Writeback");
2206 anWf(
"TXS",
"TX FIFO Q");
2207 DPRINTF(EthernetSM,
"TXS: FIFO full, stopping ticking until space "
2208 "available in FIFO\n");
2215 DPRINTF(EthernetSM,
"TXS: Nothing to do, stopping ticking\n");
2225 DPRINTF(Ethernet,
"RxFIFO: Receiving pcakte from wire\n");
2230 DPRINTF(Ethernet,
"RxFIFO: RX not enabled, dropping\n");
2239 "RXS: received packet into fifo, starting ticking\n");
2244 DPRINTF(Ethernet,
"RxFIFO: Packet won't fit in fifo... dropped\n");
2259 anQ(
"RXQ",
"RX FIFO Q");
2272 DPRINTF(EthernetSM,
"RXS: RX disabled, stopping ticking\n");
2279 DPRINTF(EthernetSM,
"RXS: Packet completed DMA to memory\n");
2281 DPRINTF(EthernetSM,
"RXS: descLeft: %d rdmts: %d rdlen: %d\n",
2284 case 2:
if (descLeft > .125 *
regs.
rdlen())
break;
2285 case 1:
if (descLeft > .250 *
regs.
rdlen())
break;
2286 case 0:
if (descLeft > .500 *
regs.
rdlen())
break;
2287 DPRINTF(Ethernet,
"RXS: Interrupting (RXDMT) "
2288 "because of descriptors left\n");
2296 if (descLeft == 0) {
2297 anBegin(
"RXS",
"Writeback Descriptors");
2299 DPRINTF(EthernetSM,
"RXS: No descriptors left in ring, forcing"
2300 " writeback and stopping ticking\n");
2309 "RXS: Writing back because WTHRESH >= descUsed\n");
2310 anBegin(
"RXS",
"Writeback Descriptors");
2320 DPRINTF(EthernetSM,
"RXS: Fetching descriptors because "
2321 "descUnused < PTHRESH\n");
2322 anBegin(
"RXS",
"Fetch Descriptors");
2327 anBegin(
"RXS",
"Fetch Descriptors");
2330 DPRINTF(EthernetSM,
"RXS: No descriptors available in cache, "
2331 "fetching descriptors and stopping ticking\n");
2339 "RXS: stopping ticking until packet DMA completes\n");
2345 anBegin(
"RXS",
"Fetch Descriptors");
2348 DPRINTF(EthernetSM,
"RXS: No descriptors available in cache, "
2349 "stopping ticking\n");
2351 DPRINTF(EthernetSM,
"RXS: No descriptors available, fetching\n");
2357 anWe(
"RXS",
"RX FIFO Q");
2358 DPRINTF(EthernetSM,
"RXS: RxFIFO empty, stopping ticking\n");
2362 anPq(
"RXS",
"RX FIFO Q");
2370 DPRINTF(EthernetSM,
"RXS: Writing packet into memory\n");
2372 anBegin(
"RXS",
"FIFO Dequeue");
2373 DPRINTF(EthernetSM,
"RXS: Removing packet from FIFO\n");
2375 anDq(
"RXS",
"RX FIFO Q");
2379 DPRINTF(EthernetSM,
"RXS: stopping ticking until packet DMA completes\n");
2389 anWe(
"TXQ",
"TX FIFO Q");
2395 anPq(
"TXQ",
"TX FIFO Q");
2397 anQ(
"TXQ",
"WireQ");
2398 if (
DTRACE(EthernetSM)) {
2401 DPRINTF(EthernetSM,
"Transmitting Ip packet with Id=%d\n",
2404 DPRINTF(EthernetSM,
"Transmitting Non-Ip packet\n");
2406 anDq(
"TXQ",
"TX FIFO Q");
2409 "TxFIFO: Successful transmit, bytes available in fifo: %d\n",
2426 DPRINTF(EthernetSM,
"IGbE: -------------- Cycle --------------\n");
2455 DPRINTF(EthernetSM,
"TxFIFO: Transmission complete\n");
2475 bool txPktExists =
txPacket !=
nullptr;
2478 txPacket->serialize(
"txpacket", cp);
2480 Tick rdtr_time = 0, radv_time = 0, tidv_time = 0, tadv_time = 0,
2529 txPacket = std::make_shared<EthPacketData>(16384);
2530 txPacket->unserialize(
"txpacket", cp);
2537 Tick rdtr_time, radv_time, tidv_time, tadv_time, inter_time;
2566 IGbEParams::create()
2568 return new IGbE(
this);
const uint8_t MULTICAST_TABLE_SIZE
void anQ(std::string sm, std::string q)
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)
void processContextDesc()
const uint16_t RXDEE_TCPE
void set(T v, ByteOrder endian)
Set the value in the data pointer to v using the specified endianness.
void pktComplete()
Called by event when dma to write packet is completed.
const uint32_t REG_CRCERRS
unsigned descUsed() const
const uint8_t RCV_ADDRESS_TABLE_SIZE
Cycles is a wrapper class for representing cycle counts, i.e.
void unserialize(CheckpointIn &cp) override
Reconstruct the state of this object from a checkpoint.
struct iGbReg::RxDesc::@61::@63 legacy
const std::string & name()
void unserialize(const std::string &base, CheckpointIn &cp)
const uint8_t PHY_GSTATUS
DrainState
Object drain/handover states.
void chkInterrupt()
Check and see if changes to the mask register have caused an interrupt to need to be sent or perhaps ...
const uint8_t PHY_EPSTATUS
const uint32_t REG_RXCSUM
void serialize(CheckpointOut &cp) const override
Serialize an object.
uint16_t cksum(const IpPtr &ptr)
void unserializeSection(CheckpointIn &cp, const char *name)
Unserialize an a child object.
void serialize(CheckpointOut &cp) const override
Serialize an object.
TxDescCache(IGbE *i, std::string n, int s)
int hsplit(const EthPacketPtr &ptr)
const uint32_t REG_SRRCTL
bool scheduled() const
Determine if the current event is scheduled.
const uint8_t EEPROM_READ_OPCODE_SPI
void unserialize(CheckpointIn &cp) override
Unserialize an object.
const uint32_t REG_CTRL_EXT
bool isType(TxDesc *d, uint8_t type)
void restartClock()
This function is used to restart the clock so it can handle things like draining and resume in one pl...
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)
DescCache(IGbE *i, const std::string n, int s)
bool packetDone()
Check if the dma on the packet has completed and RX state machine can continue.
void writeback(Addr aMask)
Addr pciToDma(Addr pci_addr) const
const uint8_t RXDT_ADV_SPLIT_A
void serialize(const std::string &base, CheckpointOut &cp) const
Serialization stuff.
std::string annSmFetch
Annotate sm.
void deschedule(Event &event)
T get(ByteOrder endian) const
Get the data in the packet byte swapped from the specified endianness.
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 wbComplete()
Called by event when dma to writeback descriptors is completed.
void init() override
init() is called after all C++ SimObjects have been created and all ports are connected.
const uint32_t STATS_REGS_SIZE
void anRq(std::string sm, std::string q, int num=1)
void delayIntEvent()
Send an interrupt to the cpu.
const uint32_t REG_RXDCTL
void serialize(CheckpointOut &cp) const override
Serialize an object.
#define UNSERIALIZE_SCALAR(scalar)
EtherInt * getEthPort(const std::string &if_name, int idx) override
Additional function to return the Port of a memory object.
void drainResume() override
Resume execution after a successful drain.
void anWf(std::string sm, std::string q)
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...
Tick curTick()
The current simulated tick.
void postInterrupt(iGbReg::IntTypes t, bool now=false)
Write an interrupt into the interrupt pending register and check mask and interrupt limit timer befor...
void anWe(std::string sm, std::string q)
std::string csprintf(const char *format, const Args &...args)
const uint16_t RXDS_UDPCS
const uint32_t REG_LEDCTL
const uint32_t REG_STATUS
EventWrapper< IGbE,&IGbE::delayIntEvent > interEvent
Tick when() const
Get the time that the event is scheduled.
void makeAtomicResponse()
uint64_t Tick
Tick count type.
const uint8_t RXDT_LEGACY
bool packetWaiting()
Ask if we are still waiting for the packet to be transfered.
const uint8_t EEPROM_SIZE
virtual Tick writeConfig(PacketPtr pkt)
Write to the PCI config space data that is stored locally.
void checkDrain()
Check if all the draining things that need to occur have occured and handle the drain event if so...
void serializeSection(CheckpointOut &cp, const char *name) const
Serialize an object into a new section.
std::string annUnusedDescQ
void anBegin(std::string sm, std::string st, int flags=CPA::FL_NONE)
unsigned int cacheBlockSize() const
#define SERIALIZE_ARRAY(member, size)
const uint32_t REG_TDWBAL
const uint32_t REG_SWFWSYNC
std::shared_ptr< EthPacketData > EthPacketPtr
void pktComplete()
Called by event when dma to write packet is completed.
int getBAR(Addr addr)
Which base address register (if any) maps the given address?
#define PCI_DEVICE_SPECIFIC
unsigned reserve(unsigned len=0)
void unserialize(CheckpointIn &cp) override
Unserialize an object.
void arrayParamOut(CheckpointOut &cp, const std::string &name, const CircleBuf< T > ¶m)
EventWrapper< IGbE,&IGbE::tick > tickEvent
bool isContext(TxDesc *d)
const uint16_t EEPROM_CSUM
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
Draining buffers pending serialization/handover.
A Packet is used to encapsulate a transfer between two objects in the memory system (e...
void areaChanged()
If the address/len/head change when we've got descriptors that are dirty that is very bad...
RxDescCache(IGbE *i, std::string n, int s)
void serialize(CheckpointOut &cp) const override
Serialize an object.
DrainState drain() override
Notify an object that it needs to drain its state.
bool ethRxPkt(EthPacketPtr packet)
Tick write(PacketPtr pkt) override
Pure virtual function that the device must implement.
void init() override
init() is called after all C++ SimObjects have been created and all ports are connected.
#define SERIALIZE_SCALAR(scalar)
const uint8_t PHY_PSTATUS
IGbE(const Params *params)
const uint8_t EEPROM_RDSR_OPCODE_SPI
#define UNSERIALIZE_ARRAY(member, size)
bool sendPacket(EthPacketPtr packet)
bool hasOutstandingEvents() override
void actionAfterWb() override
void completionWriteback(Addr a, bool enabled)
virtual const std::string name() const
unsigned descUnused() const
struct iGbReg::RxDesc::@61::@64 adv_read
Declaration of the Packet class.
unsigned descLeft() const
std::ostream CheckpointOut
static int numSystemsRunning
void anDq(std::string sm, std::string q)
virtual void drainResume()
Resume execution after a successful drain.
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 unserialize(CheckpointIn &cp) override
Unserialize an object.
EventWrapper< IGbE,&IGbE::tidvProcess > tidvEvent
void signalDrainDone() const
Signal that an object is drained.
const Params * params() const
EventWrapper< IGbE,&IGbE::rdtrProcess > rdtrEvent
void anPq(std::string sm, std::string q, int num=1)
std::string annUsedCacheQ
void schedule(Event &event, Tick when)
DrainState drainState() const
Return the current drain state of an object.
const uint16_t RXDS_TCPCS
void arrayParamIn(CheckpointIn &cp, const std::string &name, CircleBuf< T > ¶m)
const uint8_t EEPROM_SIZE
void fetchDescriptors()
Fetch a chunk of descriptors into the descriptor cache.
void fetchComplete()
Called by event when dma to read descriptors is completed.
const uint32_t REG_TXDCA_CTL
#define IN_RANGE(val, base, len)
The base EtherObject class, allows for an accesor function to a simobj that returns the Port...
const uint8_t VLAN_FILTER_TABLE_SIZE
EventWrapper< IGbE,&IGbE::tadvProcess > tadvEvent
bool packetMultiDesc()
Ask if this packet is composed of multiple descriptors so even if we've got data, we need to wait for...
T mbits(T val, int first, int last)
Mask off the given bits in place like bits() but without shifting.
T bits(T val, int first, int last)
Extract the bitfield from position 'first' to 'last' (inclusive) from 'val' and right justify it...
void cpuClearInt()
Clear the interupt line to the cpu.
uint16_t flash[iGbReg::EEPROM_SIZE]
bool push(EthPacketPtr ptr)
Stats::Scalar postedInterrupts
bool packetAvailable()
Ask if the packet has been transfered so the state machine can give it to the fifo.
void unserialize(CheckpointIn &cp) override
Unserialize an object.
void getPacketData(EthPacketPtr p)
EventWrapper< IGbE,&IGbE::radvProcess > radvEvent
const uint8_t TXD_ADVDATA
const uint32_t REG_TXDCTL
std::string annUnusedCacheQ
Tick read(PacketPtr pkt) override
Pure virtual function that the device must implement.
bool hasOutstandingEvents() override
void serialize(CheckpointOut &cp) const override
Serialize an object.
void serialize(CheckpointOut &cp) const override
Serialize this object to the given output stream.
struct iGbReg::RxDesc::@61::@65 adv_wb
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.
static std::vector< System * > systemList
void unserialize(CheckpointIn &cp) override
Unserialize an object.