IGbE: Add support for newer 8257x based Intel NICs

This commit is contained in:
Ali Saidi 2008-12-05 13:58:22 -05:00
parent 400e516261
commit dd788a23c9
5 changed files with 458 additions and 60 deletions

View file

@ -67,7 +67,9 @@ class EtherDevice(PciDevice):
interface = Port("Ethernet Interrface")
class IGbE(EtherDevice):
# Base class for two IGbE adapters listed above
type = 'IGbE'
#abstract = True
hardware_address = Param.EthernetAddr(NextEthernetAddr,
"Ethernet Hardware Address")
use_flow_control = Param.Bool(False,
@ -80,7 +82,6 @@ class IGbE(EtherDevice):
"Number of enteries in the rx descriptor cache")
clock = Param.Clock('500MHz', "Clock speed of the device")
VendorID = 0x8086
DeviceID = 0x1075
SubsystemID = 0x1008
SubsystemVendorID = 0x8086
Status = 0x0000
@ -104,8 +105,21 @@ class IGbE(EtherDevice):
wb_comp_delay = Param.Latency('10ns', "delay after desc wb occurs")
tx_read_delay = Param.Latency('0ns', "delay after tx dma read")
rx_write_delay = Param.Latency('0ns', "delay after rx dma read")
is8257 = Param.Bool("Select between and 8254x and 8257x device")
class IGbE_e1000(IGbE):
# Older Intel 8254x based gigabit ethernet adapter
# Uses Intel e1000 driver
DeviceID = 0x1075
is8257 = False
class IGbE_igb(IGbE):
# Newer Intel 8257x based gigabit ethernet adapter
# Uses Intel igb driver and in theory supports packet splitting and LRO
DeviceID = 0x10C9
is8257 = True
class EtherDevBase(EtherDevice):
type = 'EtherDevBase'
abstract = True

View file

@ -98,7 +98,7 @@ if env['FULL_SYSTEM']:
CompoundFlag('DiskImageAll', [ 'DiskImageRead', 'DiskImageWrite' ])
CompoundFlag('EthernetAll', [ 'Ethernet', 'EthernetPIO', 'EthernetDMA',
'EthernetData' , 'EthernetDesc', 'EthernetIntr', 'EthernetSM',
'EthernetCksum' ])
'EthernetCksum', 'EthernetEEPROM' ])
CompoundFlag('EthernetNoData', [ 'Ethernet', 'EthernetPIO', 'EthernetDesc',
'EthernetIntr', 'EthernetSM', 'EthernetCksum' ])
CompoundFlag('IdeAll', [ 'IdeCtrl', 'IdeDisk' ])

View file

@ -85,6 +85,9 @@ IGbE::IGbE(const Params *p)
regs.rxdctl.gran(1);
regs.rxdctl.wthresh(1);
regs.fcrth(1);
regs.tdwba = 0;
regs.rlpml = 0;
regs.sw_fw_sync = 0;
regs.pba.rxa(0x30);
regs.pba.txa(0x10);
@ -197,6 +200,11 @@ IGbE::read(PacketPtr pkt)
regs.imr &= ~regs.iam;
chkInterrupt();
break;
case REG_EICR:
// This is only useful for MSI, but the driver reads it every time
// Just don't do anything
pkt->set<uint32_t>(0);
break;
case REG_ITR:
pkt->set<uint32_t>(regs.itr());
break;
@ -231,6 +239,9 @@ IGbE::read(PacketPtr pkt)
case REG_RDLEN:
pkt->set<uint32_t>(regs.rdlen());
break;
case REG_SRRCTL:
pkt->set<uint32_t>(regs.srrctl());
break;
case REG_RDH:
pkt->set<uint32_t>(regs.rdh());
break;
@ -246,6 +257,9 @@ IGbE::read(PacketPtr pkt)
regs.rdtr.fpd(0);
}
break;
case REG_RXDCTL:
pkt->set<uint32_t>(regs.rxdctl());
break;
case REG_RADV:
pkt->set<uint32_t>(regs.radv());
break;
@ -261,6 +275,9 @@ IGbE::read(PacketPtr pkt)
case REG_TDH:
pkt->set<uint32_t>(regs.tdh());
break;
case REG_TXDCA_CTL:
pkt->set<uint32_t>(regs.txdca_ctl());
break;
case REG_TDT:
pkt->set<uint32_t>(regs.tdt());
break;
@ -273,12 +290,34 @@ IGbE::read(PacketPtr pkt)
case REG_TADV:
pkt->set<uint32_t>(regs.tadv());
break;
case REG_TDWBAL:
pkt->set<uint32_t>(regs.tdwba & mask(32));
break;
case REG_TDWBAH:
pkt->set<uint32_t>(regs.tdwba >> 32);
break;
case REG_RXCSUM:
pkt->set<uint32_t>(regs.rxcsum());
break;
case REG_RLPML:
pkt->set<uint32_t>(regs.rlpml);
break;
case REG_RFCTL:
pkt->set<uint32_t>(regs.rfctl());
break;
case REG_MANC:
pkt->set<uint32_t>(regs.manc());
break;
case REG_SWSM:
pkt->set<uint32_t>(regs.swsm());
regs.swsm.smbi(1);
break;
case REG_FWSM:
pkt->set<uint32_t>(regs.fwsm());
break;
case REG_SWFWSYNC:
pkt->set<uint32_t>(regs.sw_fw_sync);
break;
default:
if (!(daddr >= REG_VFTA && daddr < (REG_VFTA + VLAN_FILTER_TABLE_SIZE*4)) &&
!(daddr >= REG_RAL && daddr < (REG_RAL + RCV_ADDRESS_TABLE_SIZE*8)) &&
@ -385,6 +424,14 @@ IGbE::write(PacketPtr pkt)
break;
case REG_EERD:
regs.eerd = val;
if (regs.eerd.start()) {
regs.eerd.done(1);
assert(regs.eerd.addr() < EEPROM_SIZE);
regs.eerd.data(flash[regs.eerd.addr()]);
regs.eerd.start(0);
DPRINTF(EthernetEEPROM, "EEPROM: read addr: %#X data %#x\n",
regs.eerd.addr(), regs.eerd.data());
}
break;
case REG_MDIC:
regs.mdic = val;
@ -399,10 +446,16 @@ IGbE::write(PacketPtr pkt)
regs.mdic.data(0x796D); // link up
break;
case PHY_PID:
regs.mdic.data(0x02A8);
if (params()->is8257)
regs.mdic.data(0x0141);
else
regs.mdic.data(0x02A8);
break;
case PHY_EPID:
regs.mdic.data(0x0380);
if (params()->is8257)
regs.mdic.data(0x0CC0);
else
regs.mdic.data(0x0380);
break;
case PHY_GSTATUS:
regs.mdic.data(0x7C00);
@ -485,6 +538,9 @@ IGbE::write(PacketPtr pkt)
case REG_TIPG:
; // We don't care, so don't store anything
break;
case REG_IVAR0:
warn("Writing to IVAR0, ignoring...\n");
break;
case REG_FCRTL:
regs.fcrtl = val;
break;
@ -503,6 +559,9 @@ IGbE::write(PacketPtr pkt)
regs.rdlen = val & ~mask(7);
rxDescCache.areaChanged();
break;
case REG_SRRCTL:
regs.srrctl = val;
break;
case REG_RDH:
regs.rdh = val;
rxDescCache.areaChanged();
@ -523,6 +582,9 @@ IGbE::write(PacketPtr pkt)
case REG_RADV:
regs.radv = val;
break;
case REG_RXDCTL:
regs.rxdctl = val;
break;
case REG_TDBAL:
regs.tdba.tdbal( val & ~mask(4));
txDescCache.areaChanged();
@ -539,6 +601,11 @@ IGbE::write(PacketPtr pkt)
regs.tdh = val;
txDescCache.areaChanged();
break;
case REG_TXDCA_CTL:
regs.txdca_ctl = val;
if (regs.txdca_ctl.enabled())
panic("No support for DCA\n");
break;
case REG_TDT:
regs.tdt = val;
DPRINTF(EthernetSM, "TXS: TX Tail pointer updated\n");
@ -558,12 +625,38 @@ IGbE::write(PacketPtr pkt)
case REG_TADV:
regs.tadv = val;
break;
case REG_TDWBAL:
regs.tdwba &= ~mask(32);
regs.tdwba |= val;
txDescCache.completionWriteback(regs.tdwba & ~mask(1), regs.tdwba & mask(1));
break;
case REG_TDWBAH:
regs.tdwba &= mask(32);
regs.tdwba |= (uint64_t)val << 32;
txDescCache.completionWriteback(regs.tdwba & ~mask(1), regs.tdwba & mask(1));
break;
case REG_RXCSUM:
regs.rxcsum = val;
break;
case REG_RLPML:
regs.rlpml = val;
break;
case REG_RFCTL:
regs.rfctl = val;
if (regs.rfctl.exsten())
panic("Extended RX descriptors not implemented\n");
break;
case REG_MANC:
regs.manc = val;
break;
case REG_SWSM:
regs.swsm = val;
if (regs.fwsm.eep_fw_semaphore())
regs.swsm.swesmbi(0);
break;
case REG_SWFWSYNC:
regs.sw_fw_sync = val;
break;
default:
if (!(daddr >= REG_VFTA && daddr < (REG_VFTA + VLAN_FILTER_TABLE_SIZE*4)) &&
!(daddr >= REG_RAL && daddr < (REG_RAL + RCV_ADDRESS_TABLE_SIZE*8)) &&
@ -710,19 +803,38 @@ IGbE::RxDescCache::RxDescCache(IGbE *i, const std::string n, int s)
void
IGbE::RxDescCache::writePacket(EthPacketPtr packet)
{
// We shouldn't have to deal with any of these yet
DPRINTF(EthernetDesc, "Packet Length: %d Desc Size: %d\n",
packet->length, igbe->regs.rctl.descSize());
assert(packet->length < igbe->regs.rctl.descSize());
assert(unusedCache.size());
assert(unusedCache.size());
//if (!unusedCache.size())
// return false;
pktPtr = packet;
pktDone = false;
igbe->dmaWrite(igbe->platform->pciToDma(unusedCache.front()->buf),
packet->length, &pktEvent, packet->data, igbe->rxWriteDelay);
Addr buf;
RxDesc *desc = unusedCache.front();
switch (igbe->regs.srrctl.desctype()) {
case RXDT_LEGACY:
buf = desc->legacy.buf;
DPRINTF(EthernetDesc, "Packet Length: %d Desc Size: %d\n",
packet->length, igbe->regs.rctl.descSize());
assert(packet->length < igbe->regs.rctl.descSize());
break;
case RXDT_ADV_ONEBUF:
int buf_len;
buf_len = igbe->regs.rctl.lpe() ? igbe->regs.srrctl.bufLen() :
igbe->regs.rctl.descSize();
DPRINTF(EthernetDesc, "Packet Length: %d srrctl: %#x Desc Size: %d\n",
packet->length, igbe->regs.srrctl(), buf_len);
assert(packet->length < buf_len);
buf = desc->adv_read.pkt;
break;
default:
panic("Unimplemnted RX receive buffer type: %d\n",
igbe->regs.srrctl.desctype());
}
igbe->dmaWrite(igbe->platform->pciToDma(buf), packet->length, &pktEvent,
packet->data, igbe->rxWriteDelay);
}
void
@ -733,7 +845,6 @@ IGbE::RxDescCache::pktComplete()
desc = unusedCache.front();
uint16_t crcfixup = igbe->regs.rctl.secrc() ? 0 : 4 ;
desc->len = htole((uint16_t)(pktPtr->length + crcfixup));
DPRINTF(EthernetDesc, "pktPtr->length: %d stripcrc offset: %d value written: %d %d\n",
pktPtr->length, crcfixup,
htole((uint16_t)(pktPtr->length + crcfixup)),
@ -744,21 +855,28 @@ IGbE::RxDescCache::pktComplete()
DPRINTF(EthernetDesc, "Packet written to memory updating Descriptor\n");
uint8_t status = RXDS_DD | RXDS_EOP;
uint16_t status = RXDS_DD | RXDS_EOP;
uint8_t err = 0;
uint16_t ext_err = 0;
uint16_t csum = 0;
uint16_t ptype = 0;
uint16_t ip_id = 0;
IpPtr ip(pktPtr);
if (ip) {
DPRINTF(EthernetDesc, "Proccesing Ip packet with Id=%d\n", ip->id());
ptype |= RXDP_IPV4;
ip_id = ip->id();
if (igbe->regs.rxcsum.ipofld()) {
DPRINTF(EthernetDesc, "Checking IP checksum\n");
status |= RXDS_IPCS;
desc->csum = htole(cksum(ip));
csum = htole(cksum(ip));
igbe->rxIpChecksums++;
if (cksum(ip) != 0) {
err |= RXDE_IPE;
ext_err |= RXDEE_IPE;
DPRINTF(EthernetDesc, "Checksum is bad!!\n");
}
}
@ -766,11 +884,13 @@ IGbE::RxDescCache::pktComplete()
if (tcp && igbe->regs.rxcsum.tuofld()) {
DPRINTF(EthernetDesc, "Checking TCP checksum\n");
status |= RXDS_TCPCS;
desc->csum = htole(cksum(tcp));
ptype |= RXDP_TCP;
csum = htole(cksum(tcp));
igbe->rxTcpChecksums++;
if (cksum(tcp) != 0) {
DPRINTF(EthernetDesc, "Checksum is bad!!\n");
err |= RXDE_TCPE;
ext_err |= RXDEE_TCPE;
}
}
@ -778,10 +898,12 @@ IGbE::RxDescCache::pktComplete()
if (udp && igbe->regs.rxcsum.tuofld()) {
DPRINTF(EthernetDesc, "Checking UDP checksum\n");
status |= RXDS_UDPCS;
desc->csum = htole(cksum(udp));
ptype |= RXDP_UDP;
csum = htole(cksum(udp));
igbe->rxUdpChecksums++;
if (cksum(udp) != 0) {
DPRINTF(EthernetDesc, "Checksum is bad!!\n");
ext_err |= RXDEE_TCPE;
err |= RXDE_TCPE;
}
}
@ -789,12 +911,38 @@ IGbE::RxDescCache::pktComplete()
DPRINTF(EthernetSM, "Proccesing Non-Ip packet\n");
}
switch (igbe->regs.srrctl.desctype()) {
case RXDT_LEGACY:
desc->legacy.len = htole((uint16_t)(pktPtr->length + crcfixup));
desc->legacy.status = htole(status);
desc->legacy.errors = htole(err);
// No vlan support at this point... just set it to 0
desc->legacy.vlan = 0;
break;
case RXDT_ADV_ONEBUF:
desc->adv_wb.pkt_len = htole((uint16_t)(pktPtr->length + crcfixup));
desc->adv_wb.rss_type = htole(0);
desc->adv_wb.pkt_type = htole(ptype);
// no header splititng support yet
desc->adv_wb.header_len = htole(0);
desc->adv_wb.sph = htole(0);
if (igbe->regs.rxcsum.pcsd()) {
// no rss support right now
desc->adv_wb.rss_hash = htole(0);
} else {
desc->adv_wb.id = htole(ip_id);
desc->adv_wb.csum = htole(csum);
}
desc->adv_wb.status = htole(status);
desc->adv_wb.errors = htole(ext_err);
// no vlan support
desc->adv_wb.vlan_tag = htole(0);
break;
default:
panic("Unimplemnted RX receive buffer type %d\n",
igbe->regs.srrctl.desctype());
}
desc->status = htole(status);
desc->errors = htole(err);
// No vlan support at this point... just set it to 0
desc->vlan = 0;
// Deal with the rx timer interrupts
if (igbe->regs.rdtr.delay()) {
@ -883,7 +1031,7 @@ IGbE::RxDescCache::unserialize(Checkpoint *cp, const std::string &section)
IGbE::TxDescCache::TxDescCache(IGbE *i, const std::string n, int s)
: DescCache<TxDesc>(i,n, s), pktDone(false), isTcp(false), pktWaiting(false),
useTso(false), pktEvent(this), headerEvent(this)
useTso(false), pktEvent(this), headerEvent(this), nullEvent(this)
{
}
@ -907,13 +1055,15 @@ IGbE::TxDescCache::processContextDesc()
// is this going to be a tcp or udp packet?
isTcp = TxdOp::tcp(desc) ? true : false;
if (TxdOp::tse(desc)) {
// setup all the TSO variables, they'll be ignored if we don't use
// tso for this connection
tsoHeaderLen = TxdOp::hdrlen(desc);
tsoMss = TxdOp::mss(desc);
if (TxdOp::isType(desc, TxdOp::TXD_CNXT) && TxdOp::tse(desc)) {
DPRINTF(EthernetDesc, "TCP offload enabled for packet hdrlen: %d mss: %d paylen %d\n",
TxdOp::hdrlen(desc), TxdOp::mss(desc), TxdOp::getLen(desc));
// setup all the TSO variables
useTso = true;
tsoHeaderLen = TxdOp::hdrlen(desc);
tsoMss = TxdOp::mss(desc);
tsoTotalLen = TxdOp::getLen(desc);
tsoLoadedHeader = false;
tsoDescBytesUsed = 0;
@ -921,6 +1071,7 @@ IGbE::TxDescCache::processContextDesc()
tsoPrevSeq = 0;
tsoPktHasHeader = false;
tsoPkts = 0;
}
TxdOp::setDd(desc);
@ -931,10 +1082,23 @@ IGbE::TxDescCache::processContextDesc()
if (!unusedCache.size())
return;
desc = unusedCache.front();
if (!useTso && TxdOp::isType(desc, TxdOp::TXD_ADVDATA) && TxdOp::tse(desc)) {
DPRINTF(EthernetDesc, "TCP offload(adv) enabled for packet hdrlen: %d mss: %d paylen %d\n",
tsoHeaderLen, tsoMss, TxdOp::getTsoLen(desc));
useTso = true;
tsoTotalLen = TxdOp::getTsoLen(desc);
tsoLoadedHeader = false;
tsoDescBytesUsed = 0;
tsoUsedLen = 0;
tsoPrevSeq = 0;
tsoPktHasHeader = false;
tsoPkts = 0;
}
if (useTso && !tsoLoadedHeader) {
// we need to fetch a header
DPRINTF(EthernetDesc, "Starting DMA of TSO header\n");
desc = unusedCache.front();
assert(TxdOp::isData(desc) && TxdOp::getLen(desc) >= tsoHeaderLen);
pktWaiting = true;
assert(tsoHeaderLen <= 256);
@ -1015,6 +1179,7 @@ IGbE::TxDescCache::getPacketData(EthPacketPtr p)
TxDesc *desc;
desc = unusedCache.front();
DPRINTF(EthernetDesc, "getPacketData(): TxDescriptor data d1: %#llx d2: %#llx\n", desc->d1, desc->d2);
assert((TxdOp::isLegacy(desc) || TxdOp::isData(desc)) && TxdOp::getLen(desc));
pktPtr = p;
@ -1216,14 +1381,34 @@ IGbE::TxDescCache::pktComplete()
if (igbe->regs.txdctl.wthresh() == 0) {
DPRINTF(EthernetDesc, "WTHRESH == 0, writing back descriptor\n");
writeback(0);
} else if (igbe->regs.txdctl.gran() && igbe->regs.txdctl.wthresh() >=
descInBlock(usedCache.size())) {
DPRINTF(EthernetDesc, "used > WTHRESH, writing back descriptor\n");
writeback((igbe->cacheBlockSize()-1)>>4);
} else if (igbe->regs.txdctl.wthresh() >= usedCache.size()) {
DPRINTF(EthernetDesc, "used > WTHRESH, writing back descriptor\n");
writeback((igbe->cacheBlockSize()-1)>>4);
}
enableSm();
igbe->checkDrain();
}
void
IGbE::TxDescCache::actionAfterWb()
{
DPRINTF(EthernetDesc, "actionAfterWb() completionEnabled: %d\n",
completionEnabled);
igbe->postInterrupt(iGbReg::IT_TXDW);
if (completionEnabled) {
descEnd = igbe->regs.tdh();
DPRINTF(EthernetDesc, "Completion writing back value: %d to addr: %#x\n", descEnd,
completionAddress);
igbe->dmaWrite(igbe->platform->pciToDma(mbits(completionAddress, 63, 2)),
sizeof(descEnd), &nullEvent, (uint8_t*)&descEnd, 0);
}
}
void
IGbE::TxDescCache::serialize(std::ostream &os)
{
@ -1247,7 +1432,9 @@ IGbE::TxDescCache::serialize(std::ostream &os)
SERIALIZE_SCALAR(tsoCopyBytes);
SERIALIZE_SCALAR(tsoPkts);
SERIALIZE_SCALAR(completionAddress);
SERIALIZE_SCALAR(completionEnabled);
SERIALIZE_SCALAR(descEnd);
}
void
@ -1272,6 +1459,10 @@ IGbE::TxDescCache::unserialize(Checkpoint *cp, const std::string &section)
UNSERIALIZE_SCALAR(tsoDescBytesUsed);
UNSERIALIZE_SCALAR(tsoCopyBytes);
UNSERIALIZE_SCALAR(tsoPkts);
UNSERIALIZE_SCALAR(completionAddress);
UNSERIALIZE_SCALAR(completionEnabled);
UNSERIALIZE_SCALAR(descEnd);
}
bool
@ -1391,7 +1582,6 @@ IGbE::txStateMachine()
}
// Only support descriptor granularity
assert(regs.txdctl.gran());
if (regs.txdctl.lwthresh() && txDescCache.descLeft() < (regs.txdctl.lwthresh() * 8)) {
DPRINTF(EthernetSM, "TXS: LWTHRESH caused posting of TXDLOW\n");
postInterrupt(IT_TXDLOW);

View file

@ -183,7 +183,7 @@ class IGbE : public EtherDevice
virtual long descLen() const = 0;
virtual void updateHead(long h) = 0;
virtual void enableSm() = 0;
virtual void intAfterWb() const {}
virtual void actionAfterWb() {}
virtual void fetchAfterWb() = 0;
std::deque<T*> usedCache;
@ -440,7 +440,7 @@ class IGbE : public EtherDevice
oldHead, curHead);
// If we still have more to wb, call wb now
intAfterWb();
actionAfterWb();
if (moreToWb) {
moreToWb = false;
DPRINTF(EthernetDesc, "Writeback has more todo\n");
@ -625,16 +625,22 @@ class IGbE : public EtherDevice
virtual long descLen() const { return igbe->regs.tdlen() >> 4; }
virtual void updateHead(long h) { igbe->regs.tdh(h); }
virtual void enableSm();
virtual void intAfterWb() const { igbe->postInterrupt(iGbReg::IT_TXDW); }
virtual void actionAfterWb();
virtual void fetchAfterWb() {
if (!igbe->txTick && igbe->getState() == SimObject::Running)
fetchDescriptors();
}
bool pktDone;
bool isTcp;
bool pktWaiting;
bool pktMultiDesc;
Addr completionAddress;
bool completionEnabled;
uint32_t descEnd;
// tso variables
bool useTso;
@ -662,6 +668,11 @@ class IGbE : public EtherDevice
void getPacketData(EthPacketPtr p);
void processContextDesc();
/** Return the number of dsecriptors in a cache block for threshold
* operations.
*/
int descInBlock(int num_desc) { return num_desc /
igbe->cacheBlockSize() / sizeof(iGbReg::TxDesc); }
/** Ask if the packet has been transfered so the state machine can give
* it to the fifo.
* @return packet available in descriptor cache
@ -689,8 +700,19 @@ class IGbE : public EtherDevice
void headerComplete();
EventWrapper<TxDescCache, &TxDescCache::headerComplete> headerEvent;
void completionWriteback(Addr a, bool enabled) {
DPRINTF(EthernetDesc, "Completion writeback Addr: %#x enabled: %d\n",
a, enabled);
completionAddress = a;
completionEnabled = enabled;
}
virtual bool hasOutstandingEvents();
void nullCallback() { DPRINTF(EthernetDesc, "Completion writeback complete\n"); }
EventWrapper<TxDescCache, &TxDescCache::nullCallback> nullEvent;
virtual void serialize(std::ostream &os);
virtual void unserialize(Checkpoint *cp, const std::string &section);

View file

@ -59,11 +59,14 @@ const uint32_t REG_FCTTV = 0x00170;
const uint32_t REG_TIPG = 0x00410;
const uint32_t REG_AIFS = 0x00458;
const uint32_t REG_LEDCTL = 0x00e00;
const uint32_t REG_EICR = 0x01580;
const uint32_t REG_IVAR0 = 0x01700;
const uint32_t REG_FCRTL = 0x02160;
const uint32_t REG_FCRTH = 0x02168;
const uint32_t REG_RDBAL = 0x02800;
const uint32_t REG_RDBAH = 0x02804;
const uint32_t REG_RDLEN = 0x02808;
const uint32_t REG_SRRCTL = 0x0280C;
const uint32_t REG_RDH = 0x02810;
const uint32_t REG_RDT = 0x02818;
const uint32_t REG_RDTR = 0x02820;
@ -74,12 +77,17 @@ const uint32_t REG_TDBAL = 0x03800;
const uint32_t REG_TDBAH = 0x03804;
const uint32_t REG_TDLEN = 0x03808;
const uint32_t REG_TDH = 0x03810;
const uint32_t REG_TXDCA_CTL = 0x03814;
const uint32_t REG_TDT = 0x03818;
const uint32_t REG_TIDV = 0x03820;
const uint32_t REG_TXDCTL = 0x03828;
const uint32_t REG_TADV = 0x0382C;
const uint32_t REG_TDWBAL = 0x03838;
const uint32_t REG_TDWBAH = 0x0383C;
const uint32_t REG_CRCERRS = 0x04000;
const uint32_t REG_RXCSUM = 0x05000;
const uint32_t REG_RLPML = 0x05004;
const uint32_t REG_RFCTL = 0x05008;
const uint32_t REG_MTA = 0x05200;
const uint32_t REG_RAL = 0x05400;
const uint32_t REG_RAH = 0x05404;
@ -87,6 +95,9 @@ const uint32_t REG_VFTA = 0x05600;
const uint32_t REG_WUC = 0x05800;
const uint32_t REG_MANC = 0x05820;
const uint32_t REG_SWSM = 0x05B50;
const uint32_t REG_FWSM = 0x05B54;
const uint32_t REG_SWFWSYNC = 0x05B5C;
const uint8_t EEPROM_READ_OPCODE_SPI = 0x03;
const uint8_t EEPROM_RDSR_OPCODE_SPI = 0x05;
@ -94,9 +105,9 @@ const uint8_t EEPROM_SIZE = 64;
const uint16_t EEPROM_CSUM = 0xBABA;
const uint8_t VLAN_FILTER_TABLE_SIZE = 128;
const uint8_t RCV_ADDRESS_TABLE_SIZE = 16;
const uint8_t RCV_ADDRESS_TABLE_SIZE = 24;
const uint8_t MULTICAST_TABLE_SIZE = 128;
const uint32_t STATS_REGS_SIZE = 0x124;
const uint32_t STATS_REGS_SIZE = 0x228;
// Registers in that are accessed in the PHY
@ -108,14 +119,17 @@ const uint8_t PHY_EPSTATUS = 15;
const uint8_t PHY_AGC = 18;
// Receive Descriptor Status Flags
const uint8_t RXDS_PIF = 0x80;
const uint8_t RXDS_IPCS = 0x40;
const uint8_t RXDS_TCPCS = 0x20;
const uint8_t RXDS_UDPCS = 0x10;
const uint8_t RXDS_VP = 0x08;
const uint8_t RXDS_IXSM = 0x04;
const uint8_t RXDS_EOP = 0x02;
const uint8_t RXDS_DD = 0x01;
const uint16_t RXDS_DYNINT = 0x800;
const uint16_t RXDS_UDPV = 0x400;
const uint16_t RXDS_CRCV = 0x100;
const uint16_t RXDS_PIF = 0x080;
const uint16_t RXDS_IPCS = 0x040;
const uint16_t RXDS_TCPCS = 0x020;
const uint16_t RXDS_UDPCS = 0x010;
const uint16_t RXDS_VP = 0x008;
const uint16_t RXDS_IXSM = 0x004;
const uint16_t RXDS_EOP = 0x002;
const uint16_t RXDS_DD = 0x001;
// Receive Descriptor Error Flags
const uint8_t RXDE_RXE = 0x80;
@ -125,6 +139,32 @@ const uint8_t RXDE_SEQ = 0x04;
const uint8_t RXDE_SE = 0x02;
const uint8_t RXDE_CE = 0x01;
// Receive Descriptor Extended Error Flags
const uint16_t RXDEE_HBO = 0x008;
const uint16_t RXDEE_CE = 0x010;
const uint16_t RXDEE_LE = 0x020;
const uint16_t RXDEE_PE = 0x080;
const uint16_t RXDEE_OSE = 0x100;
const uint16_t RXDEE_USE = 0x200;
const uint16_t RXDEE_TCPE = 0x400;
const uint16_t RXDEE_IPE = 0x800;
// Receive Descriptor Types
const uint8_t RXDT_LEGACY = 0x00;
const uint8_t RXDT_ADV_ONEBUF = 0x01;
const uint8_t RXDT_ADV_SPLIT_A = 0x05;
// Receive Descriptor Packet Types
const uint16_t RXDP_IPV4 = 0x001;
const uint16_t RXDP_IPV4E = 0x002;
const uint16_t RXDP_IPV6 = 0x004;
const uint16_t RXDP_IPV6E = 0x008;
const uint16_t RXDP_TCP = 0x010;
const uint16_t RXDP_UDP = 0x020;
const uint16_t RXDP_SCTP = 0x040;
const uint16_t RXDP_NFS = 0x080;
// Interrupt types
enum IntTypes
{
@ -147,12 +187,38 @@ enum IntTypes
// Receive Descriptor struct
struct RxDesc {
Addr buf;
uint16_t len;
uint16_t csum;
uint8_t status;
uint8_t errors;
uint16_t vlan;
union {
struct {
Addr buf;
uint16_t len;
uint16_t csum;
uint8_t status;
uint8_t errors;
uint16_t vlan;
} legacy;
struct {
Addr pkt;
Addr hdr;
} adv_read;
struct {
uint16_t rss_type:4;
uint16_t pkt_type:12;
uint16_t __reserved1:5;
uint16_t header_len:10;
uint16_t sph:1;
union {
struct {
uint16_t id;
uint16_t csum;
};
uint32_t rss_hash;
};
uint32_t status:20;
uint32_t errors:12;
uint16_t pkt_len;
uint16_t vlan_tag;
} adv_wb ;
};
};
struct TxDesc {
@ -163,24 +229,33 @@ struct TxDesc {
namespace TxdOp {
const uint8_t TXD_CNXT = 0x0;
const uint8_t TXD_DATA = 0x1;
const uint8_t TXD_ADVCNXT = 0x2;
const uint8_t TXD_ADVDATA = 0x3;
bool isLegacy(TxDesc *d) { return !bits(d->d2,29,29); }
uint8_t getType(TxDesc *d) { return bits(d->d2, 23,20); }
bool isContext(TxDesc *d) { return !isLegacy(d) && getType(d) == TXD_CNXT; }
bool isData(TxDesc *d) { return !isLegacy(d) && getType(d) == TXD_DATA; }
bool isType(TxDesc *d, uint8_t type) { return getType(d) == type; }
bool isTypes(TxDesc *d, uint8_t t1, uint8_t t2) { return isType(d, t1) || isType(d, t2); }
bool isAdvDesc(TxDesc *d) { return !isLegacy(d) && isTypes(d, TXD_ADVDATA,TXD_ADVCNXT); }
bool isContext(TxDesc *d) { return !isLegacy(d) && isTypes(d,TXD_CNXT, TXD_ADVCNXT); }
bool isData(TxDesc *d) { return !isLegacy(d) && isTypes(d, TXD_DATA, TXD_ADVDATA); }
Addr getBuf(TxDesc *d) { assert(isLegacy(d) || isData(d)); return d->d1; }
Addr getLen(TxDesc *d) { if (isLegacy(d)) return bits(d->d2,15,0); else return bits(d->d2, 19,0); }
void setDd(TxDesc *d)
{
replaceBits(d->d2, 35, 32, ULL(1));
}
void setDd(TxDesc *d) { replaceBits(d->d2, 35, 32, ULL(1)); }
bool ide(TxDesc *d) { return bits(d->d2, 31,31); }
bool ide(TxDesc *d) { return bits(d->d2, 31,31) && (getType(d) == TXD_DATA || isLegacy(d)); }
bool vle(TxDesc *d) { assert(isLegacy(d) || isData(d)); return bits(d->d2, 30,30); }
bool rs(TxDesc *d) { return bits(d->d2, 27,27); }
bool ic(TxDesc *d) { assert(isLegacy(d) || isData(d)); return isLegacy(d) && bits(d->d2, 26,26); }
bool tse(TxDesc *d) { return (isData(d) || isContext(d)) && bits(d->d2, 26,26); }
bool tse(TxDesc *d) {
if (isTypes(d, TXD_CNXT, TXD_DATA))
return bits(d->d2, 26,26);
if (isType(d, TXD_ADVDATA))
return bits(d->d2, 31, 31);
return false;
}
bool ifcs(TxDesc *d) { assert(isLegacy(d) || isData(d)); return bits(d->d2, 25,25); }
bool eop(TxDesc *d) { assert(isLegacy(d) || isData(d)); return bits(d->d2, 24,24); }
bool ip(TxDesc *d) { assert(isContext(d)); return bits(d->d2, 25,25); }
@ -199,7 +274,14 @@ int ipcse(TxDesc *d) { assert(isContext(d)); return bits(d->d1,31,16); }
int ipcso(TxDesc *d) { assert(isContext(d)); return bits(d->d1,15,8); }
int ipcss(TxDesc *d) { assert(isContext(d)); return bits(d->d1,7,0); }
int mss(TxDesc *d) { assert(isContext(d)); return bits(d->d2,63,48); }
int hdrlen(TxDesc *d) { assert(isContext(d)); return bits(d->d2,47,40); }
int hdrlen(TxDesc *d) {
assert(isContext(d));
if (!isAdvDesc(d))
return bits(d->d2,47,40);
return bits(d->d2, 47,40) + bits(d->d1, 8,0) + bits(d->d1, 15, 9);
}
int getTsoLen(TxDesc *d) { assert(isType(d, TXD_ADVDATA)); return bits(d->d2, 63,46); }
int utcmd(TxDesc *d) { assert(isContext(d)); return bits(d->d2,24,31); }
} // namespace TxdOp
@ -304,8 +386,8 @@ struct Regs {
struct EERD : public Reg<uint32_t> { // 0x0014 EERD Register
using Reg<uint32_t>::operator=;
ADD_FIELD32(start,0,1); // start read
ADD_FIELD32(done,4,1); // done read
ADD_FIELD32(addr,8,8); // address
ADD_FIELD32(done,1,1); // done read
ADD_FIELD32(addr,2,14); // address
ADD_FIELD32(data,16,16); // data
};
EERD eerd;
@ -471,6 +553,17 @@ struct Regs {
};
RDLEN rdlen;
struct SRRCTL : public Reg<uint32_t> { // 0x280C SRRCTL Register
using Reg<uint32_t>::operator=;
ADD_FIELD32(pktlen, 0, 7);
ADD_FIELD32(hdrlen, 16, 7); // guess based on header, not documented
ADD_FIELD32(desctype, 25,3); // type of descriptor 000 legacy, 001 adv,
//101 hdr split
int bufLen() { return pktlen() << 10; }
int hdrLen() { return hdrlen() << 6; }
};
SRRCTL srrctl;
struct RDH : public Reg<uint32_t> { // 0x2810 RDH Register
using Reg<uint32_t>::operator=;
ADD_FIELD32(rdh,0,16); // head of the descriptor ring
@ -532,6 +625,14 @@ struct Regs {
};
TDH tdh;
struct TXDCA_CTL : public Reg<uint32_t> { // 0x3814 TXDCA_CTL Register
using Reg<uint32_t>::operator=;
ADD_FIELD32(cpu_mask, 0, 5);
ADD_FIELD32(enabled, 5,1);
ADD_FIELD32(relax_ordering, 6, 1);
};
TXDCA_CTL txdca_ctl;
struct TDT : public Reg<uint32_t> { // 0x3818 TDT Register
using Reg<uint32_t>::operator=;
ADD_FIELD32(tdt,0,16); // tail of the descriptor ring
@ -564,15 +665,42 @@ struct Regs {
ADD_FIELD32(idv,0,16); // absolute interrupt delay
};
TADV tadv;
/*
struct TDWBA : public Reg<uint64_t> { // 0x3838 TDWBA Register
using Reg<uint64_t>::operator=;
ADD_FIELD64(en,0,1); // enable transmit description ring address writeback
ADD_FIELD64(tdwbal,2,32); // base address of transmit descriptor ring address writeback
ADD_FIELD64(tdwbah,32,32); // base address of transmit descriptor ring
};
TDWBA tdwba;*/
uint64_t tdwba;
struct RXCSUM : public Reg<uint32_t> { // 0x5000 RXCSUM Register
using Reg<uint32_t>::operator=;
ADD_FIELD32(pcss,0,8);
ADD_FIELD32(ipofld,8,1);
ADD_FIELD32(tuofld,9,1);
ADD_FIELD32(pcsd, 13,1);
};
RXCSUM rxcsum;
uint32_t rlpml; // 0x5004 RLPML probably maximum accepted packet size
struct RFCTL : public Reg<uint32_t> { // 0x5008 RFCTL Register
using Reg<uint32_t>::operator=;
ADD_FIELD32(iscsi_dis,0,1);
ADD_FIELD32(iscsi_dwc,1,5);
ADD_FIELD32(nfsw_dis,6,1);
ADD_FIELD32(nfsr_dis,7,1);
ADD_FIELD32(nfs_ver,8,2);
ADD_FIELD32(ipv6_dis,10,1);
ADD_FIELD32(ipv6xsum_dis,11,1);
ADD_FIELD32(ackdis,13,1);
ADD_FIELD32(ipfrsp_dis,14,1);
ADD_FIELD32(exsten,15,1);
};
RFCTL rfctl;
struct MANC : public Reg<uint32_t> { // 0x5820 MANC Register
using Reg<uint32_t>::operator=;
ADD_FIELD32(smbus,0,1); // SMBus enabled #####
@ -605,6 +733,32 @@ struct Regs {
};
MANC manc;
struct SWSM : public Reg<uint32_t> { // 0x5B50 SWSM register
using Reg<uint32_t>::operator=;
ADD_FIELD32(smbi,0,1); // Semaphone bit
ADD_FIELD32(swesmbi, 1,1); // Software eeporm semaphore
ADD_FIELD32(wmng, 2,1); // Wake MNG clock
ADD_FIELD32(reserved, 3, 29);
};
SWSM swsm;
struct FWSM : public Reg<uint32_t> { // 0x5B54 FWSM register
using Reg<uint32_t>::operator=;
ADD_FIELD32(eep_fw_semaphore,0,1);
ADD_FIELD32(fw_mode, 1,3);
ADD_FIELD32(ide, 4,1);
ADD_FIELD32(sol, 5,1);
ADD_FIELD32(eep_roload, 6,1);
ADD_FIELD32(reserved, 7,8);
ADD_FIELD32(fw_val_bit, 15, 1);
ADD_FIELD32(reset_cnt, 16, 3);
ADD_FIELD32(ext_err_ind, 19, 6);
ADD_FIELD32(reserved2, 25, 7);
};
FWSM fwsm;
uint32_t sw_fw_sync;
void serialize(std::ostream &os)
{
paramOut(os, "ctrl", ctrl._data);
@ -625,6 +779,7 @@ struct Regs {
paramOut(os, "fcrth", fcrth._data);
paramOut(os, "rdba", rdba._data);
paramOut(os, "rdlen", rdlen._data);
paramOut(os, "srrctl", srrctl._data);
paramOut(os, "rdh", rdh._data);
paramOut(os, "rdt", rdt._data);
paramOut(os, "rdtr", rdtr._data);
@ -634,12 +789,20 @@ struct Regs {
paramOut(os, "tdba", tdba._data);
paramOut(os, "tdlen", tdlen._data);
paramOut(os, "tdh", tdh._data);
paramOut(os, "txdca_ctl", txdca_ctl._data);
paramOut(os, "tdt", tdt._data);
paramOut(os, "tidv", tidv._data);
paramOut(os, "txdctl", txdctl._data);
paramOut(os, "tadv", tadv._data);
//paramOut(os, "tdwba", tdwba._data);
SERIALIZE_SCALAR(tdwba);
paramOut(os, "rxcsum", rxcsum._data);
SERIALIZE_SCALAR(rlpml);
paramOut(os, "rfctl", rfctl._data);
paramOut(os, "manc", manc._data);
paramOut(os, "swsm", swsm._data);
paramOut(os, "fwsm", fwsm._data);
SERIALIZE_SCALAR(sw_fw_sync);
}
void unserialize(Checkpoint *cp, const std::string &section)
@ -662,6 +825,7 @@ struct Regs {
paramIn(cp, section, "fcrth", fcrth._data);
paramIn(cp, section, "rdba", rdba._data);
paramIn(cp, section, "rdlen", rdlen._data);
paramIn(cp, section, "srrctl", srrctl._data);
paramIn(cp, section, "rdh", rdh._data);
paramIn(cp, section, "rdt", rdt._data);
paramIn(cp, section, "rdtr", rdtr._data);
@ -671,12 +835,20 @@ struct Regs {
paramIn(cp, section, "tdba", tdba._data);
paramIn(cp, section, "tdlen", tdlen._data);
paramIn(cp, section, "tdh", tdh._data);
paramIn(cp, section, "txdca_ctl", txdca_ctl._data);
paramIn(cp, section, "tdt", tdt._data);
paramIn(cp, section, "tidv", tidv._data);
paramIn(cp, section, "txdctl", txdctl._data);
paramIn(cp, section, "tadv", tadv._data);
UNSERIALIZE_SCALAR(tdwba);
//paramIn(cp, section, "tdwba", tdwba._data);
paramIn(cp, section, "rxcsum", rxcsum._data);
UNSERIALIZE_SCALAR(rlpml);
paramIn(cp, section, "rfctl", rfctl._data);
paramIn(cp, section, "manc", manc._data);
paramIn(cp, section, "swsm", swsm._data);
paramIn(cp, section, "fwsm", fwsm._data);
UNSERIALIZE_SCALAR(sw_fw_sync);
}
};
} // iGbReg namespace