summaryrefslogtreecommitdiff
path: root/src/dev/i8254xGBe.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/dev/i8254xGBe.cc')
-rw-r--r--src/dev/i8254xGBe.cc156
1 files changed, 152 insertions, 4 deletions
diff --git a/src/dev/i8254xGBe.cc b/src/dev/i8254xGBe.cc
index 943e6881f..e52a3e73d 100644
--- a/src/dev/i8254xGBe.cc
+++ b/src/dev/i8254xGBe.cc
@@ -30,6 +30,9 @@
/* @file
* Device model for Intel's 8254x line of gigabit ethernet controllers.
+ * In particular an 82547 revision 2 (82547GI) MAC because it seems to have the
+ * fewest workarounds in the driver. It will probably work with most of the
+ * other MACs with slight modifications.
*/
#include "base/inet.hh"
@@ -39,10 +42,38 @@
#include "sim/stats.hh"
#include "sim/system.hh"
+using namespace iGbReg;
+
IGbE::IGbE(Params *p)
: PciDev(p), etherInt(NULL)
{
-
+ // 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;
+
+ eeOpBits = 0;
+ eeAddrBits = 0;
+ eeDataBits = 0;
+ eeOpcode = 0;
+
+ memset(&flash, 0, EEPROM_SIZE);
+ // Magic happy checksum value
+ flash[0] = 0xBABA;
}
@@ -74,15 +105,49 @@ IGbE::read(PacketPtr pkt)
// Only Memory register BAR is allowed
assert(bar == 0);
- DPRINTF(Ethernet, "Accessed devie register %#X\n", daddr);
+ // Only 32bit accesses allowed
+ assert(pkt->getSize() == 4);
- pkt->allocate();
+ DPRINTF(Ethernet, "Read device register %#X\n", daddr);
+ pkt->allocate();
///
/// Handle read of register here
///
+ 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 MANC:
+ pkt->set<uint32_t>(regs.manc.reg);
+ break;
+ default:
+ panic("Read request to unknown register number: %#x\n", daddr);
+ };
+
pkt->result = Packet::Success;
return pioDelay;
}
@@ -93,17 +158,100 @@ IGbE::write(PacketPtr pkt)
int bar;
Addr daddr;
+
if (!getBAR(pkt->getAddr(), bar, daddr))
panic("Invalid PCI memory access to unmapped memory.\n");
// Only Memory register BAR is allowed
assert(bar == 0);
- DPRINTF(Ethernet, "Accessed devie register %#X\n", daddr);
+ // Only 32bit accesses allowed
+ assert(pkt->getSize() == sizeof(uint32_t));
+
+ DPRINTF(Ethernet, "Wrote device register %#X value %#X\n", daddr, pkt->get<uint32_t>());
///
/// Handle write of register here
///
+ 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 < EEPROM_SIZE);
+ DPRINTF(Ethernet, "EEPROM bit read: %d word: %#X\n",
+ flash[eeAddr] >> eeDataBits & 0x1, flash[eeAddr]);
+ regs.eecd.dout = (flash[eeAddr] >> 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;
+ eeOpcode = 0;
+ eeAddr = 0;
+ }
+
+ DPRINTF(Ethernet, "EEPROM: opcode: %#X:%d\n",
+ (uint32_t)eeOpcode, (uint32_t) eeOpBits);
+ 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 MANC:
+ regs.manc.reg = val;
+ break;
+ default:
+ panic("Write request to unknown register number: %#x\n", daddr);
+ };
pkt->result = Packet::Success;
return pioDelay;