From 3a5a20769b2ba15905fc2e0a833a8ecbf3098646 Mon Sep 17 00:00:00 2001 From: Ali Saidi Date: Thu, 15 Mar 2007 15:16:23 -0400 Subject: [PATCH] add all the registers we'll need to support for the Intel GbE device and support enough functionality make the driver think the device is there, and in good working order. src/dev/SConscript: add intel gbe to the dev SCons file src/dev/i8254xGBe.cc: src/dev/i8254xGBe.hh: src/dev/i8254xGBe_defs.hh: use new manner of registers and implement all device registers that are touched through boot and ifup --HG-- extra : convert_revision : b1a1767f0fd31cd371e432cb48ac9a2e9f9291b5 --- src/dev/SConscript | 2 +- src/dev/i8254xGBe.cc | 472 +++++++++++++++++++-------- src/dev/i8254xGBe.hh | 4 +- src/dev/i8254xGBe_defs.hh | 668 ++++++++++++++++++++++++-------------- 4 files changed, 768 insertions(+), 378 deletions(-) diff --git a/src/dev/SConscript b/src/dev/SConscript index 1ec83de4b..ea529b536 100644 --- a/src/dev/SConscript +++ b/src/dev/SConscript @@ -40,7 +40,7 @@ if env['FULL_SYSTEM']: Source('etherlink.cc') Source('etherpkt.cc') Source('ethertap.cc') - #Source('i8254xGBe.cc') + Source('i8254xGBe.cc') Source('ide_ctrl.cc') Source('ide_disk.cc') Source('io_device.cc') diff --git a/src/dev/i8254xGBe.cc b/src/dev/i8254xGBe.cc index 7fc68f4e7..5476ef9eb 100644 --- a/src/dev/i8254xGBe.cc +++ b/src/dev/i8254xGBe.cc @@ -46,29 +46,32 @@ using namespace iGbReg; IGbE::IGbE(Params *p) - : PciDev(p), etherInt(NULL) + : PciDev(p), etherInt(NULL), useFlowControl(p->use_flow_control) { // Initialized internal registers per Intel documentation - regs.tctl.reg = 0; - regs.rctl.reg = 0; - regs.ctrl.reg = 0; - regs.ctrl.fd = 1; - regs.ctrl.lrst = 1; - regs.ctrl.speed = 2; - regs.ctrl.frcspd = 1; - regs.sts.reg = 0; - regs.eecd.reg = 0; - regs.eecd.fwe = 1; - regs.eecd.ee_type = 1; - regs.eerd.reg = 0; - regs.icd.reg = 0; - regs.imc.reg = 0; - regs.rctl.reg = 0; - regs.tctl.reg = 0; - regs.manc.reg = 0; + regs.tctl(0); + regs.rctl(0); + regs.ctrl(0); + regs.ctrl.fd(1); + regs.ctrl.lrst(1); + regs.ctrl.speed(2); + regs.ctrl.frcspd(1); + regs.sts(0); + regs.sts.speed(3); // Say we're 1000Mbps + regs.sts.fd(1); // full duplex + regs.eecd(0); + regs.eecd.fwe(1); + regs.eecd.ee_type(1); + regs.eerd(0); + regs.icr(0); + regs.rctl(0); + regs.tctl(0); + regs.fcrtl(0); + regs.fcrth(1); + regs.manc(0); - regs.pba.rxa = 0x30; - regs.pba.txa = 0x10; + regs.pba.rxa(0x30); + regs.pba.txa(0x10); eeOpBits = 0; eeAddrBits = 0; @@ -78,8 +81,17 @@ IGbE::IGbE(Params *p) // clear all 64 16 bit words of the eeprom memset(&flash, 0, EEPROM_SIZE*2); + //We'll need to instert the MAC address into the flash + flash[0] = 0xA4A4; + flash[1] = 0xB6B6; + flash[2] = 0xC8C8; + + uint16_t csum = 0; + for (int x = 0; x < EEPROM_SIZE; x++) + csum += flash[x]; + // Magic happy checksum value - flash[0] = 0xBABA; + flash[EEPROM_SIZE-1] = htobe((uint16_t)(EEPROM_CSUM - csum)); } @@ -124,47 +136,112 @@ IGbE::read(PacketPtr pkt) switch (daddr) { - case CTRL: - pkt->set(regs.ctrl.reg); - break; - case STATUS: - pkt->set(regs.sts.reg); - break; - case EECD: - pkt->set(regs.eecd.reg); - break; - case EERD: - pkt->set(regs.eerd.reg); - break; - case ICR: - pkt->set(regs.icd.reg); - break; - case IMC: - pkt->set(regs.imc.reg); - break; - case RCTL: - pkt->set(regs.rctl.reg); - break; - case TCTL: - pkt->set(regs.tctl.reg); - break; - case PBA: - pkt->set(regs.pba.reg); - break; - case WUC: - case LEDCTL: - pkt->set(0); // We don't care, so just return 0 - break; - case MANC: - pkt->set(regs.manc.reg); - break; + case REG_CTRL: + pkt->set(regs.ctrl()); + break; + case REG_STATUS: + pkt->set(regs.sts()); + break; + case REG_EECD: + pkt->set(regs.eecd()); + break; + case REG_EERD: + pkt->set(regs.eerd()); + break; + case REG_CTRL_EXT: + pkt->set(regs.ctrl_ext()); + break; + case REG_MDIC: + pkt->set(regs.mdic()); + break; + case REG_ICR: + pkt->set(regs.icr()); + // handle auto setting mask from IAM + break; + case REG_ITR: + pkt->set(regs.itr()); + break; + case REG_RCTL: + pkt->set(regs.rctl()); + break; + case REG_FCTTV: + pkt->set(regs.fcttv()); + break; + case REG_TCTL: + pkt->set(regs.tctl()); + break; + case REG_PBA: + pkt->set(regs.pba()); + break; + case REG_WUC: + case REG_LEDCTL: + pkt->set(0); // We don't care, so just return 0 + break; + case REG_FCRTL: + pkt->set(regs.fcrtl()); + break; + case REG_FCRTH: + pkt->set(regs.fcrth()); + break; + case REG_RDBAL: + pkt->set(regs.rdba.rdbal()); + break; + case REG_RDBAH: + pkt->set(regs.rdba.rdbah()); + break; + case REG_RDLEN: + pkt->set(regs.rdlen()); + break; + case REG_RDH: + pkt->set(regs.rdh()); + break; + case REG_RDT: + pkt->set(regs.rdt()); + break; + case REG_RDTR: + pkt->set(regs.rdtr()); + break; + case REG_RADV: + pkt->set(regs.radv()); + break; + case REG_TDBAL: + pkt->set(regs.tdba.tdbal()); + break; + case REG_TDBAH: + pkt->set(regs.tdba.tdbah()); + break; + case REG_TDLEN: + pkt->set(regs.tdlen()); + break; + case REG_TDH: + pkt->set(regs.tdh()); + break; + case REG_TDT: + pkt->set(regs.tdt()); + break; + case REG_TIDV: + pkt->set(regs.tidv()); + break; + case REG_TXDCTL: + pkt->set(regs.txdctl()); + break; + case REG_TADV: + pkt->set(regs.tadv()); + break; + case REG_RXCSUM: + pkt->set(regs.rxcsum()); + break; + case REG_MANC: + pkt->set(regs.manc()); + break; default: - if (!(daddr >= VFTA && daddr < (VFTA + VLAN_FILTER_TABLE_SIZE)*4) && - !(daddr >= RAL && daddr < (RAL + RCV_ADDRESS_TABLE_SIZE)*4) && - !(daddr >= MTA && daddr < (MTA + MULTICAST_TABLE_SIZE)*4)) - pkt->set(0); - else - panic("Read request to unknown register number: %#x\n", daddr); + if (!(daddr >= REG_VFTA && daddr < (REG_VFTA + VLAN_FILTER_TABLE_SIZE*4)) && + !(daddr >= REG_RAL && daddr < (REG_RAL + RCV_ADDRESS_TABLE_SIZE*8)) && + !(daddr >= REG_MTA && daddr < (REG_MTA + MULTICAST_TABLE_SIZE*4)) && + !(daddr >= REG_CRCERRS && daddr < (REG_CRCERRS + STATS_REGS_SIZE))) + panic("Read request to unknown register number: %#x\n", daddr); + else + pkt->set(0); }; pkt->result = Packet::Success; @@ -195,92 +272,211 @@ IGbE::write(PacketPtr pkt) uint32_t val = pkt->get(); switch (daddr) { - case CTRL: - regs.ctrl.reg = val; - break; - case STATUS: - regs.sts.reg = val; - break; - case EECD: - int oldClk; - oldClk = regs.eecd.sk; - regs.eecd.reg = val; - // See if this is a eeprom access and emulate accordingly - if (!oldClk && regs.eecd.sk) { - if (eeOpBits < 8) { - eeOpcode = eeOpcode << 1 | regs.eecd.din; - eeOpBits++; - } else if (eeAddrBits < 8 && eeOpcode == EEPROM_READ_OPCODE_SPI) { - eeAddr = eeAddr << 1 | regs.eecd.din; - eeAddrBits++; - } else if (eeDataBits < 16 && eeOpcode == EEPROM_READ_OPCODE_SPI) { - assert(eeAddr>>1 < EEPROM_SIZE); - DPRINTF(EthernetEEPROM, "EEPROM bit read: %d word: %#X\n", - flash[eeAddr>>1] >> eeDataBits & 0x1, flash[eeAddr>>1]); - regs.eecd.dout = (flash[eeAddr>>1] >> (15-eeDataBits)) & 0x1; - eeDataBits++; - } else if (eeDataBits < 8 && eeOpcode == EEPROM_RDSR_OPCODE_SPI) { - regs.eecd.dout = 0; - eeDataBits++; - } else - panic("What's going on with eeprom interface? opcode:" - " %#x:%d addr: %#x:%d, data: %d\n", (uint32_t)eeOpcode, - (uint32_t)eeOpBits, (uint32_t)eeAddr, - (uint32_t)eeAddrBits, (uint32_t)eeDataBits); + case REG_CTRL: + regs.ctrl = val; + if (regs.ctrl.tfce()) + warn("TX Flow control enabled, should implement\n"); + if (regs.ctrl.rfce()) + warn("RX Flow control enabled, should implement\n"); + break; + case REG_CTRL_EXT: + regs.ctrl_ext = val; + break; + case REG_STATUS: + regs.sts = val; + break; + case REG_EECD: + int oldClk; + oldClk = regs.eecd.sk(); + regs.eecd = val; + // See if this is a eeprom access and emulate accordingly + if (!oldClk && regs.eecd.sk()) { + if (eeOpBits < 8) { + eeOpcode = eeOpcode << 1 | regs.eecd.din(); + eeOpBits++; + } else if (eeAddrBits < 8 && eeOpcode == EEPROM_READ_OPCODE_SPI) { + eeAddr = eeAddr << 1 | regs.eecd.din(); + eeAddrBits++; + } else if (eeDataBits < 16 && eeOpcode == EEPROM_READ_OPCODE_SPI) { + assert(eeAddr>>1 < EEPROM_SIZE); + DPRINTF(EthernetEEPROM, "EEPROM bit read: %d word: %#X\n", + flash[eeAddr>>1] >> eeDataBits & 0x1, flash[eeAddr>>1]); + regs.eecd.dout((flash[eeAddr>>1] >> (15-eeDataBits)) & 0x1); + eeDataBits++; + } else if (eeDataBits < 8 && eeOpcode == EEPROM_RDSR_OPCODE_SPI) { + regs.eecd.dout(0); + eeDataBits++; + } else + panic("What's going on with eeprom interface? opcode:" + " %#x:%d addr: %#x:%d, data: %d\n", (uint32_t)eeOpcode, + (uint32_t)eeOpBits, (uint32_t)eeAddr, + (uint32_t)eeAddrBits, (uint32_t)eeDataBits); - // Reset everything for the next command - if ((eeDataBits == 16 && eeOpcode == EEPROM_READ_OPCODE_SPI) || + // Reset everything for the next command + if ((eeDataBits == 16 && eeOpcode == EEPROM_READ_OPCODE_SPI) || (eeDataBits == 8 && eeOpcode == EEPROM_RDSR_OPCODE_SPI)) { - eeOpBits = 0; - eeAddrBits = 0; - eeDataBits = 0; + eeOpBits = 0; + eeAddrBits = 0; + eeDataBits = 0; eeOpcode = 0; - eeAddr = 0; - } + eeAddr = 0; + } DPRINTF(EthernetEEPROM, "EEPROM: opcode: %#X:%d addr: %#X:%d\n", - (uint32_t)eeOpcode, (uint32_t) eeOpBits, - (uint32_t)eeAddr>>1, (uint32_t)eeAddrBits); + (uint32_t)eeOpcode, (uint32_t) eeOpBits, + (uint32_t)eeAddr>>1, (uint32_t)eeAddrBits); if (eeOpBits == 8 && !(eeOpcode == EEPROM_READ_OPCODE_SPI || - eeOpcode == EEPROM_RDSR_OPCODE_SPI )) - panic("Unknown eeprom opcode: %#X:%d\n", (uint32_t)eeOpcode, - (uint32_t)eeOpBits); + eeOpcode == EEPROM_RDSR_OPCODE_SPI )) + panic("Unknown eeprom opcode: %#X:%d\n", (uint32_t)eeOpcode, + (uint32_t)eeOpBits); - } - // If driver requests eeprom access, immediately give it to it - regs.eecd.ee_gnt = regs.eecd.ee_req; - break; - case EERD: - regs.eerd.reg = val; - break; - case ICR: - regs.icd.reg = val; - break; - case IMC: - regs.imc.reg = val; - break; - case RCTL: - regs.rctl.reg = val; - break; - case TCTL: - regs.tctl.reg = val; - break; - case PBA: - regs.pba.rxa = val; - regs.pba.txa = 64 - regs.pba.rxa; - break; - case WUC: - case LEDCTL: - ; // We don't care, so don't store anything - break; - case MANC: - regs.manc.reg = val; - break; + } + // If driver requests eeprom access, immediately give it to it + regs.eecd.ee_gnt(regs.eecd.ee_req()); + break; + case REG_EERD: + regs.eerd = val; + break; + case REG_MDIC: + regs.mdic = val; + if (regs.mdic.i()) + panic("No support for interrupt on mdic complete\n"); + if (regs.mdic.phyadd() != 1) + panic("No support for reading anything but phy\n"); + DPRINTF(Ethernet, "%s phy address %x\n", regs.mdic.op() == 1 ? "Writing" + : "Reading", regs.mdic.regadd()); + switch (regs.mdic.regadd()) { + case PHY_PSTATUS: + regs.mdic.data(0x796D); // link up + break; + case PHY_PID: + regs.mdic.data(0x02A8); + break; + case PHY_EPID: + regs.mdic.data(0x0380); + break; + case PHY_GSTATUS: + regs.mdic.data(0x7C00); + break; + case PHY_EPSTATUS: + regs.mdic.data(0x3000); + break; + case PHY_AGC: + regs.mdic.data(0x180); // some random length + break; + default: + regs.mdic.data(0); + warn("Accessing unknown phy register %d\n", regs.mdic.regadd()); + } + regs.mdic.r(1); + break; + case REG_ICR: + regs.icr = val; + // handle auto setting mask from IAM + break; + case REG_ITR: + regs.itr = val; + break; + case REG_ICS: + regs.icr = val | regs.icr(); + // generate an interrupt if needed here + break; + case REG_IMS: + regs.imr |= val; + // handle interrupts if needed here + break; + case REG_IMC: + regs.imr |= ~val; + // handle interrupts if needed here + break; + case REG_IAM: + regs.iam = val; + break; + case REG_RCTL: + regs.rctl = val; + break; + case REG_FCTTV: + regs.fcttv = val; + break; + case REG_TCTL: + regs.tctl = val; + break; + case REG_PBA: + regs.pba.rxa(val); + regs.pba.txa(64 - regs.pba.rxa()); + break; + case REG_WUC: + case REG_LEDCTL: + case REG_FCAL: + case REG_FCAH: + case REG_FCT: + case REG_VET: + case REG_AIFS: + case REG_TIPG: + ; // We don't care, so don't store anything + break; + case REG_FCRTL: + regs.fcrtl = val; + break; + case REG_FCRTH: + regs.fcrth = val; + break; + case REG_RDBAL: + regs.rdba.rdbal( val & ~mask(4)); + break; + case REG_RDBAH: + regs.rdba.rdbah(val); + break; + case REG_RDLEN: + regs.rdlen = val & ~mask(7); + break; + case REG_RDH: + regs.rdh = val; + break; + case REG_RDT: + regs.rdt = val; + break; + case REG_RDTR: + regs.rdtr = val; + break; + case REG_RADV: + regs.radv = val; + break; + case REG_TDBAL: + regs.tdba.tdbal( val & ~mask(4)); + break; + case REG_TDBAH: + regs.tdba.tdbah(val); + break; + case REG_TDLEN: + regs.tdlen = val & ~mask(7); + break; + case REG_TDH: + regs.tdh = val; + break; + case REG_TDT: + regs.tdt = val; + break; + case REG_TIDV: + regs.tidv = val; + break; + case REG_TXDCTL: + regs.txdctl = val; + break; + case REG_TADV: + regs.tadv = val; + break; + case REG_RXCSUM: + regs.rxcsum = val; + break; + case REG_MANC: + regs.manc = val; + break; default: - if (!(daddr >= VFTA && daddr < (VFTA + VLAN_FILTER_TABLE_SIZE)*4) && - !(daddr >= RAL && daddr < (RAL + RCV_ADDRESS_TABLE_SIZE)*4) && - !(daddr >= MTA && daddr < (MTA + MULTICAST_TABLE_SIZE)*4)) + if (!(daddr >= REG_VFTA && daddr < (REG_VFTA + VLAN_FILTER_TABLE_SIZE*4)) && + !(daddr >= REG_RAL && daddr < (REG_RAL + RCV_ADDRESS_TABLE_SIZE*8)) && + !(daddr >= REG_MTA && daddr < (REG_MTA + MULTICAST_TABLE_SIZE*4))) panic("Write request to unknown register number: %#x\n", daddr); }; diff --git a/src/dev/i8254xGBe.hh b/src/dev/i8254xGBe.hh index ce4007263..fa9e65b22 100644 --- a/src/dev/i8254xGBe.hh +++ b/src/dev/i8254xGBe.hh @@ -54,13 +54,15 @@ class IGbE : public PciDev int eeOpBits, eeAddrBits, eeDataBits; uint8_t eeOpcode, eeAddr; + bool useFlowControl; + uint16_t flash[iGbReg::EEPROM_SIZE]; public: struct Params : public PciDev::Params { - ; + bool use_flow_control; }; IGbE(Params *params); diff --git a/src/dev/i8254xGBe_defs.hh b/src/dev/i8254xGBe_defs.hh index ae0925356..b59b34a67 100644 --- a/src/dev/i8254xGBe_defs.hh +++ b/src/dev/i8254xGBe_defs.hh @@ -31,47 +31,81 @@ /* @file * Register and structure descriptions for Intel's 8254x line of gigabit ethernet controllers. */ +#include "base/bitfield.hh" namespace iGbReg { -const uint32_t CTRL = 0x00000; //* -const uint32_t STATUS = 0x00008; //* -const uint32_t EECD = 0x00010; //* -const uint32_t EERD = 0x00014; //* -const uint32_t CTRL_EXT = 0x00018; -const uint32_t PBA = 0x01000; -const uint32_t ICR = 0x000C0; //* -const uint32_t ITR = 0x000C4; -const uint32_t ICS = 0x000C8; -const uint32_t IMS = 0x000D0; -const uint32_t IMC = 0x000D8; //* -const uint32_t RCTL = 0x00100; //* -const uint32_t RDBAL = 0x02800; -const uint32_t RDBAH = 0x02804; -const uint32_t RDLEN = 0x02808; -const uint32_t RDH = 0x02810; -const uint32_t RDT = 0x02818; -const uint32_t RDTR = 0x02820; -const uint32_t RADV = 0x0282C; -const uint32_t RSRPD = 0x02C00; -const uint32_t TCTL = 0x00400; //* -const uint32_t TDBAL = 0x03800; -const uint32_t TDBAH = 0x03804; -const uint32_t TDLEN = 0x03808; -const uint32_t TDH = 0x03810; -const uint32_t THT = 0x03818; -const uint32_t TIDV = 0x03820; -const uint32_t TXDMAC = 0x03000; -const uint32_t TXDCTL = 0x03828; -const uint32_t TADV = 0x0282C; -const uint32_t TSPMT = 0x03830; -const uint32_t RXDCTL = 0x02828; -const uint32_t RXCSUM = 0x05000; -const uint32_t MANC = 0x05820;//* +const uint32_t REG_CTRL = 0x00000; //* +const uint32_t REG_STATUS = 0x00008; //* +const uint32_t REG_EECD = 0x00010; //* +const uint32_t REG_EERD = 0x00014; //* +const uint32_t REG_CTRL_EXT = 0x00018; //*- +const uint32_t REG_MDIC = 0x00020; //* +const uint32_t REG_FCAL = 0x00028; //* +const uint32_t REG_FCAH = 0x0002C; //* +const uint32_t REG_FCT = 0x00030; //* +const uint32_t REG_VET = 0x00038; //* +const uint32_t REG_PBA = 0x01000; //* +const uint32_t REG_ICR = 0x000C0; //* +const uint32_t REG_ITR = 0x000C4; //* +const uint32_t REG_ICS = 0x000C8; //* +const uint32_t REG_IMS = 0x000D0; //* +const uint32_t REG_IMC = 0x000D8; //* +const uint32_t REG_IAM = 0x000E0; //* +const uint32_t REG_RCTL = 0x00100; //* +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_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_RDH = 0x02810; //*- +const uint32_t REG_RDT = 0x02818; //*- +const uint32_t REG_RDTR = 0x02820; //*- +const uint32_t REG_RXDCTL = 0x02828; //* +const uint32_t REG_RADV = 0x0282C; //*- +const uint32_t REG_RSRPD = 0x02C00; +const uint32_t REG_TCTL = 0x00400; //* +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_TDT = 0x03818; //* +const uint32_t REG_TIDV = 0x03820; //* +const uint32_t REG_TXDMAC = 0x03000; +const uint32_t REG_TXDCTL = 0x03828; //* +const uint32_t REG_TADV = 0x0382C; //* +const uint32_t REG_TSPMT = 0x03830; +const uint32_t REG_CRCERRS = 0x04000; +const uint32_t REG_RXCSUM = 0x05000; //*- +const uint32_t REG_MTA = 0x05200; +const uint32_t REG_RAL = 0x05400; +const uint32_t REG_RAH = 0x05404; +const uint32_t REG_VFTA = 0x05600; + +const uint32_t REG_WUC = 0x05800;//* +const uint32_t REG_MANC = 0x05820;//* const uint8_t EEPROM_READ_OPCODE_SPI = 0x03; const uint8_t EEPROM_RDSR_OPCODE_SPI = 0x05; 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 MULTICAST_TABLE_SIZE = 128; +const uint32_t STATS_REGS_SIZE = 0x124; + +const uint8_t PHY_PSTATUS = 0x1; +const uint8_t PHY_PID = 0x2; +const uint8_t PHY_EPID = 0x3; +const uint8_t PHY_GSTATUS = 10; +const uint8_t PHY_EPSTATUS = 15; +const uint8_t PHY_AGC = 18; + struct RxDesc { Addr buf; @@ -245,219 +279,377 @@ union TxDesc { } type; }; +#define ADD_FIELD32(NAME, OFFSET, BITS) \ + inline uint32_t NAME() { return bits(_data, OFFSET+BITS-1, OFFSET); } \ + inline void NAME(uint32_t d) { replaceBits(_data, OFFSET+BITS-1, OFFSET,d); } + +#define ADD_FIELD64(NAME, OFFSET, BITS) \ + inline uint64_t NAME() { return bits(_data, OFFSET+BITS-1, OFFSET); } \ + inline void NAME(uint64_t d) { replaceBits(_data, OFFSET+BITS-1, OFFSET,d); } + struct Regs { - union { // 0x0000 CTRL Register - uint32_t reg; - struct { - uint8_t fd:1; // full duplex - uint8_t bem:1; // big endian mode - uint8_t pcipr:1; // PCI priority - uint8_t lrst:1; // link reset - uint8_t tme:1; // test mode enable - uint8_t asde:1; // Auto-speed detection - uint8_t slu:1; // Set link up - uint8_t ilos:1; // invert los-of-signal - uint8_t speed:2; // speed selection bits - uint8_t be32:1; // big endian mode 32 - uint8_t frcspd:1; // force speed - uint8_t frcdpx:1; // force duplex - uint8_t duden:1; // dock/undock enable - uint8_t dudpol:1; // dock/undock polarity - uint8_t fphyrst:1; // force phy reset - uint8_t extlen:1; // external link status enable - uint8_t rsvd:1; // reserved - uint8_t sdp0d:1; // software controlled pin data - uint8_t sdp1d:1; // software controlled pin data - uint8_t sdp2d:1; // software controlled pin data - uint8_t sdp3d:1; // software controlled pin data - uint8_t sdp0i:1; // software controlled pin dir - uint8_t sdp1i:1; // software controlled pin dir - uint8_t sdp2i:1; // software controlled pin dir - uint8_t sdp3i:1; // software controlled pin dir - uint8_t rst:1; // reset - uint8_t rfce:1; // receive flow control enable - uint8_t tfce:1; // transmit flow control enable - uint8_t rte:1; // routing tag enable - uint8_t vme:1; // vlan enable - uint8_t phyrst:1; // phy reset - } ; - } ctrl; + template + struct Reg { + T _data; + T operator()() { return _data; } + const Reg &operator=(T d) { _data = d; return *this;} + bool operator==(T d) { return d == _data; } + void operator()(T d) { _data = d; } + }; - union { // 0x0008 STATUS - uint32_t reg; - struct { - uint8_t fd:1; // full duplex - uint8_t lu:1; // link up - uint8_t func:2; // function id - uint8_t txoff:1; // transmission paused - uint8_t tbimode:1; // tbi mode - uint8_t speed:2; // link speed - uint8_t asdv:2; // auto speed detection value - uint8_t mtxckok:1; // mtx clock running ok - uint8_t pci66:1; // In 66Mhz pci slot - uint8_t bus64:1; // in 64 bit slot - uint8_t pcix:1; // Pci mode - uint8_t pcixspd:1; // pci x speed - uint8_t reserved; // reserved - } ; - } sts; + struct CTRL : public Reg { // 0x0000 CTRL Register + using Reg::operator=; + ADD_FIELD32(fd,0,1); // full duplex + ADD_FIELD32(bem,1,1); // big endian mode + ADD_FIELD32(pcipr,2,1); // PCI priority + ADD_FIELD32(lrst,3,1); // link reset + ADD_FIELD32(tme,4,1); // test mode enable + ADD_FIELD32(asde,5,1); // Auto-speed detection + ADD_FIELD32(slu,6,1); // Set link up + ADD_FIELD32(ilos,7,1); // invert los-of-signal + ADD_FIELD32(speed,8,2); // speed selection bits + ADD_FIELD32(be32,10,1); // big endian mode 32 + ADD_FIELD32(frcspd,11,1); // force speed + ADD_FIELD32(frcdpx,12,1); // force duplex + ADD_FIELD32(duden,13,1); // dock/undock enable + ADD_FIELD32(dudpol,14,1); // dock/undock polarity + ADD_FIELD32(fphyrst,15,1); // force phy reset + ADD_FIELD32(extlen,16,1); // external link status enable + ADD_FIELD32(rsvd,17,1); // reserved + ADD_FIELD32(sdp0d,18,1); // software controlled pin data + ADD_FIELD32(sdp1d,19,1); // software controlled pin data + ADD_FIELD32(sdp2d,20,1); // software controlled pin data + ADD_FIELD32(sdp3d,21,1); // software controlled pin data + ADD_FIELD32(sdp0i,22,1); // software controlled pin dir + ADD_FIELD32(sdp1i,23,1); // software controlled pin dir + ADD_FIELD32(sdp2i,24,1); // software controlled pin dir + ADD_FIELD32(sdp3i,25,1); // software controlled pin dir + ADD_FIELD32(rst,26,1); // reset + ADD_FIELD32(rfce,27,1); // receive flow control enable + ADD_FIELD32(tfce,28,1); // transmit flow control enable + ADD_FIELD32(rte,29,1); // routing tag enable + ADD_FIELD32(vme,30,1); // vlan enable + ADD_FIELD32(phyrst,31,1); // phy reset + }; + CTRL ctrl; - union { // 0x0010 EECD - uint32_t reg; - struct { - uint8_t sk:1; // clack input to the eeprom - uint8_t cs:1; // chip select to eeprom - uint8_t din:1; // data input to eeprom - uint8_t dout:1; // data output bit - uint8_t fwe:2; // flash write enable - uint8_t ee_req:1; // request eeprom access - uint8_t ee_gnt:1; // grant eeprom access - uint8_t ee_pres:1; // eeprom present - uint8_t ee_size:1; // eeprom size - uint8_t ee_sz1:1; // eeprom size - uint8_t rsvd:2; // reserved - uint8_t ee_type:1; // type of eeprom - } ; - } eecd; + struct STATUS : public Reg { // 0x0008 STATUS Register + using Reg::operator=; + ADD_FIELD32(fd,0,1); // full duplex + ADD_FIELD32(lu,1,1); // link up + ADD_FIELD32(func,2,2); // function id + ADD_FIELD32(txoff,4,1); // transmission paused + ADD_FIELD32(tbimode,5,1); // tbi mode + ADD_FIELD32(speed,6,2); // link speed + ADD_FIELD32(asdv,8,2); // auto speed detection value + ADD_FIELD32(mtxckok,10,1); // mtx clock running ok + ADD_FIELD32(pci66,11,1); // In 66Mhz pci slot + ADD_FIELD32(bus64,12,1); // in 64 bit slot + ADD_FIELD32(pcix,13,1); // Pci mode + ADD_FIELD32(pcixspd,14,2); // pci x speed + }; + STATUS sts; - union { // 0x0014 EERD - uint32_t reg; - struct { - uint8_t start:1; // start read - uint8_t done:1; // done read - uint16_t addr:14; // address - uint16_t data; // data - }; - } eerd; + struct EECD : public Reg { // 0x0010 EECD Register + using Reg::operator=; + ADD_FIELD32(sk,0,1); // clack input to the eeprom + ADD_FIELD32(cs,1,1); // chip select to eeprom + ADD_FIELD32(din,2,1); // data input to eeprom + ADD_FIELD32(dout,3,1); // data output bit + ADD_FIELD32(fwe,4,2); // flash write enable + ADD_FIELD32(ee_req,6,1); // request eeprom access + ADD_FIELD32(ee_gnt,7,1); // grant eeprom access + ADD_FIELD32(ee_pres,8,1); // eeprom present + ADD_FIELD32(ee_size,9,1); // eeprom size + ADD_FIELD32(ee_sz1,10,1); // eeprom size + ADD_FIELD32(rsvd,11,2); // reserved + ADD_FIELD32(ee_type,13,1); // type of eeprom + } ; + EECD eecd; - union { // 0x00C0 ICR - uint32_t reg; - struct { - uint8_t txdw:1; // tx descr witten back - uint8_t txqe:1; // tx queue empty - uint8_t lsc:1; // link status change - uint8_t rxseq:1; // rcv sequence error - uint8_t rxdmt0:1; // rcv descriptor min thresh - uint8_t rsvd1:1; // reserved - uint8_t rxo:1; // receive overrunn - uint8_t rxt0:1; // receiver timer interrupt - uint8_t rsvd2:1; // reserved - uint8_t mdac:1; // mdi/o access complete - uint8_t rxcfg:1; // recv /c/ ordered sets - uint8_t rsvd3:1; // reserved - uint8_t phyint:1; // phy interrupt - uint8_t gpi1:1; // gpi int 1 - uint8_t gpi2:1; // gpi int 2 - uint8_t txdlow:1; // transmit desc low thresh - uint8_t srpd:1; // small receive packet detected - uint16_t rsvd4:15; // reserved - } ; - } icd; + struct EERD : public Reg { // 0x0014 EERD Register + using Reg::operator=; + ADD_FIELD32(start,0,1); // start read + ADD_FIELD32(done,4,1); // done read + ADD_FIELD32(addr,8,8); // address + ADD_FIELD32(data,16,16); // data + }; + EERD eerd; - union { // 0x00C0 IMC - uint32_t reg; - struct { - uint8_t txdw:1; // tx descr witten back - uint8_t txqe:1; // tx queue empty - uint8_t lsc:1; // link status change - uint8_t rxseq:1; // rcv sequence error - uint8_t rxdmt0:1; // rcv descriptor min thresh - uint8_t rsvd1:1; // reserved - uint8_t rxo:1; // receive overrunn - uint8_t rxt0:1; // receiver timer interrupt - uint8_t rsvd2:1; // reserved - uint8_t mdac:1; // mdi/o access complete - uint8_t rxcfg:1; // recv /c/ ordered sets - uint8_t rsvd3:1; // reserved - uint8_t phyint:1; // phy interrupt - uint8_t gpi1:1; // gpi int 1 - uint8_t gpi2:1; // gpi int 2 - uint8_t txdlow:1; // transmit desc low thresh - uint8_t srpd:1; // small receive packet detected - uint16_t rsvd4:15; // reserved - } ; - } imc; + struct CTRL_EXT : public Reg { // 0x0018 CTRL_EXT Register + using Reg::operator=; + ADD_FIELD32(gpi_en,0,4); // enable interrupts from gpio + ADD_FIELD32(phyint,5,1); // reads the phy internal int status + ADD_FIELD32(sdp2_data,6,1); // data from gpio sdp + ADD_FIELD32(spd3_data,7,1); // data frmo gpio sdp + ADD_FIELD32(spd2_iodir,10,1); // direction of sdp2 + ADD_FIELD32(spd3_iodir,11,1); // direction of sdp2 + ADD_FIELD32(asdchk,12,1); // initiate auto-speed-detection + ADD_FIELD32(eerst,13,1); // reset the eeprom + ADD_FIELD32(spd_byps,15,1); // bypass speed select + ADD_FIELD32(ro_dis,17,1); // disable relaxed memory ordering + ADD_FIELD32(vreg,21,1); // power down the voltage regulator + ADD_FIELD32(link_mode,22,2); // interface to talk to the link + ADD_FIELD32(iame, 27,1); // interrupt acknowledge auto-mask ?? + ADD_FIELD32(drv_loaded, 28,1);// driver is loaded and incharge of device + ADD_FIELD32(timer_clr, 29,1); // clear interrupt timers after IMS clear ?? + }; + CTRL_EXT ctrl_ext; - union { // 0x0100 RCTL - uint32_t reg; - struct { - uint8_t rst:1; // Reset - uint8_t en:1; // Enable - uint8_t sbp:1; // Store bad packets - uint8_t upe:1; // Unicast Promiscuous enabled - uint8_t mpe:1; // Multicast promiscuous enabled - uint8_t lpe:1; // long packet reception enabled - uint8_t lbm:2; // - uint8_t rdmts:2; // - uint8_t rsvd:2; // - uint8_t mo:2; // - uint8_t mdr:1; // - uint8_t bam:1; // - uint8_t bsize:2; // - uint8_t vpe:1; // - uint8_t cfien:1; // - uint8_t cfi:1; // - uint8_t rsvd2:1; // - uint8_t dpf:1; // discard pause frames - uint8_t pmcf:1; // pass mac control frames - uint8_t rsvd3:1; // reserved - uint8_t bsex:1; // buffer size extension - uint8_t secrc:1; // strip ethernet crc from incoming packet - uint8_t rsvd1:5; // reserved - } ; - } rctl; + struct MDIC : public Reg { // 0x0020 MDIC Register + using Reg::operator=; + ADD_FIELD32(data,0,16); // data + ADD_FIELD32(regadd,16,5); // register address + ADD_FIELD32(phyadd,21,5); // phy addresses + ADD_FIELD32(op,26,2); // opcode + ADD_FIELD32(r,28,1); // ready + ADD_FIELD32(i,29,1); // interrupt + ADD_FIELD32(e,30,1); // error + }; + MDIC mdic; - union { // 0x0400 TCTL - uint32_t reg; - struct { - uint8_t rst:1; // Reset - uint8_t en:1; // Enable - uint8_t bce:1; // busy check enable - uint8_t psp:1; // pad short packets - uint8_t ct:8; // collision threshold - uint16_t cold:10; // collision distance - uint8_t swxoff:1; // software xoff transmission - uint8_t pbe:1; // packet burst enable - uint8_t rtlc:1; // retransmit late collisions - uint8_t nrtu:1; // on underrun no TX - uint8_t mulr:1; // multiple request - uint8_t rsvd:5; // reserved - } ; - } tctl; + struct ICR : public Reg { // 0x00C0 ICR Register + using Reg::operator=; + ADD_FIELD32(txdw,0,1) // tx descr witten back + ADD_FIELD32(txqe,1,1) // tx queue empty + ADD_FIELD32(lsc,2,1) // link status change + ADD_FIELD32(rxseq,3,1) // rcv sequence error + ADD_FIELD32(rxdmt0,4,1) // rcv descriptor min thresh + ADD_FIELD32(rsvd1,5,1) // reserved + ADD_FIELD32(rxo,6,1) // receive overrunn + ADD_FIELD32(rxt0,7,1) // receiver timer interrupt + ADD_FIELD32(mdac,9,1) // mdi/o access complete + ADD_FIELD32(rxcfg,10,1) // recv /c/ ordered sets + ADD_FIELD32(phyint,12,1) // phy interrupt + ADD_FIELD32(gpi1,13,1) // gpi int 1 + ADD_FIELD32(gpi2,14,1) // gpi int 2 + ADD_FIELD32(txdlow,15,1) // transmit desc low thresh + ADD_FIELD32(srpd,16,1) // small receive packet detected + ADD_FIELD32(ack,17,1); // receive ack frame + ADD_FIELD32(int_assert, 31,0); // interrupt caused a system interrupt + }; + ICR icr; - union { // 0x5820 MANC - uint32_t reg; - struct { - uint8_t smbus:1; // SMBus enabled ##### - uint8_t asf:1; // ASF enabled ##### - uint8_t ronforce:1; // reset of force - uint8_t rsvd:5; // reserved - uint8_t rmcp1:1; // rcmp1 filtering - uint8_t rmcp2:1; // rcmp2 filtering - uint8_t ipv4:1; // enable ipv4 - uint8_t ipv6:1; // enable ipv6 - uint8_t snap:1; // accept snap - uint8_t arp:1; // filter arp ##### - uint8_t neighbor:1; // neighbor discovery - uint8_t arp_resp:1; // arp response - uint8_t tcorst:1; // tco reset happened - uint8_t rcvtco:1; // receive tco enabled ###### - uint8_t blkphyrst:1;// block phy resets ######## - uint8_t rcvall:1; // receive all - uint8_t macaddrfltr:1; // mac address filtering ###### - uint8_t mng2host:1; // mng2 host packets ####### - uint8_t ipaddrfltr:1; // ip address filtering - uint8_t xsumfilter:1; // checksum filtering - uint8_t brfilter:1; // broadcast filtering - uint8_t smbreq:1; // smb request - uint8_t smbgnt:1; // smb grant - uint8_t smbclkin:1; // smbclkin - uint8_t smbdatain:1; // smbdatain - uint8_t smbdataout:1; // smb data out - uint8_t smbclkout:1; // smb clock out - uint8_t rsvd2:2; - }; - } manc; + uint32_t imr; // register that contains the current interrupt mask + + struct ITR : public Reg { // 0x00C4 ITR Register + using Reg::operator=; + ADD_FIELD32(interval, 0,16); // minimum inter-interrutp inteval + // specified in 256ns interrupts + }; + ITR itr; + + // When CTRL_EXT.IAME and the ICR.INT_ASSERT is 1 an ICR read or write + // causes the IAM register contents to be written into the IMC + // automatically clearing all interrupts that have a bit in the IAM set + uint32_t iam; + + struct RCTL : public Reg { // 0x0100 RCTL Register + using Reg::operator=; + ADD_FIELD32(rst,0,1); // Reset + ADD_FIELD32(en,1,1); // Enable + ADD_FIELD32(sbp,2,1); // Store bad packets + ADD_FIELD32(upe,3,1); // Unicast Promiscuous enabled + ADD_FIELD32(mpe,4,1); // Multicast promiscuous enabled + ADD_FIELD32(lpe,5,1); // long packet reception enabled + ADD_FIELD32(lbm,6,2); // + ADD_FIELD32(rdmts,8,2); // + ADD_FIELD32(rsvd,10,2); // + ADD_FIELD32(mo,12,2); // + ADD_FIELD32(mdr,14,1); // + ADD_FIELD32(bam,15,1); // + ADD_FIELD32(bsize,16,2); // + ADD_FIELD32(vfe,18,1); // + ADD_FIELD32(cfien,19,1); // + ADD_FIELD32(cfi,20,1); // + ADD_FIELD32(rsvd2,21,1); // + ADD_FIELD32(dpf,22,1); // discard pause frames + ADD_FIELD32(pmcf,23,1); // pass mac control frames + ADD_FIELD32(bsex,25,1); // buffer size extension + ADD_FIELD32(secrc,26,1); // strip ethernet crc from incoming packet + }; + RCTL rctl; + + struct FCTTV : public Reg { // 0x0170 FCTTV + using Reg::operator=; + ADD_FIELD32(ttv,0,16); // Transmit Timer Value + }; + FCTTV fcttv; + + struct TCTL : public Reg { // 0x0400 TCTL Register + using Reg::operator=; + ADD_FIELD32(rst,0,1); // Reset + ADD_FIELD32(en,1,1); // Enable + ADD_FIELD32(bce,2,1); // busy check enable + ADD_FIELD32(psp,3,1); // pad short packets + ADD_FIELD32(ct,4,8); // collision threshold + ADD_FIELD32(cold,12,10); // collision distance + ADD_FIELD32(swxoff,22,1); // software xoff transmission + ADD_FIELD32(pbe,23,1); // packet burst enable + ADD_FIELD32(rtlc,24,1); // retransmit late collisions + ADD_FIELD32(nrtu,25,1); // on underrun no TX + ADD_FIELD32(mulr,26,1); // multiple request + }; + TCTL tctl; + + struct PBA : public Reg { // 0x1000 PBA Register + using Reg::operator=; + ADD_FIELD32(rxa,0,16); + ADD_FIELD32(txa,16,16); + }; + PBA pba; + + struct FCRTL : public Reg { // 0x2160 FCRTL Register + using Reg::operator=; + ADD_FIELD32(rtl,3,28); // make this bigger than the spec so we can have + // a larger buffer + ADD_FIELD32(xone, 31,1); + }; + FCRTL fcrtl; + + struct FCRTH : public Reg { // 0x2168 FCRTL Register + using Reg::operator=; + ADD_FIELD32(rth,3,13); // make this bigger than the spec so we can have + //a larger buffer + ADD_FIELD32(xfce, 31,1); + }; + FCRTH fcrth; + + struct RDBA : public Reg { // 0x2800 RDBA Register + using Reg::operator=; + ADD_FIELD64(rdbal,4,28); // base address of rx descriptor ring + ADD_FIELD64(rdbah,32,32); // base address of rx descriptor ring + }; + RDBA rdba; + + struct RDLEN : public Reg { // 0x2808 RDLEN Register + using Reg::operator=; + ADD_FIELD32(len,7,13); // number of bytes in the descriptor buffer + }; + RDLEN rdlen; + + struct RDH : public Reg { // 0x2810 RDH Register + using Reg::operator=; + ADD_FIELD32(rdh,0,16); // head of the descriptor ring + }; + RDH rdh; + + struct RDT : public Reg { // 0x2818 RDT Register + using Reg::operator=; + ADD_FIELD32(rdt,0,16); // tail of the descriptor ring + }; + RDT rdt; + + struct RDTR : public Reg { // 0x2820 RDTR Register + using Reg::operator=; + ADD_FIELD32(delay,0,16); // receive delay timer + ADD_FIELD32(fpd, 31,); // flush partial descriptor block ?? + }; + RDTR rdtr; + + struct RADV : public Reg { // 0x282C RADV Register + using Reg::operator=; + ADD_FIELD32(idv,0,16); // absolute interrupt delay + }; + RADV radv; + + struct RSRPD : public Reg { // 0x2C00 RSRPD Register + using Reg::operator=; + ADD_FIELD32(idv,0,12); // size to interrutp on small packets + }; + RSRPD rsrpd; + + struct TDBA : public Reg { // 0x3800 TDBAL Register + using Reg::operator=; + ADD_FIELD64(tdbal,4,28); // base address of transmit descriptor ring + ADD_FIELD64(tdbah,32,32); // base address of transmit descriptor ring + }; + TDBA tdba; + + struct TDLEN : public Reg { // 0x3808 TDLEN Register + using Reg::operator=; + ADD_FIELD32(len,7,13); // number of bytes in the descriptor buffer + }; + TDLEN tdlen; + + struct TDH : public Reg { // 0x3810 TDH Register + using Reg::operator=; + ADD_FIELD32(tdh,0,16); // head of the descriptor ring + }; + TDH tdh; + + struct TDT : public Reg { // 0x3818 TDT Register + using Reg::operator=; + ADD_FIELD32(tdt,0,16); // tail of the descriptor ring + }; + TDT tdt; + + struct TIDV : public Reg { // 0x3820 TIDV Register + using Reg::operator=; + ADD_FIELD32(idv,0,16); // interrupt delay + }; + TIDV tidv; + + struct TXDCTL : public Reg { // 0x3828 TXDCTL Register + using Reg::operator=; + ADD_FIELD32(pthresh, 0,6); // if number of descriptors control has is + // below this number, a prefetch is considered + ADD_FIELD32(hthresh,8,8); // number of valid descriptors is host memory + // before a prefetch is considered + ADD_FIELD32(wthresh,16,6); // number of descriptors to keep until + // writeback is considered + ADD_FIELD32(gran, 24,1); // granulatiry of above values (0 = cacheline, + // 1 == desscriptor) + ADD_FIELD32(lwthresh,25,7); // xmit descriptor low thresh, interrupt + // below this level + }; + TXDCTL txdctl; + + struct TADV : public Reg { // 0x382C TADV Register + using Reg::operator=; + ADD_FIELD32(idv,0,16); // absolute interrupt delay + }; + TADV tadv; + + struct RXCSUM : public Reg { // 0x5000 RXCSUM Register + using Reg::operator=; + ADD_FIELD32(pcss,0,8); + ADD_FIELD32(ipofld,8,1); + ADD_FIELD32(tuofld,9,1); + }; + RXCSUM rxcsum; + + struct MANC : public Reg { // 0x5820 MANC Register + using Reg::operator=; + ADD_FIELD32(smbus,0,1); // SMBus enabled ##### + ADD_FIELD32(asf,1,1); // ASF enabled ##### + ADD_FIELD32(ronforce,2,1); // reset of force + ADD_FIELD32(rsvd,3,5); // reserved + ADD_FIELD32(rmcp1,8,1); // rcmp1 filtering + ADD_FIELD32(rmcp2,9,1); // rcmp2 filtering + ADD_FIELD32(ipv4,10,1); // enable ipv4 + ADD_FIELD32(ipv6,11,1); // enable ipv6 + ADD_FIELD32(snap,12,1); // accept snap + ADD_FIELD32(arp,13,1); // filter arp ##### + ADD_FIELD32(neighbor,14,1); // neighbor discovery + ADD_FIELD32(arp_resp,15,1); // arp response + ADD_FIELD32(tcorst,16,1); // tco reset happened + ADD_FIELD32(rcvtco,17,1); // receive tco enabled ###### + ADD_FIELD32(blkphyrst,18,1);// block phy resets ######## + ADD_FIELD32(rcvall,19,1); // receive all + ADD_FIELD32(macaddrfltr,20,1); // mac address filtering ###### + ADD_FIELD32(mng2host,21,1); // mng2 host packets ####### + ADD_FIELD32(ipaddrfltr,22,1); // ip address filtering + ADD_FIELD32(xsumfilter,23,1); // checksum filtering + ADD_FIELD32(brfilter,24,1); // broadcast filtering + ADD_FIELD32(smbreq,25,1); // smb request + ADD_FIELD32(smbgnt,26,1); // smb grant + ADD_FIELD32(smbclkin,27,1); // smbclkin + ADD_FIELD32(smbdatain,28,1); // smbdatain + ADD_FIELD32(smbdataout,29,1); // smb data out + ADD_FIELD32(smbclkout,30,1); // smb clock out + }; + MANC manc; }; }; // iGbReg namespace