summaryrefslogtreecommitdiff
path: root/src/dev/i8254xGBe.cc
diff options
context:
space:
mode:
authorAli Saidi <saidi@eecs.umich.edu>2007-03-15 15:16:23 -0400
committerAli Saidi <saidi@eecs.umich.edu>2007-03-15 15:16:23 -0400
commit3a5a20769b2ba15905fc2e0a833a8ecbf3098646 (patch)
tree599ec2cc9b5dcc6a75ae42d7169d7087f3c8946a /src/dev/i8254xGBe.cc
parentc6188a226472c23f173b04b0fa86614cf717c9e7 (diff)
downloadgem5-3a5a20769b2ba15905fc2e0a833a8ecbf3098646.tar.xz
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
Diffstat (limited to 'src/dev/i8254xGBe.cc')
-rw-r--r--src/dev/i8254xGBe.cc480
1 files changed, 338 insertions, 142 deletions
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.pba.rxa = 0x30;
- regs.pba.txa = 0x10;
+ 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);
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<uint32_t>(regs.ctrl.reg);
- break;
- case STATUS:
- pkt->set<uint32_t>(regs.sts.reg);
- break;
- case EECD:
- pkt->set<uint32_t>(regs.eecd.reg);
- break;
- case EERD:
- pkt->set<uint32_t>(regs.eerd.reg);
- break;
- case ICR:
- pkt->set<uint32_t>(regs.icd.reg);
- break;
- case IMC:
- pkt->set<uint32_t>(regs.imc.reg);
- break;
- case RCTL:
- pkt->set<uint32_t>(regs.rctl.reg);
- break;
- case TCTL:
- pkt->set<uint32_t>(regs.tctl.reg);
- break;
- case PBA:
- pkt->set<uint32_t>(regs.pba.reg);
- break;
- case WUC:
- case LEDCTL:
- pkt->set<uint32_t>(0); // We don't care, so just return 0
- break;
- case MANC:
- pkt->set<uint32_t>(regs.manc.reg);
- break;
+ case REG_CTRL:
+ pkt->set<uint32_t>(regs.ctrl());
+ break;
+ case REG_STATUS:
+ pkt->set<uint32_t>(regs.sts());
+ break;
+ case REG_EECD:
+ pkt->set<uint32_t>(regs.eecd());
+ break;
+ case REG_EERD:
+ pkt->set<uint32_t>(regs.eerd());
+ break;
+ case REG_CTRL_EXT:
+ pkt->set<uint32_t>(regs.ctrl_ext());
+ break;
+ case REG_MDIC:
+ pkt->set<uint32_t>(regs.mdic());
+ break;
+ case REG_ICR:
+ pkt->set<uint32_t>(regs.icr());
+ // handle auto setting mask from IAM
+ break;
+ case REG_ITR:
+ pkt->set<uint32_t>(regs.itr());
+ break;
+ case REG_RCTL:
+ pkt->set<uint32_t>(regs.rctl());
+ break;
+ case REG_FCTTV:
+ pkt->set<uint32_t>(regs.fcttv());
+ break;
+ case REG_TCTL:
+ pkt->set<uint32_t>(regs.tctl());
+ break;
+ case REG_PBA:
+ pkt->set<uint32_t>(regs.pba());
+ break;
+ case REG_WUC:
+ case REG_LEDCTL:
+ pkt->set<uint32_t>(0); // We don't care, so just return 0
+ break;
+ case REG_FCRTL:
+ pkt->set<uint32_t>(regs.fcrtl());
+ break;
+ case REG_FCRTH:
+ pkt->set<uint32_t>(regs.fcrth());
+ break;
+ case REG_RDBAL:
+ pkt->set<uint32_t>(regs.rdba.rdbal());
+ break;
+ case REG_RDBAH:
+ pkt->set<uint32_t>(regs.rdba.rdbah());
+ break;
+ case REG_RDLEN:
+ pkt->set<uint32_t>(regs.rdlen());
+ break;
+ case REG_RDH:
+ pkt->set<uint32_t>(regs.rdh());
+ break;
+ case REG_RDT:
+ pkt->set<uint32_t>(regs.rdt());
+ break;
+ case REG_RDTR:
+ pkt->set<uint32_t>(regs.rdtr());
+ break;
+ case REG_RADV:
+ pkt->set<uint32_t>(regs.radv());
+ break;
+ case REG_TDBAL:
+ pkt->set<uint32_t>(regs.tdba.tdbal());
+ break;
+ case REG_TDBAH:
+ pkt->set<uint32_t>(regs.tdba.tdbah());
+ break;
+ case REG_TDLEN:
+ pkt->set<uint32_t>(regs.tdlen());
+ break;
+ case REG_TDH:
+ pkt->set<uint32_t>(regs.tdh());
+ break;
+ case REG_TDT:
+ pkt->set<uint32_t>(regs.tdt());
+ break;
+ case REG_TIDV:
+ pkt->set<uint32_t>(regs.tidv());
+ break;
+ case REG_TXDCTL:
+ pkt->set<uint32_t>(regs.txdctl());
+ break;
+ case REG_TADV:
+ pkt->set<uint32_t>(regs.tadv());
+ break;
+ case REG_RXCSUM:
+ pkt->set<uint32_t>(regs.rxcsum());
+ break;
+ case REG_MANC:
+ pkt->set<uint32_t>(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<uint32_t>(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<uint32_t>(0);
};
pkt->result = Packet::Success;
@@ -195,92 +272,211 @@ IGbE::write(PacketPtr pkt)
uint32_t val = pkt->get<uint32_t>();
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);
-
- // Reset everything for the next command
- if ((eeDataBits == 16 && eeOpcode == EEPROM_READ_OPCODE_SPI) ||
+ 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) ||
(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);
-
-
- }
- // 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;
+ 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 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);
};