diff options
Diffstat (limited to 'src/dev')
-rw-r--r-- | src/dev/SConscript | 74 | ||||
-rw-r--r-- | src/dev/alpha/SConscript | 43 | ||||
-rw-r--r-- | src/dev/alpha/tsunami_cchip.cc | 12 | ||||
-rw-r--r-- | src/dev/alpha/tsunamireg.h | 21 | ||||
-rw-r--r-- | src/dev/etherbus.cc | 2 | ||||
-rw-r--r-- | src/dev/etherdump.cc | 2 | ||||
-rw-r--r-- | src/dev/etherlink.cc | 2 | ||||
-rw-r--r-- | src/dev/i8254xGBe.cc | 1122 | ||||
-rw-r--r-- | src/dev/i8254xGBe.hh | 420 | ||||
-rw-r--r-- | src/dev/i8254xGBe_defs.hh | 957 | ||||
-rw-r--r-- | src/dev/ide_disk.cc | 2 | ||||
-rw-r--r-- | src/dev/io_device.hh | 14 | ||||
-rw-r--r-- | src/dev/ns_gige.cc | 26 | ||||
-rw-r--r-- | src/dev/pcidev.cc | 2 | ||||
-rw-r--r-- | src/dev/platform.hh | 3 | ||||
-rw-r--r-- | src/dev/simconsole.cc | 224 | ||||
-rw-r--r-- | src/dev/simconsole.hh | 76 | ||||
-rw-r--r-- | src/dev/sparc/SConscript | 23 | ||||
-rw-r--r-- | src/dev/sparc/iob.cc | 402 | ||||
-rw-r--r-- | src/dev/sparc/iob.hh | 153 | ||||
-rw-r--r-- | src/dev/sparc/mm_disk.cc | 2 | ||||
-rw-r--r-- | src/dev/uart.cc | 1 | ||||
-rw-r--r-- | src/dev/uart8250.hh | 13 |
23 files changed, 2696 insertions, 900 deletions
diff --git a/src/dev/SConscript b/src/dev/SConscript index 951bc29d1..ea529b536 100644 --- a/src/dev/SConscript +++ b/src/dev/SConscript @@ -29,51 +29,29 @@ # Authors: Steve Reinhardt # Gabe Black -import os.path, sys - -# Import build environment variable from SConstruct. -Import('env') - -# Right now there are no source files immediately in this directory -sources = [] - -# -# Now include other ISA-specific sources from the ISA subdirectories. -# - -isa = env['TARGET_ISA'] # someday this may be a list of ISAs - -# -# These source files can be used by any architecture -# - -sources += Split(''' - baddev.cc - disk_image.cc - etherbus.cc - etherdump.cc - etherint.cc - etherlink.cc - etherpkt.cc - ethertap.cc - ide_ctrl.cc - ide_disk.cc - io_device.cc - isa_fake.cc - ns_gige.cc - pciconfigall.cc - pcidev.cc - pktfifo.cc - platform.cc - simconsole.cc - simple_disk.cc - ''') - -# Let the target architecture define what additional sources it needs -sources += SConscript(os.path.join(isa, 'SConscript'), exports = 'env') - -# Convert file names to SCons File objects. This takes care of the -# path relative to the top of the directory tree. -sources = [File(s) for s in sources] - -Return('sources') +Import('*') + +if env['FULL_SYSTEM']: + Source('baddev.cc') + Source('disk_image.cc') + Source('etherbus.cc') + Source('etherdump.cc') + Source('etherint.cc') + Source('etherlink.cc') + Source('etherpkt.cc') + Source('ethertap.cc') + Source('i8254xGBe.cc') + Source('ide_ctrl.cc') + Source('ide_disk.cc') + Source('io_device.cc') + Source('isa_fake.cc') + Source('ns_gige.cc') + Source('pciconfigall.cc') + Source('pcidev.cc') + Source('pktfifo.cc') + Source('platform.cc') + Source('simconsole.cc') + Source('simple_disk.cc') + #Source('sinic.cc') + Source('uart.cc') + Source('uart8250.cc') diff --git a/src/dev/alpha/SConscript b/src/dev/alpha/SConscript index fb0e626d3..c985fdd9f 100644 --- a/src/dev/alpha/SConscript +++ b/src/dev/alpha/SConscript @@ -29,40 +29,11 @@ # Authors: Steve Reinhardt # Gabe Black -import os.path, sys +Import('*') -# Import build environment variable from SConstruct. -Import('env') - -sources = Split(''' - console.cc - tsunami.cc - tsunami_cchip.cc - tsunami_io.cc - tsunami_pchip.cc - ''') -# baddev.cc -# disk_image.cc -# etherbus.cc -# etherdump.cc -# etherint.cc -# etherlink.cc -# etherpkt.cc -# ethertap.cc -# ide_ctrl.cc -# ide_disk.cc -# io_device.cc -# isa_fake.cc -# ns_gige.cc -# pciconfigall.cc -# pcidev.cc -# pktfifo.cc -# platform.cc -# simconsole.cc -# simple_disk.cc - -# Convert file names to SCons File objects. This takes care of the -# path relative to the top of the directory tree. -sources = [File(s) for s in sources] - -Return('sources') +if env['FULL_SYSTEM'] and env['TARGET_ISA'] == 'alpha': + Source('console.cc') + Source('tsunami.cc') + Source('tsunami_cchip.cc') + Source('tsunami_io.cc') + Source('tsunami_pchip.cc') diff --git a/src/dev/alpha/tsunami_cchip.cc b/src/dev/alpha/tsunami_cchip.cc index 15c47984b..118160adf 100644 --- a/src/dev/alpha/tsunami_cchip.cc +++ b/src/dev/alpha/tsunami_cchip.cc @@ -372,7 +372,7 @@ TsunamiCChip::write(PacketPtr pkt) void TsunamiCChip::clearIPI(uint64_t ipintr) { - int numcpus = tsunami->intrctrl->cpu->system->threadContexts.size(); + int numcpus = sys->threadContexts.size(); assert(numcpus <= Tsunami::Max_CPUs); if (ipintr) { @@ -398,7 +398,7 @@ TsunamiCChip::clearIPI(uint64_t ipintr) void TsunamiCChip::clearITI(uint64_t itintr) { - int numcpus = tsunami->intrctrl->cpu->system->threadContexts.size(); + int numcpus = sys->threadContexts.size(); assert(numcpus <= Tsunami::Max_CPUs); if (itintr) { @@ -418,7 +418,7 @@ TsunamiCChip::clearITI(uint64_t itintr) void TsunamiCChip::reqIPI(uint64_t ipreq) { - int numcpus = tsunami->intrctrl->cpu->system->threadContexts.size(); + int numcpus = sys->threadContexts.size(); assert(numcpus <= Tsunami::Max_CPUs); if (ipreq) { @@ -445,7 +445,7 @@ TsunamiCChip::reqIPI(uint64_t ipreq) void TsunamiCChip::postRTC() { - int size = tsunami->intrctrl->cpu->system->threadContexts.size(); + int size = sys->threadContexts.size(); assert(size <= Tsunami::Max_CPUs); for (int i = 0; i < size; i++) { @@ -463,7 +463,7 @@ void TsunamiCChip::postDRIR(uint32_t interrupt) { uint64_t bitvector = ULL(1) << interrupt; - uint64_t size = tsunami->intrctrl->cpu->system->threadContexts.size(); + uint64_t size = sys->threadContexts.size(); assert(size <= Tsunami::Max_CPUs); drir |= bitvector; @@ -481,7 +481,7 @@ void TsunamiCChip::clearDRIR(uint32_t interrupt) { uint64_t bitvector = ULL(1) << interrupt; - uint64_t size = tsunami->intrctrl->cpu->system->threadContexts.size(); + uint64_t size = sys->threadContexts.size(); assert(size <= Tsunami::Max_CPUs); if (drir & bitvector) diff --git a/src/dev/alpha/tsunamireg.h b/src/dev/alpha/tsunamireg.h index d603972be..a2742e36d 100644 --- a/src/dev/alpha/tsunamireg.h +++ b/src/dev/alpha/tsunamireg.h @@ -136,15 +136,6 @@ /* Added for keyboard accesses */ #define TSDEV_KBD 0x64 -/* Added for ATA PCI DMA */ -#define ATA_PCI_DMA 0x00 -#define ATA_PCI_DMA2 0x02 -#define ATA_PCI_DMA3 0x16 -#define ATA_PCI_DMA4 0x17 -#define ATA_PCI_DMA5 0x1a -#define ATA_PCI_DMA6 0x11 -#define ATA_PCI_DMA7 0x14 - #define TSDEV_RTC_ADDR 0x70 #define TSDEV_RTC_DATA 0x71 @@ -155,18 +146,6 @@ #define TSUNAMI_PCI0_IO TSUNAMI_UNCACHABLE_BIT + PCHIP_PCI0_IO -// UART Defines -#define UART_IER_RDI 0x01 -#define UART_IER_THRI 0x02 -#define UART_IER_RLSI 0x04 - - -#define UART_LSR_TEMT 0x40 -#define UART_LSR_THRE 0x20 -#define UART_LSR_DR 0x01 - -#define UART_MCR_LOOP 0x10 - // System Control PortB Status Bits #define PORTB_SPKR_HIGH 0x20 diff --git a/src/dev/etherbus.cc b/src/dev/etherbus.cc index 348bb818a..cedb3cd4d 100644 --- a/src/dev/etherbus.cc +++ b/src/dev/etherbus.cc @@ -43,7 +43,7 @@ #include "dev/etherint.hh" #include "dev/etherpkt.hh" #include "sim/builder.hh" -#include "sim/root.hh" +#include "sim/core.hh" using namespace std; diff --git a/src/dev/etherdump.cc b/src/dev/etherdump.cc index 0c986cc21..04463f3ee 100644 --- a/src/dev/etherdump.cc +++ b/src/dev/etherdump.cc @@ -41,7 +41,7 @@ #include "base/output.hh" #include "dev/etherdump.hh" #include "sim/builder.hh" -#include "sim/root.hh" +#include "sim/core.hh" using std::string; diff --git a/src/dev/etherlink.cc b/src/dev/etherlink.cc index cd3812270..5d30e1744 100644 --- a/src/dev/etherlink.cc +++ b/src/dev/etherlink.cc @@ -47,7 +47,7 @@ #include "sim/builder.hh" #include "sim/serialize.hh" #include "sim/system.hh" -#include "sim/root.hh" +#include "sim/core.hh" using namespace std; diff --git a/src/dev/i8254xGBe.cc b/src/dev/i8254xGBe.cc index 7fc68f4e7..d6449f6c5 100644 --- a/src/dev/i8254xGBe.cc +++ b/src/dev/i8254xGBe.cc @@ -35,7 +35,13 @@ * other MACs with slight modifications. */ + +/* + * @todo really there are multiple dma engines.. we should implement them. + */ + #include "base/inet.hh" +#include "base/trace.hh" #include "dev/i8254xGBe.hh" #include "mem/packet.hh" #include "mem/packet_access.hh" @@ -43,32 +49,37 @@ #include "sim/stats.hh" #include "sim/system.hh" +#include <algorithm> + using namespace iGbReg; +using namespace Net; IGbE::IGbE(Params *p) - : PciDev(p), etherInt(NULL) + : PciDev(p), etherInt(NULL), useFlowControl(p->use_flow_control), + rxFifo(p->rx_fifo_size), txFifo(p->tx_fifo_size), rxTick(false), + txTick(false), rdtrEvent(this), radvEvent(this), tadvEvent(this), + tidvEvent(this), tickEvent(this), interEvent(this), + rxDescCache(this, name()+".TxDesc", p->rx_desc_cache_size), + txDescCache(this, name()+".RxDesc", p->tx_desc_cache_size), clock(p->clock) { // 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; + // All registers intialized to 0 by per register constructor + regs.ctrl.fd(1); + regs.ctrl.lrst(1); + regs.ctrl.speed(2); + regs.ctrl.frcspd(1); + regs.sts.speed(3); // Say we're 1000Mbps + regs.sts.fd(1); // full duplex + regs.eecd.fwe(1); + regs.eecd.ee_type(1); + regs.imr = 0; + regs.iam = 0; + regs.rxdctl.gran(1); + regs.rxdctl.wthresh(1); + regs.fcrth(1); + + regs.pba.rxa(0x30); + regs.pba.txa(0x10); eeOpBits = 0; eeAddrBits = 0; @@ -78,8 +89,20 @@ 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)); + + rxFifo.clear(); + txFifo.clear(); } @@ -124,47 +147,129 @@ 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()); + if (regs.icr.int_assert()) + regs.imr &= regs.iam; + if (regs.imr == 0 || (regs.icr.int_assert() && regs.ctrl_ext.iame())) { + regs.icr(0); + cpuClearInt(); + } + 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()); + if (regs.rdtr.fpd()) { + rxDescCache.writeback(0); + postInterrupt(IT_RXT); + regs.rdtr.fpd(0); + } + if (regs.rdtr.delay()) { + Tick t = regs.rdtr.delay() * Clock::Int::ns * 1024; + if (rdtrEvent.scheduled()) + rdtrEvent.reschedule(curTick + t); + else + rdtrEvent.schedule(curTick + t); + } + 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; @@ -194,93 +299,253 @@ IGbE::write(PacketPtr pkt) /// uint32_t val = pkt->get<uint32_t>(); + Regs::RCTL oldrctl; + Regs::TCTL oldtctl; + 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: + if (regs.icr.int_assert()) + regs.imr &= regs.iam; + + regs.icr = ~bits(val,30,0) & regs.icr(); + // if no more bits are set clear the int_asserted bit + if (!bits(regs.icr(),31,31)) + cpuClearInt(); + + break; + case REG_ITR: + regs.itr = val; + break; + case REG_ICS: + postInterrupt((IntTypes)val); + break; + case REG_IMS: + regs.imr |= val; + chkInterrupt(); + break; + case REG_IMC: + regs.imr &= ~val; + chkInterrupt(); + break; + case REG_IAM: + regs.iam = val; + break; + case REG_RCTL: + oldrctl = regs.rctl; + regs.rctl = val; + if (regs.rctl.rst()) { + rxDescCache.reset(); + rxFifo.clear(); + regs.rctl.rst(0); + } + if (regs.rctl.en()) + rxTick = true; + if ((rxTick || txTick) && !tickEvent.scheduled()) + tickEvent.schedule(curTick + cycles(1)); + break; + case REG_FCTTV: + regs.fcttv = val; + break; + case REG_TCTL: + regs.tctl = val; + oldtctl = regs.tctl; + regs.tctl = val; + if (regs.tctl.en()) + txTick = true; + if ((rxTick || txTick) && !tickEvent.scheduled()) + tickEvent.schedule(curTick + cycles(1)); + if (regs.tctl.en() && !oldtctl.en()) { + txDescCache.reset(); + } + 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)); + rxDescCache.areaChanged(); + break; + case REG_RDBAH: + regs.rdba.rdbah(val); + rxDescCache.areaChanged(); + break; + case REG_RDLEN: + regs.rdlen = val & ~mask(7); + rxDescCache.areaChanged(); + break; + case REG_RDH: + regs.rdh = val; + rxDescCache.areaChanged(); + break; + case REG_RDT: + regs.rdt = val; + rxTick = true; + if ((rxTick || txTick) && !tickEvent.scheduled()) + tickEvent.schedule(curTick + cycles(1)); + break; + case REG_RDTR: + regs.rdtr = val; + break; + case REG_RADV: + regs.radv = val; + break; + case REG_TDBAL: + regs.tdba.tdbal( val & ~mask(4)); + txDescCache.areaChanged(); + break; + case REG_TDBAH: + regs.tdba.tdbah(val); + txDescCache.areaChanged(); + break; + case REG_TDLEN: + regs.tdlen = val & ~mask(7); + txDescCache.areaChanged(); + break; + case REG_TDH: + regs.tdh = val; + txDescCache.areaChanged(); + break; + case REG_TDT: + regs.tdt = val; + txTick = true; + if ((rxTick || txTick) && !tickEvent.scheduled()) + tickEvent.schedule(curTick + cycles(1)); + 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); }; @@ -288,18 +553,585 @@ IGbE::write(PacketPtr pkt) return pioDelay; } +void +IGbE::postInterrupt(IntTypes t, bool now) +{ + // Interrupt is already pending + if (t & regs.icr()) + return; + + if (regs.icr() & regs.imr) + { + // already in an interrupt state, set new int and done + regs.icr = regs.icr() | t; + } else { + regs.icr = regs.icr() | t; + if (regs.itr.interval() == 0 || now) { + if (now) { + if (interEvent.scheduled()) + interEvent.deschedule(); + } + cpuPostInt(); + } else { + DPRINTF(EthernetIntr, "EINT: Scheduling timer interrupt for %d ticks\n", + Clock::Int::ns * 256 * regs.itr.interval()); + assert(!interEvent.scheduled()); + interEvent.schedule(curTick + Clock::Int::ns * 256 * regs.itr.interval()); + } + } +} + +void +IGbE::cpuPostInt() +{ + if (rdtrEvent.scheduled()) { + regs.icr.rxt0(1); + rdtrEvent.deschedule(); + } + if (radvEvent.scheduled()) { + regs.icr.rxt0(1); + radvEvent.deschedule(); + } + if (tadvEvent.scheduled()) { + regs.icr.txdw(1); + tadvEvent.deschedule(); + } + if (tidvEvent.scheduled()) { + regs.icr.txdw(1); + tidvEvent.deschedule(); + } + + regs.icr.int_assert(1); + DPRINTF(EthernetIntr, "EINT: Posting interrupt to CPU now. Vector %#x\n", + regs.icr()); + intrPost(); +} + +void +IGbE::cpuClearInt() +{ + regs.icr.int_assert(0); + DPRINTF(EthernetIntr, "EINT: Clearing interrupt to CPU now. Vector %#x\n", + regs.icr()); + intrClear(); +} + +void +IGbE::chkInterrupt() +{ + // Check if we need to clear the cpu interrupt + if (!(regs.icr() & regs.imr)) + cpuClearInt(); + + // Check if we need to set the cpu interupt + postInterrupt(IT_NONE); +} + + +IGbE::RxDescCache::RxDescCache(IGbE *i, const std::string n, int s) + : DescCache<RxDesc>(i, n, s), pktDone(false), pktEvent(this) + +{ +} bool -IGbE::ethRxPkt(EthPacketPtr packet) +IGbE::RxDescCache::writePacket(EthPacketPtr packet) { - panic("Need to implemenet\n"); + // We shouldn't have to deal with any of these yet + assert(packet->length < igbe->regs.rctl.descSize()); + + if (!unusedCache.size()) + return false; + + pktPtr = packet; + + igbe->dmaWrite(unusedCache.front()->buf, packet->length, &pktEvent, packet->data); + return true; +} + +void +IGbE::RxDescCache::pktComplete() +{ + assert(unusedCache.size()); + RxDesc *desc; + desc = unusedCache.front(); + + desc->len = pktPtr->length; + // no support for anything but starting at 0 + assert(igbe->regs.rxcsum.pcss() == 0); + + DPRINTF(EthernetDesc, "RxDesc: Packet written to memory updating Descriptor\n"); + + uint8_t status = RXDS_DD | RXDS_EOP; + uint8_t err = 0; + IpPtr ip(pktPtr); + if (ip) { + if (igbe->regs.rxcsum.ipofld()) { + DPRINTF(EthernetDesc, "RxDesc: Checking IP checksum\n"); + status |= RXDS_IPCS; + desc->csum = cksum(ip); + if (cksum(ip) != 0) { + err |= RXDE_IPE; + DPRINTF(EthernetDesc, "RxDesc: Checksum is bad!!\n"); + } + } + TcpPtr tcp(ip); + if (tcp && igbe->regs.rxcsum.tuofld()) { + DPRINTF(EthernetDesc, "RxDesc: Checking TCP checksum\n"); + status |= RXDS_TCPCS; + desc->csum = cksum(tcp); + if (cksum(tcp) != 0) { + DPRINTF(EthernetDesc, "RxDesc: Checksum is bad!!\n"); + err |= RXDE_TCPE; + } + } + + UdpPtr udp(ip); + if (udp && igbe->regs.rxcsum.tuofld()) { + DPRINTF(EthernetDesc, "RxDesc: Checking UDP checksum\n"); + status |= RXDS_UDPCS; + desc->csum = cksum(udp); + if (cksum(tcp) != 0) { + DPRINTF(EthernetDesc, "RxDesc: Checksum is bad!!\n"); + err |= RXDE_TCPE; + } + } + } // if ip + + desc->status = status; + desc->errors = 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()) { + DPRINTF(EthernetSM, "RXS: Scheduling DTR for %d\n", + igbe->regs.rdtr.delay() * igbe->intClock()); + if (igbe->rdtrEvent.scheduled()) + igbe->rdtrEvent.reschedule(curTick + igbe->regs.rdtr.delay() * + igbe->intClock()); + else + igbe->rdtrEvent.schedule(curTick + igbe->regs.rdtr.delay() * + igbe->intClock()); + } + + if (igbe->regs.radv.idv() && igbe->regs.rdtr.delay()) { + DPRINTF(EthernetSM, "RXS: Scheduling ADV for %d\n", + igbe->regs.radv.idv() * igbe->intClock()); + if (!igbe->radvEvent.scheduled()) + igbe->radvEvent.schedule(curTick + igbe->regs.radv.idv() * + igbe->intClock()); + } + + // If the packet is small enough, interrupt appropriately + if (pktPtr->length <= igbe->regs.rsrpd.idv()) + igbe->postInterrupt(IT_SRPD); + + DPRINTF(EthernetDesc, "RxDesc: Processing of this descriptor complete\n"); + unusedCache.pop_front(); + usedCache.push_back(desc); + pktPtr = NULL; + enableSm(); + pktDone = true; +} + +void +IGbE::RxDescCache::enableSm() +{ + igbe->rxTick = true; + if ((igbe->rxTick || igbe->txTick) && !igbe->tickEvent.scheduled()) + igbe->tickEvent.schedule((curTick/igbe->cycles(1)) * igbe->cycles(1) + + igbe->cycles(1)); +} + +bool +IGbE::RxDescCache::packetDone() +{ + if (pktDone) { + pktDone = false; + return true; + } + return false; +} + +///////////////////////////////////// IGbE::TxDesc ///////////////////////////////// + +IGbE::TxDescCache::TxDescCache(IGbE *i, const std::string n, int s) + : DescCache<TxDesc>(i,n, s), pktDone(false), isTcp(false), pktWaiting(false), + pktEvent(this) + +{ +} + +int +IGbE::TxDescCache::getPacketSize() +{ + assert(unusedCache.size()); + + TxDesc *desc; + + DPRINTF(EthernetDesc, "TxDesc: Starting processing of descriptor\n"); + + while (unusedCache.size() && TxdOp::isContext(unusedCache.front())) { + DPRINTF(EthernetDesc, "TxDesc: Got context descriptor type... skipping\n"); + + // I think we can just ignore these for now? + desc = unusedCache.front(); + // is this going to be a tcp or udp packet? + isTcp = TxdOp::tcp(desc) ? true : false; + + // make sure it's ipv4 + assert(TxdOp::ip(desc)); + + TxdOp::setDd(desc); + unusedCache.pop_front(); + usedCache.push_back(desc); + } + + if (!unusedCache.size()) + return -1; + + DPRINTF(EthernetDesc, "TxDesc: Next TX packet is %d bytes\n", + TxdOp::getLen(unusedCache.front())); + + return TxdOp::getLen(unusedCache.front()); +} + +void +IGbE::TxDescCache::getPacketData(EthPacketPtr p) +{ + assert(unusedCache.size()); + + TxDesc *desc; + desc = unusedCache.front(); + + assert((TxdOp::isLegacy(desc) || TxdOp::isData(desc)) && TxdOp::getLen(desc)); + + pktPtr = p; + + pktWaiting = true; + + DPRINTF(EthernetDesc, "TxDesc: Starting DMA of packet\n"); + igbe->dmaRead(TxdOp::getBuf(desc), TxdOp::getLen(desc), &pktEvent, p->data); + + +} + +void +IGbE::TxDescCache::pktComplete() +{ + + TxDesc *desc; + assert(unusedCache.size()); + assert(pktPtr); + + DPRINTF(EthernetDesc, "TxDesc: DMA of packet complete\n"); + + desc = unusedCache.front(); + assert((TxdOp::isLegacy(desc) || TxdOp::isData(desc)) && TxdOp::getLen(desc)); + + // no support for vlans + assert(!TxdOp::vle(desc)); + + // we alway report status + assert(TxdOp::rs(desc)); + + // we only support single packet descriptors at this point + assert(TxdOp::eop(desc)); + + // set that this packet is done + TxdOp::setDd(desc); + + // Checksums are only ofloaded for new descriptor types + if (TxdOp::isData(desc) && ( TxdOp::ixsm(desc) || TxdOp::txsm(desc)) ) { + DPRINTF(EthernetDesc, "TxDesc: Calculating checksums for packet\n"); + IpPtr ip(pktPtr); + if (TxdOp::ixsm(desc)) { + ip->sum(0); + ip->sum(cksum(ip)); + DPRINTF(EthernetDesc, "TxDesc: Calculated IP checksum\n"); + } + if (TxdOp::txsm(desc)) { + if (isTcp) { + TcpPtr tcp(ip); + tcp->sum(0); + tcp->sum(cksum(tcp)); + DPRINTF(EthernetDesc, "TxDesc: Calculated TCP checksum\n"); + } else { + UdpPtr udp(ip); + udp->sum(0); + udp->sum(cksum(udp)); + DPRINTF(EthernetDesc, "TxDesc: Calculated UDP checksum\n"); + } + } + } + + if (TxdOp::ide(desc)) { + // Deal with the rx timer interrupts + DPRINTF(EthernetDesc, "TxDesc: Descriptor had IDE set\n"); + if (igbe->regs.tidv.idv()) { + DPRINTF(EthernetDesc, "TxDesc: setting tidv\n"); + if (igbe->tidvEvent.scheduled()) + igbe->tidvEvent.reschedule(curTick + igbe->regs.tidv.idv() * + igbe->intClock()); + else + igbe->tidvEvent.schedule(curTick + igbe->regs.tidv.idv() * + igbe->intClock()); + } + + if (igbe->regs.tadv.idv() && igbe->regs.tidv.idv()) { + DPRINTF(EthernetDesc, "TxDesc: setting tadv\n"); + if (!igbe->tadvEvent.scheduled()) + igbe->tadvEvent.schedule(curTick + igbe->regs.tadv.idv() * + igbe->intClock()); + } + } + + unusedCache.pop_front(); + usedCache.push_back(desc); + pktDone = true; + pktWaiting = false; + pktPtr = NULL; + + DPRINTF(EthernetDesc, "TxDesc: Descriptor Done\n"); +} + +bool +IGbE::TxDescCache::packetAvailable() +{ + if (pktDone) { + pktDone = false; + return true; + } + return false; +} + +void +IGbE::TxDescCache::enableSm() +{ + igbe->txTick = true; + if ((igbe->rxTick || igbe->txTick) && !igbe->tickEvent.scheduled()) + igbe->tickEvent.schedule((curTick/igbe->cycles(1)) * igbe->cycles(1) + + igbe->cycles(1)); +} + + + + +///////////////////////////////////// IGbE ///////////////////////////////// + +void +IGbE::txStateMachine() +{ + if (!regs.tctl.en()) { + txTick = false; + DPRINTF(EthernetSM, "TXS: RX disabled, stopping ticking\n"); + return; + } + + if (txPacket && txDescCache.packetAvailable()) { + bool success; + DPRINTF(EthernetSM, "TXS: packet placed in TX FIFO\n"); + success = txFifo.push(txPacket); + assert(success); + txPacket = NULL; + return; + } + + // 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); + } + + if (!txPacket) { + txPacket = new EthPacketData(16384); + } + + if (!txDescCache.packetWaiting()) { + if (txDescCache.descLeft() == 0) { + DPRINTF(EthernetSM, "TXS: No descriptors left in ring, forcing writeback\n"); + txDescCache.writeback(0); + DPRINTF(EthernetSM, "TXS: No descriptors left, stopping ticking\n"); + txTick = false; + } + + if (!(txDescCache.descUnused())) { + DPRINTF(EthernetSM, "TXS: No descriptors available in cache, stopping ticking\n"); + txTick = false; + DPRINTF(EthernetSM, "TXS: No descriptors left, fetching\n"); + txDescCache.fetchDescriptors(); + return; + } + + int size; + size = txDescCache.getPacketSize(); + if (size > 0 && rxFifo.avail() > size) { + DPRINTF(EthernetSM, "TXS: Reserving %d bytes in FIFO and begining DMA of next packet\n"); + rxFifo.reserve(size); + txDescCache.getPacketData(txPacket); + } else { + DPRINTF(EthernetSM, "TXS: No packets to get, writing back used descriptors\n"); + txDescCache.writeback(0); + } + + return; + } +} + +bool +IGbE::ethRxPkt(EthPacketPtr pkt) +{ + DPRINTF(Ethernet, "RxFIFO: Receiving pcakte from wire\n"); + if (!regs.rctl.en()) { + DPRINTF(Ethernet, "RxFIFO: RX not enabled, dropping\n"); + return true; + } + + // restart the state machines if they are stopped + rxTick = true; + if ((rxTick || txTick) && !tickEvent.scheduled()) { + DPRINTF(EthernetSM, "RXS: received packet into fifo, starting ticking\n"); + tickEvent.schedule(curTick/cycles(1) + cycles(1)); + } + + if (!rxFifo.push(pkt)) { + DPRINTF(Ethernet, "RxFIFO: Packet won't fit in fifo... dropped\n"); + postInterrupt(IT_RXO, true); + return false; + } + return true; +} + + +void +IGbE::rxStateMachine() +{ + if (!regs.rctl.en()) { + rxTick = false; + DPRINTF(EthernetSM, "RXS: RX disabled, stopping ticking\n"); + return; + } + + // If the packet is done check for interrupts/descriptors/etc + if (rxDescCache.packetDone()) { + DPRINTF(EthernetSM, "RXS: Packet completed DMA to memory\n"); + int descLeft = rxDescCache.descLeft(); + switch (regs.rctl.rdmts()) { + case 2: if (descLeft > .125 * regs.rdlen()) break; + case 1: if (descLeft > .250 * regs.rdlen()) break; + case 0: if (descLeft > .500 * regs.rdlen()) break; + DPRINTF(Ethernet, "RXS: Interrupting (RXDMT) because of descriptors left\n"); + postInterrupt(IT_RXDMT); + break; + } + + if (descLeft == 0) { + DPRINTF(EthernetSM, "RXS: No descriptors left in ring, forcing writeback\n"); + rxDescCache.writeback(0); + DPRINTF(EthernetSM, "RXS: No descriptors left, stopping ticking\n"); + rxTick = false; + } + + // only support descriptor granulaties + assert(regs.rxdctl.gran()); + + if (regs.rxdctl.wthresh() >= rxDescCache.descUsed()) { + DPRINTF(EthernetSM, "RXS: Writing back because WTHRESH >= descUsed\n"); + rxDescCache.writeback(cacheBlockSize()-1); + } + + if ((rxDescCache.descUnused() < regs.rxdctl.pthresh()) && + ((rxDescCache.descLeft() - rxDescCache.descUnused()) > regs.rxdctl.hthresh())) { + DPRINTF(EthernetSM, "RXS: Fetching descriptors because descUnused < PTHRESH\n"); + rxDescCache.fetchDescriptors(); + } + + if (rxDescCache.descUnused() == 0) { + DPRINTF(EthernetSM, "RXS: No descriptors available in cache, stopping ticking\n"); + rxTick = false; + DPRINTF(EthernetSM, "RXS: Fetching descriptors because none available\n"); + rxDescCache.fetchDescriptors(); + } + return; + } + + if (!rxDescCache.descUnused()) { + DPRINTF(EthernetSM, "RXS: No descriptors available in cache, stopping ticking\n"); + rxTick = false; + DPRINTF(EthernetSM, "RXS: No descriptors available, fetching\n"); + rxDescCache.fetchDescriptors(); + return; + } + + if (rxFifo.empty()) { + DPRINTF(EthernetSM, "RXS: RxFIFO empty, stopping ticking\n"); + rxTick = false; + return; + } + + EthPacketPtr pkt; + pkt = rxFifo.front(); + + DPRINTF(EthernetSM, "RXS: Writing packet into memory\n"); + if (!rxDescCache.writePacket(pkt)) { + return; + } + + DPRINTF(EthernetSM, "RXS: Removing packet from FIFO\n"); + rxFifo.pop(); + DPRINTF(EthernetSM, "RXS: stopping ticking until packet DMA completes\n"); + rxTick = false; } +void +IGbE::txWire() +{ + if (txFifo.empty()) { + return; + } + + txTick = true; + + if (etherInt->sendPacket(txFifo.front())) { + DPRINTF(Ethernet, "TxFIFO: Successful transmit, bytes in fifo: %d\n", + txFifo.avail()); + txFifo.pop(); + } + + if (txFifo.empty()) { + postInterrupt(IT_TXQE); + DPRINTF(Ethernet, "TxFIFO: Empty, posting interruppt\n"); + } +} + +void +IGbE::tick() +{ + DPRINTF(EthernetSM, "IGbE: -------------- Cycle -------------- "); + + if (rxTick) + rxStateMachine(); + + if (txTick) { + txStateMachine(); + txWire(); + } + + if (rxTick || txTick) + tickEvent.schedule(curTick + cycles(1)); +} void IGbE::ethTxDone() { - panic("Need to implemenet\n"); + // restart the state machines if they are stopped + txTick = true; + if ((rxTick || txTick) && !tickEvent.scheduled()) + tickEvent.schedule(curTick/cycles(1) + cycles(1)); + DPRINTF(Ethernet, "TxFIFO: Transmission complete\n"); } void diff --git a/src/dev/i8254xGBe.hh b/src/dev/i8254xGBe.hh index ce4007263..d7d20ae50 100644 --- a/src/dev/i8254xGBe.hh +++ b/src/dev/i8254xGBe.hh @@ -35,6 +35,9 @@ #ifndef __DEV_I8254XGBE_HH__ #define __DEV_I8254XGBE_HH__ +#include <deque> +#include <string> + #include "base/inet.hh" #include "base/statistics.hh" #include "dev/etherint.hh" @@ -50,22 +53,434 @@ class IGbE : public PciDev { private: IGbEInt *etherInt; + + // device registers iGbReg::Regs regs; + + // eeprom data, status and control bits int eeOpBits, eeAddrBits, eeDataBits; uint8_t eeOpcode, eeAddr; - uint16_t flash[iGbReg::EEPROM_SIZE]; + // cached parameters from params struct + Tick tickRate; + bool useFlowControl; + + // packet fifos + PacketFifo rxFifo; + PacketFifo txFifo; + + // Packet that we are currently putting into the txFifo + EthPacketPtr txPacket; + + // Should to Rx/Tx State machine tick? + bool rxTick; + bool txTick; + + // Event and function to deal with RDTR timer expiring + void rdtrProcess() { postInterrupt(iGbReg::IT_RXDMT, true); } + //friend class EventWrapper<IGbE, &IGbE::rdtrProcess>; + EventWrapper<IGbE, &IGbE::rdtrProcess> rdtrEvent; + + // Event and function to deal with RADV timer expiring + void radvProcess() { postInterrupt(iGbReg::IT_RXDMT, true); } + //friend class EventWrapper<IGbE, &IGbE::radvProcess>; + EventWrapper<IGbE, &IGbE::radvProcess> radvEvent; + + // Event and function to deal with TADV timer expiring + void tadvProcess() { postInterrupt(iGbReg::IT_TXDW, true); } + //friend class EventWrapper<IGbE, &IGbE::tadvProcess>; + EventWrapper<IGbE, &IGbE::tadvProcess> tadvEvent; + + // Event and function to deal with TIDV timer expiring + void tidvProcess() { postInterrupt(iGbReg::IT_TXDW, true); }; + //friend class EventWrapper<IGbE, &IGbE::tidvProcess>; + EventWrapper<IGbE, &IGbE::tidvProcess> tidvEvent; + + // Main event to tick the device + void tick(); + //friend class EventWrapper<IGbE, &IGbE::tick>; + EventWrapper<IGbE, &IGbE::tick> tickEvent; + + + void rxStateMachine(); + void txStateMachine(); + void txWire(); + + /** Write an interrupt into the interrupt pending register and check mask + * and interrupt limit timer before sending interrupt to CPU + * @param t the type of interrupt we are posting + * @param now should we ignore the interrupt limiting timer + */ + void postInterrupt(iGbReg::IntTypes t, bool now = false); + + /** Check and see if changes to the mask register have caused an interrupt + * to need to be sent or perhaps removed an interrupt cause. + */ + void chkInterrupt(); + + /** Send an interrupt to the cpu + */ + void cpuPostInt(); + // Event to moderate interrupts + EventWrapper<IGbE, &IGbE::cpuPostInt> interEvent; + + /** Clear the interupt line to the cpu + */ + void cpuClearInt(); + + Tick intClock() { return Clock::Int::ns * 1024; } + + template<class T> + class DescCache + { + protected: + virtual Addr descBase() const = 0; + virtual long descHead() const = 0; + virtual long descTail() const = 0; + virtual long descLen() const = 0; + virtual void updateHead(long h) = 0; + virtual void enableSm() = 0; + + std::deque<T*> usedCache; + std::deque<T*> unusedCache; + + T *fetchBuf; + T *wbBuf; + + // Pointer to the device we cache for + IGbE *igbe; + + // Name of this descriptor cache + std::string _name; + + // How far we've cached + int cachePnt; + + // The size of the descriptor cache + int size; + + // How many descriptors we are currently fetching + int curFetching; + + // How many descriptors we are currently writing back + int wbOut; + + // if the we wrote back to the end of the descriptor ring and are going + // to have to wrap and write more + bool moreToWb; + + // What the alignment is of the next descriptor writeback + Addr wbAlignment; + + /** The packet that is currently being dmad to memory if any + */ + EthPacketPtr pktPtr; + + public: + DescCache(IGbE *i, const std::string n, int s) + : igbe(i), _name(n), cachePnt(0), size(s), curFetching(0), wbOut(0), + pktPtr(NULL), fetchEvent(this), wbEvent(this) + { + fetchBuf = new T[size]; + wbBuf = new T[size]; + } + + virtual ~DescCache() + { + reset(); + } + + std::string name() { return _name; } + + /** If the address/len/head change when we've got descriptors that are + * dirty that is very bad. This function checks that we don't and if we + * do panics. + */ + void areaChanged() + { + if (usedCache.size() > 0 || unusedCache.size() > 0) + panic("Descriptor Address, Length or Head changed. Bad\n"); + } + + void writeback(Addr aMask) + { + int curHead = descHead(); + int max_to_wb = usedCache.size() + curHead; + + DPRINTF(EthernetDesc, "Writing back descriptors head: %d tail: " + "%d len: %d cachePnt: %d max_to_wb: %d descleft: %d\n", + curHead, descTail(), descLen(), cachePnt, max_to_wb, + descLeft()); + + // Check if this writeback is less restrictive that the previous + // and if so setup another one immediately following it + if (wbOut && (aMask < wbAlignment)) { + moreToWb = true; + wbAlignment = aMask; + DPRINTF(EthernetDesc, "Writing back already in process, returning\n"); + return; + } + + + moreToWb = false; + wbAlignment = aMask; + + if (max_to_wb > descLen()) { + max_to_wb = descLen() - curHead; + moreToWb = true; + // this is by definition aligned correctly + } else if (aMask != 0) { + // align the wb point to the mask + max_to_wb = max_to_wb & ~(aMask>>4); + } + + DPRINTF(EthernetDesc, "Writing back %d descriptors\n", max_to_wb); + + if (max_to_wb <= 0 || wbOut) + return; + + wbOut = max_to_wb - curHead; + + for (int x = 0; x < wbOut; x++) + memcpy(&wbBuf[x], usedCache[x], sizeof(T)); + + for (int x = 0; x < wbOut; x++) { + assert(usedCache.size()); + delete usedCache[0]; + usedCache.pop_front(); + }; + + igbe->dmaWrite(descBase() + curHead * sizeof(T), wbOut * sizeof(T), + &wbEvent, (uint8_t*)wbBuf); + } + + /** Fetch a chunk of descriptors into the descriptor cache. + * Calls fetchComplete when the memory system returns the data + */ + void fetchDescriptors() + { + size_t max_to_fetch = cachePnt - descTail(); + if (max_to_fetch < 0) + max_to_fetch = descLen() - cachePnt; + + max_to_fetch = std::min(max_to_fetch, (size - usedCache.size() - + unusedCache.size())); + + DPRINTF(EthernetDesc, "Fetching descriptors head: %d tail: " + "%d len: %d cachePnt: %d max_to_wb: %d descleft: %d\n", + descHead(), descTail(), descLen(), cachePnt, + max_to_fetch, descLeft()); + + // Nothing to do + if (max_to_fetch == 0 || curFetching) + return; + + // So we don't have two descriptor fetches going on at once + curFetching = max_to_fetch; + + igbe->dmaRead(descBase() + cachePnt * sizeof(T), + curFetching * sizeof(T), &fetchEvent, (uint8_t*)fetchBuf); + } + + + /** Called by event when dma to read descriptors is completed + */ + void fetchComplete() + { + T *newDesc; + for (int x = 0; x < curFetching; x++) { + newDesc = new T; + memcpy(newDesc, &fetchBuf[x], sizeof(T)); + unusedCache.push_back(newDesc); + } + +#ifndef NDEBUG + int oldCp = cachePnt; +#endif + + cachePnt += curFetching; + if (cachePnt > descLen()) + cachePnt -= descLen(); + + DPRINTF(EthernetDesc, "Fetching complete cachePnt %d -> %d\n", + oldCp, cachePnt); + + enableSm(); + + } + + EventWrapper<DescCache, &DescCache::fetchComplete> fetchEvent; + + /** Called by event when dma to writeback descriptors is completed + */ + void wbComplete() + { + long curHead = descHead(); +#ifndef NDEBUG + long oldHead = curHead; +#endif + + curHead += wbOut; + wbOut = 0; + + if (curHead > descLen()) + curHead = 0; + + // Update the head + updateHead(curHead); + + DPRINTF(EthernetDesc, "Writeback complete cachePnt %d -> %d\n", + oldHead, curHead); + + // If we still have more to wb, call wb now + if (moreToWb) { + DPRINTF(EthernetDesc, "Writeback has more todo\n"); + writeback(wbAlignment); + } + } + + + EventWrapper<DescCache, &DescCache::wbComplete> wbEvent; + + /* Return the number of descriptors left in the ring, so the device has + * a way to figure out if it needs to interrupt. + */ + int descLeft() const + { + int left = unusedCache.size(); + if (cachePnt - descTail() >= 0) + left += (cachePnt - descTail()); + else + left += (descLen() - cachePnt); + + return left; + } + + /* Return the number of descriptors used and not written back. + */ + int descUsed() const { return usedCache.size(); } + + /* Return the number of cache unused descriptors we have. */ + int descUnused() const {return unusedCache.size(); } + + /* Get into a state where the descriptor address/head/etc colud be + * changed */ + void reset() + { + DPRINTF(EthernetDesc, "Reseting descriptor cache\n"); + for (int x = 0; x < usedCache.size(); x++) + delete usedCache[x]; + for (int x = 0; x < unusedCache.size(); x++) + delete unusedCache[x]; + + usedCache.clear(); + unusedCache.clear(); + } + + }; + + + class RxDescCache : public DescCache<iGbReg::RxDesc> + { + protected: + virtual Addr descBase() const { return igbe->regs.rdba(); } + virtual long descHead() const { return igbe->regs.rdh(); } + virtual long descLen() const { return igbe->regs.rdlen() >> 4; } + virtual long descTail() const { return igbe->regs.rdt(); } + virtual void updateHead(long h) { igbe->regs.rdh(h); } + virtual void enableSm(); + + bool pktDone; + + public: + RxDescCache(IGbE *i, std::string n, int s); + + /** Write the given packet into the buffer(s) pointed to by the + * descriptor and update the book keeping. Should only be called when + * there are no dma's pending. + * @param packet ethernet packet to write + * @return if the packet could be written (there was a free descriptor) + */ + bool writePacket(EthPacketPtr packet); + /** Called by event when dma to write packet is completed + */ + void pktComplete(); + + /** Check if the dma on the packet has completed. + */ + + bool packetDone(); + + EventWrapper<RxDescCache, &RxDescCache::pktComplete> pktEvent; + + }; + friend class RxDescCache; + + RxDescCache rxDescCache; + + class TxDescCache : public DescCache<iGbReg::TxDesc> + { + protected: + virtual Addr descBase() const { return igbe->regs.tdba(); } + virtual long descHead() const { return igbe->regs.tdh(); } + virtual long descTail() const { return igbe->regs.tdt(); } + virtual long descLen() const { return igbe->regs.tdlen() >> 4; } + virtual void updateHead(long h) { igbe->regs.tdh(h); } + virtual void enableSm(); + + bool pktDone; + bool isTcp; + bool pktWaiting; + + public: + TxDescCache(IGbE *i, std::string n, int s); + + /** Tell the cache to DMA a packet from main memory into its buffer and + * return the size the of the packet to reserve space in tx fifo. + * @return size of the packet + */ + int getPacketSize(); + void getPacketData(EthPacketPtr p); + + /** Ask if the packet has been transfered so the state machine can give + * it to the fifo. + * @return packet available in descriptor cache + */ + bool packetAvailable(); + + /** Ask if we are still waiting for the packet to be transfered. + * @return packet still in transit. + */ + bool packetWaiting() { return pktWaiting; } + + /** Called by event when dma to write packet is completed + */ + void pktComplete(); + EventWrapper<TxDescCache, &TxDescCache::pktComplete> pktEvent; + + }; + friend class TxDescCache; + + TxDescCache txDescCache; public: struct Params : public PciDev::Params { - ; + bool use_flow_control; + int rx_fifo_size; + int tx_fifo_size; + int rx_desc_cache_size; + int tx_desc_cache_size; + Tick clock; }; IGbE(Params *params); ~IGbE() {;} + Tick clock; + inline Tick cycles(int numCycles) const { return numCycles * clock; } + virtual Tick read(PacketPtr pkt); virtual Tick write(PacketPtr pkt); @@ -76,6 +491,7 @@ class IGbE : public PciDev void setEthInt(IGbEInt *i) { assert(!etherInt); etherInt = i; } + const Params *params() const {return (const Params *)_params; } virtual void serialize(std::ostream &os); diff --git a/src/dev/i8254xGBe_defs.hh b/src/dev/i8254xGBe_defs.hh index ae0925356..d9648a7c2 100644 --- a/src/dev/i8254xGBe_defs.hh +++ b/src/dev/i8254xGBe_defs.hh @@ -31,433 +31,570 @@ /* @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;//* + +// Registers used by the Intel GbE NIC +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_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_TXDCTL = 0x03828; +const uint32_t REG_TADV = 0x0382C; +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; + + +// Registers in that are accessed in the PHY +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; + +// 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; +// Receive Descriptor Error Flags +const uint8_t RXDE_RXE = 0x80; +const uint8_t RXDE_IPE = 0x40; +const uint8_t RXDE_TCPE = 0x20; +const uint8_t RXDE_SEQ = 0x04; +const uint8_t RXDE_SE = 0x02; +const uint8_t RXDE_CE = 0x01; + +// Interrupt types +enum IntTypes +{ + IT_NONE = 0x00000, //dummy value + IT_TXDW = 0x00001, + IT_TXQE = 0x00002, + IT_LSC = 0x00004, + IT_RXSEQ = 0x00008, + IT_RXDMT = 0x00010, + IT_RXO = 0x00040, + IT_RXT = 0x00080, + IT_MADC = 0x00200, + IT_RXCFG = 0x00400, + IT_GPI0 = 0x02000, + IT_GPI1 = 0x04000, + IT_TXDLOW = 0x08000, + IT_SRPD = 0x10000, + IT_ACK = 0x20000 +}; + +// Receive Descriptor struct struct RxDesc { Addr buf; uint16_t len; uint16_t csum; - union { - uint8_t status; - struct { // these may be in the worng order - uint8_t dd:1; // descriptor done (hw is done when 1) - uint8_t eop:1; // end of packet - uint8_t xism:1; // ignore checksum - uint8_t vp:1; // packet is vlan packet - uint8_t rsv:1; // reserved - uint8_t tcpcs:1; // TCP checksum done - uint8_t ipcs:1; // IP checksum done - uint8_t pif:1; // passed in-exact filter - } st; - }; - union { - uint8_t errors; - struct { - uint8_t ce:1; // crc error or alignment error - uint8_t se:1; // symbol error - uint8_t seq:1; // sequence error - uint8_t rsv:1; // reserved - uint8_t cxe:1; // carrier extension error - uint8_t tcpe:1; // tcp checksum error - uint8_t ipe:1; // ip checksum error - uint8_t rxe:1; // PX data error - } er; - }; - union { - uint16_t special; - struct { - uint16_t vlan:12; //vlan id - uint16_t cfi:1; // canocial form id - uint16_t pri:3; // user priority - } sp; - }; + uint8_t status; + uint8_t errors; + uint16_t vlan; }; -union TxDesc { - uint8_t data[16]; - struct { - Addr buf; - uint16_t len; - uint8_t cso; - union { - uint8_t command; - struct { - uint8_t eop:1; // end of packet - uint8_t ifcs:1; // insert crc - uint8_t ic:1; // insert checksum - uint8_t rs:1; // report status - uint8_t rps:1; // report packet sent - uint8_t dext:1; // extension - uint8_t vle:1; // vlan enable - uint8_t ide:1; // interrupt delay enable - } cmd; - }; - union { - uint8_t status:4; - struct { - uint8_t dd:1; // descriptor done - uint8_t ec:1; // excess collisions - uint8_t lc:1; // late collision - uint8_t tu:1; // transmit underrun - } st; - }; - uint8_t reserved:4; - uint8_t css; - union { - uint16_t special; - struct { - uint16_t vlan:12; //vlan id - uint16_t cfi:1; // canocial form id - uint16_t pri:3; // user priority - } sp; - }; - } legacy; - - // Type 0000 descriptor - struct { - uint8_t ipcss; - uint8_t ipcso; - uint16_t ipcse; - uint8_t tucss; - uint8_t tucso; - uint16_t tucse; - uint32_t paylen:20; - uint8_t dtype:4; - union { - uint8_t tucommand; - struct { - uint8_t tcp:1; // tcp/udp - uint8_t ip:1; // ip ipv4/ipv6 - uint8_t tse:1; // tcp segment enbale - uint8_t rs:1; // report status - uint8_t rsv0:1; // reserved - uint8_t dext:1; // descriptor extension - uint8_t rsv1:1; // reserved - uint8_t ide:1; // interrupt delay enable - } tucmd; - }; - union { - uint8_t status:4; - struct { - uint8_t dd:1; - uint8_t rsvd:3; - } sta; - }; - uint8_t reserved:4; - uint8_t hdrlen; - uint16_t mss; - } t0; - - // Type 0001 descriptor - struct { - Addr buf; - uint32_t dtalen:20; - uint8_t dtype:4; - union { - uint8_t dcommand; - struct { - uint8_t eop:1; // end of packet - uint8_t ifcs:1; // insert crc - uint8_t tse:1; // segmentation enable - uint8_t rs:1; // report status - uint8_t rps:1; // report packet sent - uint8_t dext:1; // extension - uint8_t vle:1; // vlan enable - uint8_t ide:1; // interrupt delay enable - } dcmd; - }; - union { - uint8_t status:4; - struct { - uint8_t dd:1; // descriptor done - uint8_t ec:1; // excess collisions - uint8_t lc:1; // late collision - uint8_t tu:1; // transmit underrun - } sta; - }; - union { - uint8_t pktopts; - struct { - uint8_t ixsm:1; // insert ip checksum - uint8_t txsm:1; // insert tcp checksum - }; - }; - union { - uint16_t special; - struct { - uint16_t vlan:12; //vlan id - uint16_t cfi:1; // canocial form id - uint16_t pri:3; // user priority - } sp; - }; - } t1; - - // Junk to test descriptor type! - struct { - uint64_t junk; - uint32_t junk1:20; - uint8_t dtype; - uint8_t junk2:5; - uint8_t dext:1; - uint8_t junk3:2; - uint8_t junk4:4; - uint32_t junk5; - } type; +struct TxDesc { + uint64_t d1; + uint64_t d2; }; +namespace TxdOp { +const uint8_t TXD_CNXT = 0x0; +const uint8_t TXD_DATA = 0x0; + +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; } + +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->d1, 35, 32, 1); +} + +bool ide(TxDesc *d) { return bits(d->d2, 31,31); } +bool vle(TxDesc *d) { assert(isLegacy(d) || isData(d)); return bits(d->d2, 30,30); } +bool rs(TxDesc *d) { return bits(d->d2, 28,28); } +bool ic(TxDesc *d) { assert(isLegacy(d) || isData(d)); return isLegacy(d) && bits(d->d2, 27,27); } +bool tse(TxDesc *d) { return (isData(d) || isContext(d)) && bits(d->d2, 27,27); } +bool ifcs(TxDesc *d) { assert(isLegacy(d) || isData(d)); return bits(d->d2, 26,26); } +bool eop(TxDesc *d) { assert(isLegacy(d) || isData(d)); return bits(d->d2, 25,25); } +bool ip(TxDesc *d) { assert(isContext(d)); return bits(d->d2, 26,26); } +bool tcp(TxDesc *d) { assert(isContext(d)); return bits(d->d2, 25,25); } + +uint8_t getCso(TxDesc *d) { assert(isLegacy(d)); return bits(d->d2, 23,16); } +uint8_t getCss(TxDesc *d) { assert(isLegacy(d)); return bits(d->d2, 47,40); } + +bool ixsm(TxDesc *d) { return isData(d) && bits(d->d2, 40,40); } +bool txsm(TxDesc *d) { return isData(d) && bits(d->d2, 41,41); } + +int tucse(TxDesc *d) { assert(isContext(d)); return bits(d->d1,63,48); } +int tucso(TxDesc *d) { assert(isContext(d)); return bits(d->d1,47,40); } +int tucss(TxDesc *d) { assert(isContext(d)); return bits(d->d1,39,32); } +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); } +} // namespace TxdOp + + +#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; - - 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; - - 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; - - 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; - - 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; - - 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; - - 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; - - 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; - - 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; + template<class T> + struct Reg { + T _data; + T operator()() { return _data; } + const Reg<T> &operator=(T d) { _data = d; return *this;} + bool operator==(T d) { return d == _data; } + void operator()(T d) { _data = d; } + Reg() { _data = 0; } + }; + + struct CTRL : public Reg<uint32_t> { // 0x0000 CTRL Register + using Reg<uint32_t>::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; + + struct STATUS : public Reg<uint32_t> { // 0x0008 STATUS Register + using Reg<uint32_t>::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; + + struct EECD : public Reg<uint32_t> { // 0x0010 EECD Register + using Reg<uint32_t>::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; + + 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(data,16,16); // data + }; + EERD eerd; + + struct CTRL_EXT : public Reg<uint32_t> { // 0x0018 CTRL_EXT Register + using Reg<uint32_t>::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; + + struct MDIC : public Reg<uint32_t> { // 0x0020 MDIC Register + using Reg<uint32_t>::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; + + struct ICR : public Reg<uint32_t> { // 0x00C0 ICR Register + using Reg<uint32_t>::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; + + uint32_t imr; // register that contains the current interrupt mask + + struct ITR : public Reg<uint32_t> { // 0x00C4 ITR Register + using Reg<uint32_t>::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<uint32_t> { // 0x0100 RCTL Register + using Reg<uint32_t>::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(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(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 + int descSize() + { + switch(bsize()) { + case 0: return bsex() ? 2048 : -1; + case 1: return bsex() ? 1024 : 16384; + case 2: return bsex() ? 512 : 8192; + case 3: return bsex() ? 256 : 4096; + default: + return -1; + } + } + }; + RCTL rctl; + + struct FCTTV : public Reg<uint32_t> { // 0x0170 FCTTV + using Reg<uint32_t>::operator=; + ADD_FIELD32(ttv,0,16); // Transmit Timer Value + }; + FCTTV fcttv; + + struct TCTL : public Reg<uint32_t> { // 0x0400 TCTL Register + using Reg<uint32_t>::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<uint32_t> { // 0x1000 PBA Register + using Reg<uint32_t>::operator=; + ADD_FIELD32(rxa,0,16); + ADD_FIELD32(txa,16,16); + }; + PBA pba; + + struct FCRTL : public Reg<uint32_t> { // 0x2160 FCRTL Register + using Reg<uint32_t>::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<uint32_t> { // 0x2168 FCRTL Register + using Reg<uint32_t>::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<uint64_t> { // 0x2800 RDBA Register + using Reg<uint64_t>::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<uint32_t> { // 0x2808 RDLEN Register + using Reg<uint32_t>::operator=; + ADD_FIELD32(len,7,13); // number of bytes in the descriptor buffer + }; + RDLEN rdlen; + + struct RDH : public Reg<uint32_t> { // 0x2810 RDH Register + using Reg<uint32_t>::operator=; + ADD_FIELD32(rdh,0,16); // head of the descriptor ring + }; + RDH rdh; + + struct RDT : public Reg<uint32_t> { // 0x2818 RDT Register + using Reg<uint32_t>::operator=; + ADD_FIELD32(rdt,0,16); // tail of the descriptor ring + }; + RDT rdt; + + struct RDTR : public Reg<uint32_t> { // 0x2820 RDTR Register + using Reg<uint32_t>::operator=; + ADD_FIELD32(delay,0,16); // receive delay timer + ADD_FIELD32(fpd, 31,1); // flush partial descriptor block ?? + }; + RDTR rdtr; + + struct RXDCTL : public Reg<uint32_t> { // 0x2828 RXDCTL Register + using Reg<uint32_t>::operator=; + ADD_FIELD32(pthresh,0,6); // prefetch threshold, less that this + // consider prefetch + ADD_FIELD32(hthresh,8,6); // number of descriptors in host mem to + // consider prefetch + ADD_FIELD32(wthresh,16,6); // writeback threshold + ADD_FIELD32(gran,24,1); // granularity 0 = desc, 1 = cacheline + }; + RXDCTL rxdctl; + + struct RADV : public Reg<uint32_t> { // 0x282C RADV Register + using Reg<uint32_t>::operator=; + ADD_FIELD32(idv,0,16); // absolute interrupt delay + }; + RADV radv; + + struct RSRPD : public Reg<uint32_t> { // 0x2C00 RSRPD Register + using Reg<uint32_t>::operator=; + ADD_FIELD32(idv,0,12); // size to interrutp on small packets + }; + RSRPD rsrpd; + + struct TDBA : public Reg<uint64_t> { // 0x3800 TDBAL Register + using Reg<uint64_t>::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<uint32_t> { // 0x3808 TDLEN Register + using Reg<uint32_t>::operator=; + ADD_FIELD32(len,7,13); // number of bytes in the descriptor buffer + }; + TDLEN tdlen; + + struct TDH : public Reg<uint32_t> { // 0x3810 TDH Register + using Reg<uint32_t>::operator=; + ADD_FIELD32(tdh,0,16); // head of the descriptor ring + }; + TDH tdh; + + struct TDT : public Reg<uint32_t> { // 0x3818 TDT Register + using Reg<uint32_t>::operator=; + ADD_FIELD32(tdt,0,16); // tail of the descriptor ring + }; + TDT tdt; + + struct TIDV : public Reg<uint32_t> { // 0x3820 TIDV Register + using Reg<uint32_t>::operator=; + ADD_FIELD32(idv,0,16); // interrupt delay + }; + TIDV tidv; + + struct TXDCTL : public Reg<uint32_t> { // 0x3828 TXDCTL Register + using Reg<uint32_t>::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<uint32_t> { // 0x382C TADV Register + using Reg<uint32_t>::operator=; + ADD_FIELD32(idv,0,16); // absolute interrupt delay + }; + TADV tadv; + + 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); + }; + RXCSUM rxcsum; + + struct MANC : public Reg<uint32_t> { // 0x5820 MANC Register + using Reg<uint32_t>::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 diff --git a/src/dev/ide_disk.cc b/src/dev/ide_disk.cc index 5083c9c8d..9fa0cedde 100644 --- a/src/dev/ide_disk.cc +++ b/src/dev/ide_disk.cc @@ -48,7 +48,7 @@ #include "dev/alpha/tsunami_pchip.hh" #include "sim/builder.hh" #include "sim/sim_object.hh" -#include "sim/root.hh" +#include "sim/core.hh" #include "arch/isa_traits.hh" using namespace std; diff --git a/src/dev/io_device.hh b/src/dev/io_device.hh index c56eba267..cd7a5296a 100644 --- a/src/dev/io_device.hh +++ b/src/dev/io_device.hh @@ -132,6 +132,7 @@ class DmaPort : public Port bool dmaPending() { return pendingCount > 0; } + int cacheBlockSize() { return peerBlockSize(); } unsigned int drain(Event *de); }; @@ -256,15 +257,22 @@ class DmaDevice : public PioDevice virtual ~DmaDevice(); void dmaWrite(Addr addr, int size, Event *event, uint8_t *data) - { dmaPort->dmaAction(Packet::WriteInvalidateReq, addr, size, event, data) ; } + { + dmaPort->dmaAction(MemCmd::WriteInvalidateReq, + addr, size, event, data); + } - void dmaRead(Addr addr, int size, Event *event, uint8_t *data = NULL) - { dmaPort->dmaAction(Packet::ReadReq, addr, size, event, data); } + void dmaRead(Addr addr, int size, Event *event, uint8_t *data) + { + dmaPort->dmaAction(MemCmd::ReadReq, addr, size, event, data); + } bool dmaPending() { return dmaPort->dmaPending(); } virtual unsigned int drain(Event *de); + int cacheBlockSize() { return dmaPort->cacheBlockSize(); } + virtual Port *getPort(const std::string &if_name, int idx = -1) { if (if_name == "pio") { diff --git a/src/dev/ns_gige.cc b/src/dev/ns_gige.cc index 74f9d88d1..86f56b62e 100644 --- a/src/dev/ns_gige.cc +++ b/src/dev/ns_gige.cc @@ -92,28 +92,30 @@ NSGigE::NSGigE(Params *p) : PciDev(p), ioEnable(false), txFifo(p->tx_fifo_size), rxFifo(p->rx_fifo_size), txPacket(0), rxPacket(0), txPacketBufPtr(NULL), rxPacketBufPtr(NULL), - txXferLen(0), rxXferLen(0), clock(p->clock), - txState(txIdle), txEnable(false), CTDD(false), + txXferLen(0), rxXferLen(0), rxDmaFree(false), txDmaFree(false), + clock(p->clock), + txState(txIdle), txEnable(false), CTDD(false), txHalt(false), txFragPtr(0), txDescCnt(0), txDmaState(dmaIdle), rxState(rxIdle), - rxEnable(false), CRDD(false), rxPktBytes(0), + rxEnable(false), CRDD(false), rxPktBytes(0), rxHalt(false), rxFragPtr(0), rxDescCnt(0), rxDmaState(dmaIdle), extstsEnable(false), - eepromState(eepromStart), rxDmaReadEvent(this), rxDmaWriteEvent(this), + eepromState(eepromStart), eepromClk(false), eepromBitsToRx(0), + eepromOpcode(0), eepromAddress(0), eepromData(0), + dmaReadDelay(p->dma_read_delay), dmaWriteDelay(p->dma_write_delay), + dmaReadFactor(p->dma_read_factor), dmaWriteFactor(p->dma_write_factor), + rxDmaData(NULL), rxDmaAddr(0), rxDmaLen(0), + txDmaData(NULL), txDmaAddr(0), txDmaLen(0), + rxDmaReadEvent(this), rxDmaWriteEvent(this), txDmaReadEvent(this), txDmaWriteEvent(this), dmaDescFree(p->dma_desc_free), dmaDataFree(p->dma_data_free), txDelay(p->tx_delay), rxDelay(p->rx_delay), rxKickTick(0), rxKickEvent(this), txKickTick(0), txKickEvent(this), - txEvent(this), rxFilterEnable(p->rx_filter), acceptBroadcast(false), - acceptMulticast(false), acceptUnicast(false), + txEvent(this), rxFilterEnable(p->rx_filter), + acceptBroadcast(false), acceptMulticast(false), acceptUnicast(false), acceptPerfect(false), acceptArp(false), multicastHashEnable(false), - intrTick(0), cpuPendingIntr(false), + intrDelay(p->intr_delay), intrTick(0), cpuPendingIntr(false), intrEvent(0), interface(0) { - intrDelay = p->intr_delay; - dmaReadDelay = p->dma_read_delay; - dmaWriteDelay = p->dma_write_delay; - dmaReadFactor = p->dma_read_factor; - dmaWriteFactor = p->dma_write_factor; regsReset(); memcpy(&rom.perfectMatch, p->eaddr.bytes(), ETH_ADDR_LEN); diff --git a/src/dev/pcidev.cc b/src/dev/pcidev.cc index 1c2465dd1..f906e69cf 100644 --- a/src/dev/pcidev.cc +++ b/src/dev/pcidev.cc @@ -51,7 +51,7 @@ #include "sim/builder.hh" #include "sim/byteswap.hh" #include "sim/param.hh" -#include "sim/root.hh" +#include "sim/core.hh" using namespace std; diff --git a/src/dev/platform.hh b/src/dev/platform.hh index 1940dcad6..aceec0970 100644 --- a/src/dev/platform.hh +++ b/src/dev/platform.hh @@ -55,9 +55,6 @@ class Platform : public SimObject /** Pointer to the interrupt controller */ IntrControl *intrctrl; - /** Pointer to the UART, set by the uart */ - Uart *uart; - /** Pointer to the system for info about the memory system. */ System *system; diff --git a/src/dev/simconsole.cc b/src/dev/simconsole.cc index 77aafd9fa..c6ff9c1c6 100644 --- a/src/dev/simconsole.cc +++ b/src/dev/simconsole.cc @@ -56,17 +56,31 @@ using namespace std; -//////////////////////////////////////////////////////////////////////// -// -// -SimConsole::Event::Event(SimConsole *c, int fd, int e) +/* + * Poll event for the listen socket + */ +SimConsole::ListenEvent::ListenEvent(SimConsole *c, int fd, int e) : PollEvent(fd, e), cons(c) { } void -SimConsole::Event::process(int revent) +SimConsole::ListenEvent::process(int revent) +{ + cons->accept(); +} + +/* + * Poll event for the data socket + */ +SimConsole::DataEvent::DataEvent(SimConsole *c, int fd, int e) + : PollEvent(fd, e), cons(c) +{ +} + +void +SimConsole::DataEvent::process(int revent) { if (revent & POLLIN) cons->data(); @@ -74,41 +88,76 @@ SimConsole::Event::process(int revent) cons->detach(); } -SimConsole::SimConsole(const string &name, ostream *os, int num) - : SimObject(name), event(NULL), number(num), in_fd(-1), out_fd(-1), - listener(NULL), txbuf(16384), rxbuf(16384), outfile(os) +/* + * SimConsole code + */ +SimConsole::SimConsole(const string &name, ostream *os, int num, int port) + : SimObject(name), listenEvent(NULL), dataEvent(NULL), number(num), + data_fd(-1), txbuf(16384), rxbuf(16384), outfile(os) #if TRACING_ON == 1 , linebuf(16384) #endif { if (outfile) outfile->setf(ios::unitbuf); + + if (port) + listen(port); } SimConsole::~SimConsole() { - close(); + if (data_fd != -1) + ::close(data_fd); + + if (listenEvent) + delete listenEvent; + + if (dataEvent) + delete dataEvent; } +/////////////////////////////////////////////////////////////////////// +// socket creation and console attach +// + void -SimConsole::close() +SimConsole::listen(int port) { - if (in_fd != -1) - ::close(in_fd); + while (!listener.listen(port, true)) { + DPRINTF(Console, + ": can't bind address console port %d inuse PID %d\n", + port, getpid()); + port++; + } - if (out_fd != in_fd && out_fd != -1) - ::close(out_fd); + int p1, p2; + p2 = name().rfind('.') - 1; + p1 = name().rfind('.', p2); + ccprintf(cerr, "Listening for %s connection on port %d\n", + name().substr(p1+1,p2-p1), port); + + listenEvent = new ListenEvent(this, listener.getfd(), POLLIN); + pollQueue.schedule(listenEvent); } void -SimConsole::attach(int in, int out, ConsoleListener *l) +SimConsole::accept() { - in_fd = in; - out_fd = out; - listener = l; + if (!listener.islistening()) + panic("%s: cannot accept a connection if not listening!", name()); - event = new Event(this, in, POLLIN); - pollQueue.schedule(event); + int fd = listener.accept(true); + if (data_fd != -1) { + char message[] = "console already attached!\n"; + ::write(fd, message, sizeof(message)); + ::close(fd); + return; + } + + data_fd = fd; + dataEvent = new DataEvent(this, data_fd, POLLIN); + pollQueue.schedule(dataEvent); stringstream stream; ccprintf(stream, "==== m5 slave console: Console %d ====", number); @@ -119,26 +168,23 @@ SimConsole::attach(int in, int out, ConsoleListener *l) write((const uint8_t *)stream.str().c_str(), stream.str().size()); - DPRINTFN("attach console %d\n", number); - txbuf.readall(out); + txbuf.readall(data_fd); } void SimConsole::detach() { - close(); - in_fd = -1; - out_fd = -1; - - pollQueue.remove(event); - - if (listener) { - listener->add(this); - listener = NULL; + if (data_fd != -1) { + ::close(data_fd); + data_fd = -1; } + pollQueue.remove(dataEvent); + delete dataEvent; + dataEvent = NULL; + DPRINTFN("detach console %d\n", number); } @@ -159,12 +205,12 @@ SimConsole::data() size_t SimConsole::read(uint8_t *buf, size_t len) { - if (in_fd < 0) + if (data_fd < 0) panic("Console not properly attached.\n"); size_t ret; do { - ret = ::read(in_fd, buf, len); + ret = ::read(data_fd, buf, len); } while (ret == -1 && errno == EINTR); @@ -183,12 +229,12 @@ SimConsole::read(uint8_t *buf, size_t len) size_t SimConsole::write(const uint8_t *buf, size_t len) { - if (out_fd < 0) + if (data_fd < 0) panic("Console not properly attached.\n"); size_t ret; for (;;) { - ret = ::write(out_fd, buf, len); + ret = ::write(data_fd, buf, len); if (ret >= 0) break; @@ -268,7 +314,7 @@ SimConsole::out(char c) txbuf.write(c); - if (out_fd >= 0) + if (data_fd >= 0) write(c); if (outfile) @@ -279,23 +325,11 @@ SimConsole::out(char c) } - -void -SimConsole::serialize(ostream &os) -{ -} - -void -SimConsole::unserialize(Checkpoint *cp, const std::string §ion) -{ -} - - BEGIN_DECLARE_SIM_OBJECT_PARAMS(SimConsole) - SimObjectParam<ConsoleListener *> listener; SimObjectParam<IntrControl *> intr_control; Param<string> output; + Param<int> port; Param<bool> append_name; Param<int> number; @@ -303,9 +337,9 @@ END_DECLARE_SIM_OBJECT_PARAMS(SimConsole) BEGIN_INIT_SIM_OBJECT_PARAMS(SimConsole) - INIT_PARAM(listener, "console listener"), INIT_PARAM(intr_control, "interrupt controller"), INIT_PARAM(output, "file to dump output to"), + INIT_PARAM(port, ""), INIT_PARAM_DFLT(append_name, "append name() to filename", true), INIT_PARAM_DFLT(number, "console number", 0) @@ -322,95 +356,7 @@ CREATE_SIM_OBJECT(SimConsole) stream = simout.find(filename); } - SimConsole *console = new SimConsole(getInstanceName(), stream, number); - ((ConsoleListener *)listener)->add(console); - - return console; + return new SimConsole(getInstanceName(), stream, number, port); } REGISTER_SIM_OBJECT("SimConsole", SimConsole) - -//////////////////////////////////////////////////////////////////////// -// -// - -ConsoleListener::ConsoleListener(const string &name) - : SimObject(name), event(NULL) -{} - -ConsoleListener::~ConsoleListener() -{ - if (event) - delete event; -} - -void -ConsoleListener::Event::process(int revent) -{ - listener->accept(); -} - -/////////////////////////////////////////////////////////////////////// -// socket creation and console attach -// - -void -ConsoleListener::listen(int port) -{ - while (!listener.listen(port, true)) { - DPRINTF(Console, - ": can't bind address console port %d inuse PID %d\n", - port, getpid()); - port++; - } - - ccprintf(cerr, "Listening for console connection on port %d\n", port); - - event = new Event(this, listener.getfd(), POLLIN); - pollQueue.schedule(event); -} - -void -ConsoleListener::add(SimConsole *cons) -{ ConsoleList.push_back(cons);} - -void -ConsoleListener::accept() -{ - if (!listener.islistening()) - panic("%s: cannot accept a connection if not listening!", name()); - - int sfd = listener.accept(true); - if (sfd != -1) { - iter_t i = ConsoleList.begin(); - iter_t end = ConsoleList.end(); - if (i == end) { - close(sfd); - } else { - (*i)->attach(sfd, this); - i = ConsoleList.erase(i); - } - } -} - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(ConsoleListener) - - Param<int> port; - -END_DECLARE_SIM_OBJECT_PARAMS(ConsoleListener) - -BEGIN_INIT_SIM_OBJECT_PARAMS(ConsoleListener) - - INIT_PARAM_DFLT(port, "listen port", 3456) - -END_INIT_SIM_OBJECT_PARAMS(ConsoleListener) - -CREATE_SIM_OBJECT(ConsoleListener) -{ - ConsoleListener *listener = new ConsoleListener(getInstanceName()); - listener->listen(port); - - return listener; -} - -REGISTER_SIM_OBJECT("ConsoleListener", ConsoleListener) diff --git a/src/dev/simconsole.hh b/src/dev/simconsole.hh index ec99c6028..18a193493 100644 --- a/src/dev/simconsole.hh +++ b/src/dev/simconsole.hh @@ -53,30 +53,47 @@ class SimConsole : public SimObject Uart *uart; protected: - class Event : public PollEvent + class ListenEvent : public PollEvent { protected: SimConsole *cons; public: - Event(SimConsole *c, int fd, int e); + ListenEvent(SimConsole *c, int fd, int e); void process(int revent); }; - friend class Event; - Event *event; + friend class ListenEvent; + ListenEvent *listenEvent; + + class DataEvent : public PollEvent + { + protected: + SimConsole *cons; + + public: + DataEvent(SimConsole *c, int fd, int e); + void process(int revent); + }; + + friend class DataEvent; + DataEvent *dataEvent; protected: int number; - int in_fd; - int out_fd; - ConsoleListener *listener; + int data_fd; public: - SimConsole(const std::string &name, std::ostream *os, int num); + SimConsole(const std::string &name, std::ostream *os, int num, int port); ~SimConsole(); protected: + ListenSocket listener; + + void listen(int port); + void accept(); + + protected: CircleBuf txbuf; CircleBuf rxbuf; std::ostream *outfile; @@ -88,17 +105,13 @@ class SimConsole : public SimObject /////////////////////// // Terminal Interface - void attach(int fd, ConsoleListener *l = NULL) { attach(fd, fd, l); } - void attach(int in, int out, ConsoleListener *l = NULL); - void detach(); - void data(); - void close(); void read(uint8_t &c) { read(&c, 1); } size_t read(uint8_t *buf, size_t len); void write(uint8_t c) { write(&c, 1); } size_t write(const uint8_t *buf, size_t len); + void detach(); public: ///////////////// @@ -126,43 +139,6 @@ class SimConsole : public SimObject //Ask the console if data is available bool dataAvailable() { return !rxbuf.empty(); } - - virtual void serialize(std::ostream &os); - virtual void unserialize(Checkpoint *cp, const std::string §ion); -}; - -class ConsoleListener : public SimObject -{ - protected: - class Event : public PollEvent - { - protected: - ConsoleListener *listener; - - public: - Event(ConsoleListener *l, int fd, int e) - : PollEvent(fd, e), listener(l) {} - void process(int revent); - }; - - friend class Event; - Event *event; - - typedef std::list<SimConsole *> list_t; - typedef list_t::iterator iter_t; - list_t ConsoleList; - - protected: - ListenSocket listener; - - public: - ConsoleListener(const std::string &name); - ~ConsoleListener(); - - void add(SimConsole *cons); - - void accept(); - void listen(int port); }; #endif // __CONSOLE_HH__ diff --git a/src/dev/sparc/SConscript b/src/dev/sparc/SConscript index 44b082b68..8511b16fb 100644 --- a/src/dev/sparc/SConscript +++ b/src/dev/sparc/SConscript @@ -29,21 +29,10 @@ # Authors: Steve Reinhardt # Gabe Black -import os.path, sys +Import('*') -# Import build environment variable from SConstruct. -Import('env') - -sources = [] - -sources += Split(''' - dtod.cc - t1000.cc - mm_disk.cc - ''') - -# Convert file names to SCons File objects. This takes care of the -# path relative to the top of the directory tree. -sources = [File(s) for s in sources] - -Return('sources') +if env['FULL_SYSTEM'] and env['TARGET_ISA'] == 'sparc': + Source('dtod.cc') + Source('iob.cc') + Source('t1000.cc') + Source('mm_disk.cc') diff --git a/src/dev/sparc/iob.cc b/src/dev/sparc/iob.cc new file mode 100644 index 000000000..e686e51f7 --- /dev/null +++ b/src/dev/sparc/iob.cc @@ -0,0 +1,402 @@ +/* + * Copyright (c) 2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Ali Saidi + */ + +/** @file + * This device implemetns the niagara I/O bridge chip. It manages incomming + * interrupts and posts them to the CPU when needed. It holds mask registers and + * various status registers for CPUs to check what interrupts are pending as + * well as facilities to send IPIs to other cpus. + */ + +#include <cstring> + +#include "arch/sparc/isa_traits.hh" +#include "arch/sparc/faults.hh" +#include "base/trace.hh" +#include "cpu/intr_control.hh" +#include "dev/sparc/iob.hh" +#include "dev/platform.hh" +#include "mem/port.hh" +#include "mem/packet_access.hh" +#include "sim/builder.hh" +#include "sim/faults.hh" +#include "sim/system.hh" + +Iob::Iob(Params *p) + : PioDevice(p), ic(p->platform->intrctrl) +{ + iobManAddr = ULL(0x9800000000); + iobManSize = ULL(0x0100000000); + iobJBusAddr = ULL(0x9F00000000); + iobJBusSize = ULL(0x0100000000); + assert (params()->system->threadContexts.size() <= MaxNiagaraProcs); + // Get the interrupt controller from the platform + ic = platform->intrctrl; + + for (int x = 0; x < NumDeviceIds; ++x) { + intMan[x].cpu = 0; + intMan[x].vector = 0; + intCtl[x].mask = true; + intCtl[x].pend = false; + } + +} + +Tick +Iob::read(PacketPtr pkt) +{ + assert(pkt->result == Packet::Unknown); + + if (pkt->getAddr() >= iobManAddr && pkt->getAddr() < iobManAddr + iobManSize) + readIob(pkt); + else if (pkt->getAddr() >= iobJBusAddr && pkt->getAddr() < iobJBusAddr+iobJBusSize) + readJBus(pkt); + else + panic("Invalid address reached Iob\n"); + + pkt->result = Packet::Success; + return pioDelay; +} + +void +Iob::readIob(PacketPtr pkt) +{ + Addr accessAddr = pkt->getAddr() - iobManAddr; + int index; + uint64_t data; + + if (accessAddr >= IntManAddr && accessAddr < IntManAddr + IntManSize) { + index = (accessAddr - IntManAddr) >> 3; + data = intMan[index].cpu << 8 | intMan[index].vector << 0; + pkt->set(data); + return; + } + + if (accessAddr >= IntCtlAddr && accessAddr < IntCtlAddr + IntCtlSize) { + index = (accessAddr - IntManAddr) >> 3; + data = intCtl[index].mask ? 1 << 2 : 0 | + intCtl[index].pend ? 1 << 0 : 0; + pkt->set(data); + return; + } + + if (accessAddr == JIntVecAddr) { + pkt->set(jIntVec); + return; + } + + panic("Read to unknown IOB offset 0x%x\n", accessAddr); +} + +void +Iob::readJBus(PacketPtr pkt) +{ + Addr accessAddr = pkt->getAddr() - iobJBusAddr; + int cpuid = pkt->req->getCpuNum(); + int index; + uint64_t data; + + + + + if (accessAddr >= JIntData0Addr && accessAddr < JIntData1Addr) { + index = (accessAddr - JIntData0Addr) >> 3; + pkt->set(jBusData0[index]); + return; + } + + if (accessAddr >= JIntData1Addr && accessAddr < JIntDataA0Addr) { + index = (accessAddr - JIntData1Addr) >> 3; + pkt->set(jBusData1[index]); + return; + } + + if (accessAddr == JIntDataA0Addr) { + pkt->set(jBusData0[cpuid]); + return; + } + + if (accessAddr == JIntDataA1Addr) { + pkt->set(jBusData1[cpuid]); + return; + } + + if (accessAddr >= JIntBusyAddr && accessAddr < JIntBusyAddr + JIntBusySize) { + index = (accessAddr - JIntBusyAddr) >> 3; + data = jIntBusy[index].busy ? 1 << 5 : 0 | + jIntBusy[index].source; + pkt->set(data); + return; + } + if (accessAddr == JIntABusyAddr) { + data = jIntBusy[cpuid].busy ? 1 << 5 : 0 | + jIntBusy[cpuid].source; + pkt->set(data); + return; + }; + + panic("Read to unknown JBus offset 0x%x\n", accessAddr); +} + +Tick +Iob::write(PacketPtr pkt) +{ + if (pkt->getAddr() >= iobManAddr && pkt->getAddr() < iobManAddr + iobManSize) + writeIob(pkt); + else if (pkt->getAddr() >= iobJBusAddr && pkt->getAddr() < iobJBusAddr+iobJBusSize) + writeJBus(pkt); + else + panic("Invalid address reached Iob\n"); + + + pkt->result = Packet::Success; + return pioDelay; +} + +void +Iob::writeIob(PacketPtr pkt) +{ + Addr accessAddr = pkt->getAddr() - iobManAddr; + int index; + uint64_t data; + + if (accessAddr >= IntManAddr && accessAddr < IntManAddr + IntManSize) { + index = (accessAddr - IntManAddr) >> 3; + data = pkt->get<uint64_t>(); + intMan[index].cpu = bits(data,12,8); + intMan[index].vector = bits(data,5,0); + DPRINTF(Iob, "Wrote IntMan %d cpu %d, vec %d\n", index, + intMan[index].cpu, intMan[index].vector); + return; + } + + if (accessAddr >= IntCtlAddr && accessAddr < IntCtlAddr + IntCtlSize) { + index = (accessAddr - IntManAddr) >> 3; + data = pkt->get<uint64_t>(); + intCtl[index].mask = bits(data,2,2); + if (bits(data,1,1)) + intCtl[index].pend = false; + DPRINTF(Iob, "Wrote IntCtl %d pend %d cleared %d\n", index, + intCtl[index].pend, bits(data,2,2)); + return; + } + + if (accessAddr == JIntVecAddr) { + jIntVec = bits(pkt->get<uint64_t>(), 5,0); + DPRINTF(Iob, "Wrote jIntVec %d\n", jIntVec); + return; + } + + if (accessAddr >= IntVecDisAddr && accessAddr < IntVecDisAddr + IntVecDisSize) { + Type type; + int cpu_id; + int vector; + index = (accessAddr - IntManAddr) >> 3; + data = pkt->get<uint64_t>(); + type = (Type)bits(data,17,16); + cpu_id = bits(data, 12,8); + vector = bits(data,5,0); + generateIpi(type,cpu_id, vector); + return; + } + + panic("Write to unknown IOB offset 0x%x\n", accessAddr); +} + +void +Iob::writeJBus(PacketPtr pkt) +{ + Addr accessAddr = pkt->getAddr() - iobJBusAddr; + int cpuid = pkt->req->getCpuNum(); + int index; + uint64_t data; + + if (accessAddr >= JIntBusyAddr && accessAddr < JIntBusyAddr + JIntBusySize) { + index = (accessAddr - JIntBusyAddr) >> 3; + data = pkt->get<uint64_t>(); + jIntBusy[index].busy = bits(data,5,5); + DPRINTF(Iob, "Wrote jIntBusy index %d busy: %d\n", index, + jIntBusy[index].busy); + return; + } + if (accessAddr == JIntABusyAddr) { + data = pkt->get<uint64_t>(); + jIntBusy[cpuid].busy = bits(data,5,5); + DPRINTF(Iob, "Wrote jIntBusy index %d busy: %d\n", cpuid, + jIntBusy[cpuid].busy); + return; + }; + + panic("Write to unknown JBus offset 0x%x\n", accessAddr); +} + +void +Iob::receiveDeviceInterrupt(DeviceId devid) +{ + assert(devid < NumDeviceIds); + if (intCtl[devid].mask) + return; + intCtl[devid].mask = true; + intCtl[devid].pend = true; + DPRINTF(Iob, "Receiving Device interrupt: %d for cpu %d vec %d\n", + devid, intMan[devid].cpu, intMan[devid].vector); + ic->post(intMan[devid].cpu, SparcISA::IT_INT_VEC, intMan[devid].vector); +} + + +void +Iob::generateIpi(Type type, int cpu_id, int vector) +{ + SparcISA::SparcFault<SparcISA::PowerOnReset> *por = new SparcISA::PowerOnReset(); + if (cpu_id >= sys->getNumCPUs()) + return; + + switch (type) { + case 0: // interrupt + DPRINTF(Iob, "Generating interrupt because of I/O write to cpu: %d vec %d\n", + cpu_id, vector); + ic->post(cpu_id, SparcISA::IT_INT_VEC, vector); + break; + case 1: // reset + warn("Sending reset to CPU: %d\n", cpu_id); + if (vector != por->trapType()) + panic("Don't know how to set non-POR reset to cpu\n"); + por->invoke(sys->threadContexts[cpu_id]); + sys->threadContexts[cpu_id]->activate(); + break; + case 2: // idle -- this means stop executing and don't wake on interrupts + DPRINTF(Iob, "Idling CPU because of I/O write cpu: %d\n", cpu_id); + sys->threadContexts[cpu_id]->halt(); + break; + case 3: // resume + DPRINTF(Iob, "Resuming CPU because of I/O write cpu: %d\n", cpu_id); + sys->threadContexts[cpu_id]->activate(); + break; + default: + panic("Invalid type to generate ipi\n"); + } +} + +bool +Iob::receiveJBusInterrupt(int cpu_id, int source, uint64_t d0, uint64_t d1) +{ + // If we are already dealing with an interrupt for that cpu we can't deal + // with another one right now... come back later + if (jIntBusy[cpu_id].busy) + return false; + + DPRINTF(Iob, "Receiving jBus interrupt: %d for cpu %d vec %d\n", + source, cpu_id, jIntVec); + + jIntBusy[cpu_id].busy = true; + jIntBusy[cpu_id].source = source; + jBusData0[cpu_id] = d0; + jBusData1[cpu_id] = d1; + + ic->post(cpu_id, SparcISA::IT_INT_VEC, jIntVec); + return true; +} + +void +Iob::addressRanges(AddrRangeList &range_list) +{ + range_list.clear(); + range_list.push_back(RangeSize(iobManAddr, iobManSize)); + range_list.push_back(RangeSize(iobJBusAddr, iobJBusSize)); +} + + +void +Iob::serialize(std::ostream &os) +{ + + SERIALIZE_SCALAR(jIntVec); + SERIALIZE_ARRAY(jBusData0, MaxNiagaraProcs); + SERIALIZE_ARRAY(jBusData1, MaxNiagaraProcs); + for (int x = 0; x < NumDeviceIds; x++) { + nameOut(os, csprintf("%s.Int%d", name(), x)); + paramOut(os, "cpu", intMan[x].cpu); + paramOut(os, "vector", intMan[x].vector); + paramOut(os, "mask", intCtl[x].mask); + paramOut(os, "pend", intCtl[x].pend); + }; + for (int x = 0; x < MaxNiagaraProcs; x++) { + nameOut(os, csprintf("%s.jIntBusy%d", name(), x)); + paramOut(os, "busy", jIntBusy[x].busy); + paramOut(os, "source", jIntBusy[x].source); + }; +} + +void +Iob::unserialize(Checkpoint *cp, const std::string §ion) +{ + UNSERIALIZE_SCALAR(jIntVec); + UNSERIALIZE_ARRAY(jBusData0, MaxNiagaraProcs); + UNSERIALIZE_ARRAY(jBusData1, MaxNiagaraProcs); + for (int x = 0; x < NumDeviceIds; x++) { + paramIn(cp, csprintf("%s.Int%d", name(), x), "cpu", intMan[x].cpu); + paramIn(cp, csprintf("%s.Int%d", name(), x), "vector", intMan[x].vector); + paramIn(cp, csprintf("%s.Int%d", name(), x), "mask", intCtl[x].mask); + paramIn(cp, csprintf("%s.Int%d", name(), x), "pend", intCtl[x].pend); + }; + for (int x = 0; x < MaxNiagaraProcs; x++) { + paramIn(cp, csprintf("%s.jIntBusy%d", name(), x), "busy", jIntBusy[x].busy); + paramIn(cp, csprintf("%s.jIntBusy%d", name(), x), "source", jIntBusy[x].source); + }; +} + + + + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(Iob) + Param<Tick> pio_latency; + SimObjectParam<Platform *> platform; + SimObjectParam<System *> system; +END_DECLARE_SIM_OBJECT_PARAMS(Iob) + +BEGIN_INIT_SIM_OBJECT_PARAMS(Iob) + + INIT_PARAM(pio_latency, "Programmed IO latency"), + INIT_PARAM(platform, "platform"), + INIT_PARAM(system, "system object") + +END_INIT_SIM_OBJECT_PARAMS(Iob) + +CREATE_SIM_OBJECT(Iob) +{ + Iob::Params *p = new Iob::Params; + p->name = getInstanceName(); + p->pio_delay = pio_latency; + p->platform = platform; + p->system = system; + return new Iob(p); +} + +REGISTER_SIM_OBJECT("Iob", Iob) diff --git a/src/dev/sparc/iob.hh b/src/dev/sparc/iob.hh new file mode 100644 index 000000000..c05c4f2ef --- /dev/null +++ b/src/dev/sparc/iob.hh @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Ali Saidi + */ + +/** @file + * This device implements the niagara I/O Bridge chip. The device manages + * internal (ipi) and external (serial, pci via jbus). + */ + +#ifndef __DEV_SPARC_IOB_HH__ +#define __DEV_SPARC_IOB_HH__ + +#include "base/range.hh" +#include "dev/io_device.hh" +#include "dev/disk_image.hh" + +class IntrControl; + +const int MaxNiagaraProcs = 32; +// IOB Managment Addresses +const Addr IntManAddr = 0x0000; +const Addr IntManSize = 0x0020; +const Addr IntCtlAddr = 0x0400; +const Addr IntCtlSize = 0x0020; +const Addr JIntVecAddr = 0x0A00; +const Addr IntVecDisAddr = 0x0800; +const Addr IntVecDisSize = 0x0100; + + +// IOB Control Addresses +const Addr JIntData0Addr = 0x0400; +const Addr JIntData1Addr = 0x0500; +const Addr JIntDataA0Addr = 0x0600; +const Addr JIntDataA1Addr = 0x0700; +const Addr JIntBusyAddr = 0x0900; +const Addr JIntBusySize = 0x0100; +const Addr JIntABusyAddr = 0x0B00; + + +// IOB Masks +const uint64_t IntManMask = 0x01F3F; +const uint64_t IntCtlMask = 0x00006; +const uint64_t JIntVecMask = 0x0003F; +const uint64_t IntVecDis = 0x31F3F; +const uint64_t JIntBusyMask = 0x0003F; + + +class Iob : public PioDevice +{ + private: + IntrControl *ic; + Addr iobManAddr; + Addr iobManSize; + Addr iobJBusAddr; + Addr iobJBusSize; + Tick pioDelay; + + enum DeviceId { + Interal = 0, + Error = 1, + SSI = 2, + Reserved = 3, + NumDeviceIds + }; + + struct IntMan { + int cpu; + int vector; + }; + + struct IntCtl { + bool mask; + bool pend; + }; + + struct IntBusy { + bool busy; + int source; + }; + + enum Type { + Interrupt, + Reset, + Idle, + Resume + }; + + IntMan intMan[NumDeviceIds]; + IntCtl intCtl[NumDeviceIds]; + uint64_t jIntVec; + uint64_t jBusData0[MaxNiagaraProcs]; + uint64_t jBusData1[MaxNiagaraProcs]; + IntBusy jIntBusy[MaxNiagaraProcs]; + + void writeIob(PacketPtr pkt); + void writeJBus(PacketPtr pkt); + void readIob(PacketPtr pkt); + void readJBus(PacketPtr pkt); + + + public: + struct Params : public PioDevice::Params + { + Tick pio_delay; + }; + protected: + const Params *params() const { return (const Params*)_params; } + + public: + Iob(Params *p); + + virtual Tick read(PacketPtr pkt); + virtual Tick write(PacketPtr pkt); + void generateIpi(Type type, int cpu_id, int vector); + void receiveDeviceInterrupt(DeviceId devid); + bool receiveJBusInterrupt(int cpu_id, int source, uint64_t d0, uint64_t d1); + + + void addressRanges(AddrRangeList &range_list); + + virtual void serialize(std::ostream &os); + virtual void unserialize(Checkpoint *cp, const std::string §ion); + +}; + +#endif //__DEV_SPARC_IOB_HH__ + diff --git a/src/dev/sparc/mm_disk.cc b/src/dev/sparc/mm_disk.cc index b8cabd0cf..81c5c589a 100644 --- a/src/dev/sparc/mm_disk.cc +++ b/src/dev/sparc/mm_disk.cc @@ -45,7 +45,7 @@ #include "sim/system.hh" MmDisk::MmDisk(Params *p) - : BasicPioDevice(p), image(p->image), curSector((uint64_t)-1), dirty(false) + : BasicPioDevice(p), image(p->image), curSector((off_t)-1), dirty(false) { std::memset(&diskData, 0, SectorSize); pioSize = image->size() * SectorSize; diff --git a/src/dev/uart.cc b/src/dev/uart.cc index f769b720b..1c781f76d 100644 --- a/src/dev/uart.cc +++ b/src/dev/uart.cc @@ -47,7 +47,6 @@ Uart::Uart(Params *p) // set back pointers cons->uart = this; - platform->uart = this; } DEFINE_SIM_OBJECT_CLASS_NAME("Uart", Uart) diff --git a/src/dev/uart8250.hh b/src/dev/uart8250.hh index a0620c7e0..c28200592 100644 --- a/src/dev/uart8250.hh +++ b/src/dev/uart8250.hh @@ -35,7 +35,6 @@ #ifndef __DEV_UART8250_HH__ #define __DEV_UART8250_HH__ -#include "dev/alpha/tsunamireg.h" #include "base/range.hh" #include "dev/io_device.hh" #include "dev/uart.hh" @@ -54,6 +53,18 @@ const uint8_t IIR_TXID = 0x02; /* Tx Data */ const uint8_t IIR_RXID = 0x04; /* Rx Data */ const uint8_t IIR_LINE = 0x06; /* Rx Line Status (highest priority)*/ +const uint8_t UART_IER_RDI = 0x01; +const uint8_t UART_IER_THRI = 0x02; +const uint8_t UART_IER_RLSI = 0x04; + + +const uint8_t UART_LSR_TEMT = 0x40; +const uint8_t UART_LSR_THRE = 0x20; +const uint8_t UART_LSR_DR = 0x01; + +const uint8_t UART_MCR_LOOP = 0x10; + + class SimConsole; class Platform; |