/*
- * Copyright (c) 2004 The Regents of The University of Michigan
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-/* @file
+/** @file
* Device module for modelling the National Semiconductor
* DP83820 ethernet controller. Does not support priority queueing
*/
#include "base/inet.hh"
#include "cpu/exec_context.hh"
-#include "cpu/intr_control.hh"
-#include "dev/dma.hh"
#include "dev/etherlink.hh"
#include "dev/ns_gige.hh"
#include "dev/pciconfigall.hh"
#include "mem/bus/dma_interface.hh"
#include "mem/bus/pio_interface.hh"
#include "mem/bus/pio_interface_impl.hh"
-#include "mem/functional_mem/memory_control.hh"
-#include "mem/functional_mem/physical_memory.hh"
+#include "mem/functional/memory_control.hh"
+#include "mem/functional/physical.hh"
#include "sim/builder.hh"
#include "sim/debug.hh"
#include "sim/host.hh"
: 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), txState(txIdle), txEnable(false),
- CTDD(false),
+ txXferLen(0), rxXferLen(0), clock(p->clock),
+ txState(txIdle), txEnable(false), CTDD(false),
txFragPtr(0), txDescCnt(0), txDmaState(dmaIdle), rxState(rxIdle),
rxEnable(false), CRDD(false), rxPktBytes(0),
rxFragPtr(0), rxDescCnt(0), rxDmaState(dmaIdle), extstsEnable(false),
- rxDmaReadEvent(this), rxDmaWriteEvent(this),
+ eepromState(eepromStart), 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), txKickTick(0),
+ rxKickTick(0), rxKickEvent(this), txKickTick(0), txKickEvent(this),
txEvent(this), rxFilterEnable(p->rx_filter), acceptBroadcast(false),
acceptMulticast(false), acceptUnicast(false),
- acceptPerfect(false), acceptArp(false),
+ acceptPerfect(false), acceptArp(false), multicastHashEnable(false),
physmem(p->pmem), intrTick(0), cpuPendingIntr(false),
intrEvent(0), interface(0)
{
if (p->header_bus) {
- pioInterface = newPioInterface(name(), p->hier,
+ pioInterface = newPioInterface(name() + ".pio", p->hier,
p->header_bus, this,
&NSGigE::cacheAccess);
- pioLatency = p->pio_latency * p->header_bus->clockRatio;
+ pioLatency = p->pio_latency * p->header_bus->clockRate;
if (p->payload_bus)
dmaInterface = new DMAInterface<Bus>(name() + ".dma",
p->header_bus,
- p->payload_bus, 1);
+ p->payload_bus, 1,
+ p->dma_no_allocate);
else
dmaInterface = new DMAInterface<Bus>(name() + ".dma",
p->header_bus,
- p->header_bus, 1);
+ p->header_bus, 1,
+ p->dma_no_allocate);
} else if (p->payload_bus) {
- pioInterface = newPioInterface(name(), p->hier,
+ pioInterface = newPioInterface(name() + ".pio2", p->hier,
p->payload_bus, this,
&NSGigE::cacheAccess);
- pioLatency = p->pio_latency * p->payload_bus->clockRatio;
+ pioLatency = p->pio_latency * p->payload_bus->clockRate;
dmaInterface = new DMAInterface<Bus>(name() + ".dma",
p->payload_bus,
- p->payload_bus, 1);
+ p->payload_bus, 1,
+ p->dma_no_allocate);
}
- intrDelay = US2Ticks(p->intr_delay);
+ intrDelay = p->intr_delay;
dmaReadDelay = p->dma_read_delay;
dmaWriteDelay = p->dma_write_delay;
dmaReadFactor = p->dma_read_factor;
regsReset();
memcpy(&rom.perfectMatch, p->eaddr.bytes(), ETH_ADDR_LEN);
+
+ memset(&rxDesc32, 0, sizeof(rxDesc32));
+ memset(&txDesc32, 0, sizeof(txDesc32));
+ memset(&rxDesc64, 0, sizeof(rxDesc64));
+ memset(&txDesc64, 0, sizeof(txDesc64));
}
NSGigE::~NSGigE()
.precision(0)
;
-
txBandwidth
.name(name() + ".txBandwidth")
.desc("Transmit Bandwidth (bits/s)")
.prereq(rxBytes)
;
+ totBandwidth
+ .name(name() + ".totBandwidth")
+ .desc("Total Bandwidth (bits/s)")
+ .precision(0)
+ .prereq(totBytes)
+ ;
+
+ totPackets
+ .name(name() + ".totPackets")
+ .desc("Total Packets")
+ .precision(0)
+ .prereq(totBytes)
+ ;
+
+ totBytes
+ .name(name() + ".totBytes")
+ .desc("Total Bytes")
+ .precision(0)
+ .prereq(totBytes)
+ ;
+
+ totPacketRate
+ .name(name() + ".totPPS")
+ .desc("Total Tranmission Rate (packets/s)")
+ .precision(0)
+ .prereq(totBytes)
+ ;
+
txPacketRate
.name(name() + ".txPPS")
.desc("Packet Tranmission Rate (packets/s)")
.prereq(rxBytes)
;
+ postedSwi
+ .name(name() + ".postedSwi")
+ .desc("number of software interrupts posted to CPU")
+ .precision(0)
+ ;
+
+ totalSwi
+ .name(name() + ".totalSwi")
+ .desc("total number of Swi written to ISR")
+ .precision(0)
+ ;
+
+ coalescedSwi
+ .name(name() + ".coalescedSwi")
+ .desc("average number of Swi's coalesced into each post")
+ .precision(0)
+ ;
+
+ postedRxIdle
+ .name(name() + ".postedRxIdle")
+ .desc("number of rxIdle interrupts posted to CPU")
+ .precision(0)
+ ;
+
+ totalRxIdle
+ .name(name() + ".totalRxIdle")
+ .desc("total number of RxIdle written to ISR")
+ .precision(0)
+ ;
+
+ coalescedRxIdle
+ .name(name() + ".coalescedRxIdle")
+ .desc("average number of RxIdle's coalesced into each post")
+ .precision(0)
+ ;
+
+ postedRxOk
+ .name(name() + ".postedRxOk")
+ .desc("number of RxOk interrupts posted to CPU")
+ .precision(0)
+ ;
+
+ totalRxOk
+ .name(name() + ".totalRxOk")
+ .desc("total number of RxOk written to ISR")
+ .precision(0)
+ ;
+
+ coalescedRxOk
+ .name(name() + ".coalescedRxOk")
+ .desc("average number of RxOk's coalesced into each post")
+ .precision(0)
+ ;
+
+ postedRxDesc
+ .name(name() + ".postedRxDesc")
+ .desc("number of RxDesc interrupts posted to CPU")
+ .precision(0)
+ ;
+
+ totalRxDesc
+ .name(name() + ".totalRxDesc")
+ .desc("total number of RxDesc written to ISR")
+ .precision(0)
+ ;
+
+ coalescedRxDesc
+ .name(name() + ".coalescedRxDesc")
+ .desc("average number of RxDesc's coalesced into each post")
+ .precision(0)
+ ;
+
+ postedTxOk
+ .name(name() + ".postedTxOk")
+ .desc("number of TxOk interrupts posted to CPU")
+ .precision(0)
+ ;
+
+ totalTxOk
+ .name(name() + ".totalTxOk")
+ .desc("total number of TxOk written to ISR")
+ .precision(0)
+ ;
+
+ coalescedTxOk
+ .name(name() + ".coalescedTxOk")
+ .desc("average number of TxOk's coalesced into each post")
+ .precision(0)
+ ;
+
+ postedTxIdle
+ .name(name() + ".postedTxIdle")
+ .desc("number of TxIdle interrupts posted to CPU")
+ .precision(0)
+ ;
+
+ totalTxIdle
+ .name(name() + ".totalTxIdle")
+ .desc("total number of TxIdle written to ISR")
+ .precision(0)
+ ;
+
+ coalescedTxIdle
+ .name(name() + ".coalescedTxIdle")
+ .desc("average number of TxIdle's coalesced into each post")
+ .precision(0)
+ ;
+
+ postedTxDesc
+ .name(name() + ".postedTxDesc")
+ .desc("number of TxDesc interrupts posted to CPU")
+ .precision(0)
+ ;
+
+ totalTxDesc
+ .name(name() + ".totalTxDesc")
+ .desc("total number of TxDesc written to ISR")
+ .precision(0)
+ ;
+
+ coalescedTxDesc
+ .name(name() + ".coalescedTxDesc")
+ .desc("average number of TxDesc's coalesced into each post")
+ .precision(0)
+ ;
+
+ postedRxOrn
+ .name(name() + ".postedRxOrn")
+ .desc("number of RxOrn posted to CPU")
+ .precision(0)
+ ;
+
+ totalRxOrn
+ .name(name() + ".totalRxOrn")
+ .desc("total number of RxOrn written to ISR")
+ .precision(0)
+ ;
+
+ coalescedRxOrn
+ .name(name() + ".coalescedRxOrn")
+ .desc("average number of RxOrn's coalesced into each post")
+ .precision(0)
+ ;
+
+ coalescedTotal
+ .name(name() + ".coalescedTotal")
+ .desc("average number of interrupts coalesced into each post")
+ .precision(0)
+ ;
+
+ postedInterrupts
+ .name(name() + ".postedInterrupts")
+ .desc("number of posts to CPU")
+ .precision(0)
+ ;
+
+ droppedPackets
+ .name(name() + ".droppedPackets")
+ .desc("number of packets dropped")
+ .precision(0)
+ ;
+
+ coalescedSwi = totalSwi / postedInterrupts;
+ coalescedRxIdle = totalRxIdle / postedInterrupts;
+ coalescedRxOk = totalRxOk / postedInterrupts;
+ coalescedRxDesc = totalRxDesc / postedInterrupts;
+ coalescedTxOk = totalTxOk / postedInterrupts;
+ coalescedTxIdle = totalTxIdle / postedInterrupts;
+ coalescedTxDesc = totalTxDesc / postedInterrupts;
+ coalescedRxOrn = totalRxOrn / postedInterrupts;
+
+ coalescedTotal = (totalSwi + totalRxIdle + totalRxOk + totalRxDesc +
+ totalTxOk + totalTxIdle + totalTxDesc +
+ totalRxOrn) / postedInterrupts;
+
txBandwidth = txBytes * Stats::constant(8) / simSeconds;
rxBandwidth = rxBytes * Stats::constant(8) / simSeconds;
+ totBandwidth = txBandwidth + rxBandwidth;
+ totBytes = txBytes + rxBytes;
+ totPackets = txPackets + rxPackets;
+
txPacketRate = txPackets / simSeconds;
rxPacketRate = rxPackets / simSeconds;
}
* This is to read the PCI general configuration registers
*/
void
-NSGigE::ReadConfig(int offset, int size, uint8_t *data)
+NSGigE::readConfig(int offset, int size, uint8_t *data)
{
if (offset < PCI_DEVICE_SPECIFIC)
- PciDev::ReadConfig(offset, size, data);
+ PciDev::readConfig(offset, size, data);
else
panic("Device specific PCI config space not implemented!\n");
}
* This is to write to the PCI general configuration registers
*/
void
-NSGigE::WriteConfig(int offset, int size, uint32_t data)
+NSGigE::writeConfig(int offset, int size, const uint8_t* data)
{
if (offset < PCI_DEVICE_SPECIFIC)
- PciDev::WriteConfig(offset, size, data);
+ PciDev::writeConfig(offset, size, data);
else
panic("Device specific PCI config space not implemented!\n");
if (daddr > LAST && daddr <= RESERVED) {
panic("Accessing reserved register");
} else if (daddr > RESERVED && daddr <= 0x3FC) {
- ReadConfig(daddr & 0xff, req->size, data);
+ readConfig(daddr & 0xff, req->size, data);
return No_Fault;
} else if (daddr >= MIB_START && daddr <= MIB_END) {
// don't implement all the MIB's. hopefully the kernel
case sizeof(uint32_t):
{
uint32_t ® = *(uint32_t *)data;
+ uint16_t rfaddr;
switch (daddr) {
case CR:
reg &= ~(CR_RXD | CR_TXD | CR_TXR | CR_RXR);
break;
- case CFG:
+ case CFGR:
reg = regs.config;
break;
reg = regs.txdp_hi;
break;
- case TXCFG:
+ case TX_CFG:
reg = regs.txcfg;
break;
reg = regs.rxdp_hi;
break;
- case RXCFG:
+ case RX_CFG:
reg = regs.rxcfg;
break;
break;
case RFDR:
- switch (regs.rfcr & RFCR_RFADDR) {
+ rfaddr = (uint16_t)(regs.rfcr & RFCR_RFADDR);
+ switch (rfaddr) {
+ // Read from perfect match ROM octets
case 0x000:
reg = rom.perfectMatch[1];
reg = reg << 8;
reg += rom.perfectMatch[4];
break;
default:
- panic("reading RFDR for something other than PMATCH!\n");
- // didn't implement other RFDR functionality b/c
- // driver didn't use it
+ // Read filter hash table
+ if (rfaddr >= FHASH_ADDR &&
+ rfaddr < FHASH_ADDR + FHASH_SIZE) {
+
+ // Only word-aligned reads supported
+ if (rfaddr % 2)
+ panic("unaligned read from filter hash table!");
+
+ reg = rom.filterHash[rfaddr - FHASH_ADDR + 1] << 8;
+ reg += rom.filterHash[rfaddr - FHASH_ADDR];
+ break;
+ }
+
+ panic("reading RFDR for something other than pattern"
+ " matching or hashing! %#x\n", rfaddr);
}
break;
reg = regs.tesr;
break;
+ case M5REG:
+ reg = 0;
+ if (params()->dedicated)
+ reg |= M5REG_DEDICATED;
+ break;
+
default:
panic("reading unimplemented register: addr=%#x", daddr);
}
if (daddr > LAST && daddr <= RESERVED) {
panic("Accessing reserved register");
} else if (daddr > RESERVED && daddr <= 0x3FC) {
- WriteConfig(daddr & 0xff, req->size, *(uint32_t *)data);
+ writeConfig(daddr & 0xff, req->size, data);
return No_Fault;
} else if (daddr > 0x3FC)
panic("Something is messed up!\n");
if (req->size == sizeof(uint32_t)) {
uint32_t reg = *(uint32_t *)data;
+ uint16_t rfaddr;
+
DPRINTF(EthernetPIO, "write data=%d data=%#x\n", reg, reg);
switch (daddr) {
}
break;
- case CFG:
- if (reg & CFG_LNKSTS ||
- reg & CFG_SPDSTS ||
- reg & CFG_DUPSTS ||
- reg & CFG_RESERVED ||
- reg & CFG_T64ADDR ||
- reg & CFG_PCI64_DET)
- panic("writing to read-only or reserved CFG bits!\n");
-
- regs.config |= reg & ~(CFG_LNKSTS | CFG_SPDSTS | CFG_DUPSTS |
- CFG_RESERVED | CFG_T64ADDR | CFG_PCI64_DET);
+ case CFGR:
+ if (reg & CFGR_LNKSTS ||
+ reg & CFGR_SPDSTS ||
+ reg & CFGR_DUPSTS ||
+ reg & CFGR_RESERVED ||
+ reg & CFGR_T64ADDR ||
+ reg & CFGR_PCI64_DET)
+
+ // First clear all writable bits
+ regs.config &= CFGR_LNKSTS | CFGR_SPDSTS | CFGR_DUPSTS |
+ CFGR_RESERVED | CFGR_T64ADDR |
+ CFGR_PCI64_DET;
+ // Now set the appropriate writable bits
+ regs.config |= reg & ~(CFGR_LNKSTS | CFGR_SPDSTS | CFGR_DUPSTS |
+ CFGR_RESERVED | CFGR_T64ADDR |
+ CFGR_PCI64_DET);
// all these #if 0's are because i don't THINK the kernel needs to
// have these implemented. if there is a problem relating to one of
// these, you may need to add functionality in.
-#if 0
- if (reg & CFG_TBI_EN) ;
- if (reg & CFG_MODE_1000) ;
-#endif
+ if (reg & CFGR_TBI_EN) ;
+ if (reg & CFGR_MODE_1000) ;
- if (reg & CFG_AUTO_1000)
- panic("CFG_AUTO_1000 not implemented!\n");
+ if (reg & CFGR_AUTO_1000)
+ panic("CFGR_AUTO_1000 not implemented!\n");
-#if 0
- if (reg & CFG_PINT_DUPSTS ||
- reg & CFG_PINT_LNKSTS ||
- reg & CFG_PINT_SPDSTS)
+ if (reg & CFGR_PINT_DUPSTS ||
+ reg & CFGR_PINT_LNKSTS ||
+ reg & CFGR_PINT_SPDSTS)
;
- if (reg & CFG_TMRTEST) ;
- if (reg & CFG_MRM_DIS) ;
- if (reg & CFG_MWI_DIS) ;
+ if (reg & CFGR_TMRTEST) ;
+ if (reg & CFGR_MRM_DIS) ;
+ if (reg & CFGR_MWI_DIS) ;
- if (reg & CFG_T64ADDR)
- panic("CFG_T64ADDR is read only register!\n");
+ if (reg & CFGR_T64ADDR) ;
+ // panic("CFGR_T64ADDR is read only register!\n");
- if (reg & CFG_PCI64_DET)
- panic("CFG_PCI64_DET is read only register!\n");
+ if (reg & CFGR_PCI64_DET)
+ panic("CFGR_PCI64_DET is read only register!\n");
- if (reg & CFG_DATA64_EN) ;
- if (reg & CFG_M64ADDR) ;
- if (reg & CFG_PHY_RST) ;
- if (reg & CFG_PHY_DIS) ;
-#endif
+ if (reg & CFGR_DATA64_EN) ;
+ if (reg & CFGR_M64ADDR) ;
+ if (reg & CFGR_PHY_RST) ;
+ if (reg & CFGR_PHY_DIS) ;
- if (reg & CFG_EXTSTS_EN)
+ if (reg & CFGR_EXTSTS_EN)
extstsEnable = true;
else
extstsEnable = false;
-#if 0
- if (reg & CFG_REQALG) ;
- if (reg & CFG_SB) ;
- if (reg & CFG_POW) ;
- if (reg & CFG_EXD) ;
- if (reg & CFG_PESEL) ;
- if (reg & CFG_BROM_DIS) ;
- if (reg & CFG_EXT_125) ;
- if (reg & CFG_BEM) ;
-#endif
+ if (reg & CFGR_REQALG) ;
+ if (reg & CFGR_SB) ;
+ if (reg & CFGR_POW) ;
+ if (reg & CFGR_EXD) ;
+ if (reg & CFGR_PESEL) ;
+ if (reg & CFGR_BROM_DIS) ;
+ if (reg & CFGR_EXT_125) ;
+ if (reg & CFGR_BEM) ;
break;
case MEAR:
- regs.mear = reg;
+ // Clear writable bits
+ regs.mear &= MEAR_EEDO;
+ // Set appropriate writable bits
+ regs.mear |= reg & ~MEAR_EEDO;
+
+ // FreeBSD uses the EEPROM to read PMATCH (for the MAC address)
+ // even though it could get it through RFDR
+ if (reg & MEAR_EESEL) {
+ // Rising edge of clock
+ if (reg & MEAR_EECLK && !eepromClk)
+ eepromKick();
+ }
+ else {
+ eepromState = eepromStart;
+ regs.mear &= ~MEAR_EEDI;
+ }
+
+ eepromClk = reg & MEAR_EECLK;
+
// since phy is completely faked, MEAR_MD* don't matter
- // and since the driver never uses MEAR_EE*, they don't
- // matter
-#if 0
- if (reg & MEAR_EEDI) ;
- if (reg & MEAR_EEDO) ; // this one is read only
- if (reg & MEAR_EECLK) ;
- if (reg & MEAR_EESEL) ;
if (reg & MEAR_MDIO) ;
if (reg & MEAR_MDDIR) ;
if (reg & MEAR_MDC) ;
-#endif
break;
case PTSCR:
regs.txdp_hi = reg;
break;
- case TXCFG:
+ case TX_CFG:
regs.txcfg = reg;
#if 0
- if (reg & TXCFG_CSI) ;
- if (reg & TXCFG_HBI) ;
- if (reg & TXCFG_MLB) ;
- if (reg & TXCFG_ATP) ;
- if (reg & TXCFG_ECRETRY) {
+ if (reg & TX_CFG_CSI) ;
+ if (reg & TX_CFG_HBI) ;
+ if (reg & TX_CFG_MLB) ;
+ if (reg & TX_CFG_ATP) ;
+ if (reg & TX_CFG_ECRETRY) {
/*
* this could easily be implemented, but considering
* the network is just a fake pipe, wouldn't make
*/
}
- if (reg & TXCFG_BRST_DIS) ;
+ if (reg & TX_CFG_BRST_DIS) ;
#endif
#if 0
/* we handle our own DMA, ignore the kernel's exhortations */
- if (reg & TXCFG_MXDMA) ;
+ if (reg & TX_CFG_MXDMA) ;
#endif
// also, we currently don't care about fill/drain
break;
case GPIOR:
- regs.gpior = reg;
+ // Only write writable bits
+ regs.gpior &= GPIOR_UNUSED | GPIOR_GP5_IN | GPIOR_GP4_IN
+ | GPIOR_GP3_IN | GPIOR_GP2_IN | GPIOR_GP1_IN;
+ regs.gpior |= reg & ~(GPIOR_UNUSED | GPIOR_GP5_IN | GPIOR_GP4_IN
+ | GPIOR_GP3_IN | GPIOR_GP2_IN | GPIOR_GP1_IN);
/* these just control general purpose i/o pins, don't matter */
break;
regs.rxdp_hi = reg;
break;
- case RXCFG:
+ case RX_CFG:
regs.rxcfg = reg;
#if 0
- if (reg & RXCFG_AEP) ;
- if (reg & RXCFG_ARP) ;
- if (reg & RXCFG_STRIPCRC) ;
- if (reg & RXCFG_RX_RD) ;
- if (reg & RXCFG_ALP) ;
- if (reg & RXCFG_AIRL) ;
+ if (reg & RX_CFG_AEP) ;
+ if (reg & RX_CFG_ARP) ;
+ if (reg & RX_CFG_STRIPCRC) ;
+ if (reg & RX_CFG_RX_RD) ;
+ if (reg & RX_CFG_ALP) ;
+ if (reg & RX_CFG_AIRL) ;
/* we handle our own DMA, ignore what kernel says about it */
- if (reg & RXCFG_MXDMA) ;
+ if (reg & RX_CFG_MXDMA) ;
//also, we currently don't care about fill/drain thresholds
//though this may change in the future with more realistic
//networks or a driver which changes it according to feedback
- if (reg & (RXCFG_DRTH | RXCFG_DRTH0)) ;
+ if (reg & (RX_CFG_DRTH | RX_CFG_DRTH0)) ;
#endif
break;
acceptUnicast = (reg & RFCR_AAU) ? true : false;
acceptPerfect = (reg & RFCR_APM) ? true : false;
acceptArp = (reg & RFCR_AARP) ? true : false;
+ multicastHashEnable = (reg & RFCR_MHEN) ? true : false;
#if 0
if (reg & RFCR_APAT)
panic("RFCR_APAT not implemented!\n");
#endif
-
- if (reg & RFCR_MHEN || reg & RFCR_UHEN)
- panic("hash filtering not implemented!\n");
+ if (reg & RFCR_UHEN)
+ panic("Unicast hash filtering not used by drivers!\n");
if (reg & RFCR_ULM)
panic("RFCR_ULM not implemented!\n");
break;
case RFDR:
- panic("the driver never writes to RFDR, something is wrong!\n");
+ rfaddr = (uint16_t)(regs.rfcr & RFCR_RFADDR);
+ switch (rfaddr) {
+ case 0x000:
+ rom.perfectMatch[0] = (uint8_t)reg;
+ rom.perfectMatch[1] = (uint8_t)(reg >> 8);
+ break;
+ case 0x002:
+ rom.perfectMatch[2] = (uint8_t)reg;
+ rom.perfectMatch[3] = (uint8_t)(reg >> 8);
+ break;
+ case 0x004:
+ rom.perfectMatch[4] = (uint8_t)reg;
+ rom.perfectMatch[5] = (uint8_t)(reg >> 8);
+ break;
+ default:
+
+ if (rfaddr >= FHASH_ADDR &&
+ rfaddr < FHASH_ADDR + FHASH_SIZE) {
+
+ // Only word-aligned writes supported
+ if (rfaddr % 2)
+ panic("unaligned write to filter hash table!");
+
+ rom.filterHash[rfaddr - FHASH_ADDR] = (uint8_t)reg;
+ rom.filterHash[rfaddr - FHASH_ADDR + 1]
+ = (uint8_t)(reg >> 8);
+ break;
+ }
+ panic("writing RFDR for something other than pattern matching\
+ or hashing! %#x\n", rfaddr);
+ }
case BRAR:
- panic("the driver never uses BRAR, something is wrong!\n");
+ regs.brar = reg;
+ break;
case BRDR:
panic("the driver never uses BRDR, something is wrong!\n");
case VDR:
panic("the driver never uses VDR, something is wrong!\n");
- break;
case CCSR:
/* not going to implement clockrun stuff */
panic("TBISR is read only register!\n");
case TANAR:
- regs.tanar = reg;
- if (reg & TANAR_PS2)
- panic("this isn't used in driver, something wrong!\n");
+ // Only write the writable bits
+ regs.tanar &= TANAR_RF1 | TANAR_RF2 | TANAR_UNUSED;
+ regs.tanar |= reg & ~(TANAR_RF1 | TANAR_RF2 | TANAR_UNUSED);
+
+ // Pause capability unimplemented
+#if 0
+ if (reg & TANAR_PS2) ;
+ if (reg & TANAR_PS1) ;
+#endif
- if (reg & TANAR_PS1)
- panic("this isn't used in driver, something wrong!\n");
break;
case TANLPAR:
if (interrupts & ISR_NOIMPL)
warn("interrupt not implemented %#x\n", interrupts);
- interrupts &= ~ISR_NOIMPL;
+ interrupts &= ISR_IMPL;
regs.isr |= interrupts;
+ if (interrupts & regs.imr) {
+ if (interrupts & ISR_SWI) {
+ totalSwi++;
+ }
+ if (interrupts & ISR_RXIDLE) {
+ totalRxIdle++;
+ }
+ if (interrupts & ISR_RXOK) {
+ totalRxOk++;
+ }
+ if (interrupts & ISR_RXDESC) {
+ totalRxDesc++;
+ }
+ if (interrupts & ISR_TXOK) {
+ totalTxOk++;
+ }
+ if (interrupts & ISR_TXIDLE) {
+ totalTxIdle++;
+ }
+ if (interrupts & ISR_TXDESC) {
+ totalTxDesc++;
+ }
+ if (interrupts & ISR_RXORN) {
+ totalRxOrn++;
+ }
+ }
+
DPRINTF(EthernetIntr,
"interrupt written to ISR: intr=%#x isr=%#x imr=%#x\n",
interrupts, regs.isr, regs.imr);
if ((regs.isr & regs.imr)) {
Tick when = curTick;
- if (!(regs.isr & regs.imr & ISR_NODELAY))
+ if ((regs.isr & regs.imr & ISR_NODELAY) == 0)
when += intrDelay;
cpuIntrPost(when);
}
}
+/* writing this interrupt counting stats inside this means that this function
+ is now limited to being used to clear all interrupts upon the kernel
+ reading isr and servicing. just telling you in case you were thinking
+ of expanding use.
+*/
void
NSGigE::devIntrClear(uint32_t interrupts)
{
if (interrupts & ISR_RESERVE)
panic("Cannot clear a reserved interrupt");
+ if (regs.isr & regs.imr & ISR_SWI) {
+ postedSwi++;
+ }
+ if (regs.isr & regs.imr & ISR_RXIDLE) {
+ postedRxIdle++;
+ }
+ if (regs.isr & regs.imr & ISR_RXOK) {
+ postedRxOk++;
+ }
+ if (regs.isr & regs.imr & ISR_RXDESC) {
+ postedRxDesc++;
+ }
+ if (regs.isr & regs.imr & ISR_TXOK) {
+ postedTxOk++;
+ }
+ if (regs.isr & regs.imr & ISR_TXIDLE) {
+ postedTxIdle++;
+ }
+ if (regs.isr & regs.imr & ISR_TXDESC) {
+ postedTxDesc++;
+ }
+ if (regs.isr & regs.imr & ISR_RXORN) {
+ postedRxOrn++;
+ }
+
+ if (regs.isr & regs.imr & ISR_IMPL)
+ postedInterrupts++;
+
interrupts &= ~ISR_NOIMPL;
regs.isr &= ~interrupts;
NSGigE::regsReset()
{
memset(®s, 0, sizeof(regs));
- regs.config = CFG_LNKSTS;
- regs.mear = MEAR_MDDIR | MEAR_EEDO;
+ regs.config = (CFGR_LNKSTS | CFGR_TBI_EN | CFGR_MODE_1000);
+ regs.mear = 0x12;
regs.txcfg = 0x120; // set drain threshold to 1024 bytes and
// fill threshold to 32 bytes
regs.rxcfg = 0x4; // set drain threshold to 16 bytes
regs.mibc = MIBC_FRZ;
regs.vdr = 0x81; // set the vlan tag type to 802.1q
regs.tesr = 0xc000; // TBI capable of both full and half duplex
+ regs.brar = 0xffffffff;
extstsEnable = false;
acceptBroadcast = false;
void
NSGigE::rxKick()
{
- DPRINTF(EthernetSM, "receive kick rxState=%s (rxBuf.size=%d)\n",
- NsRxStateStrings[rxState], rxFifo.size());
+ bool is64bit = (bool)(regs.config & CFGR_M64ADDR);
- if (rxKickTick > curTick) {
- DPRINTF(EthernetSM, "receive kick exiting, can't run till %d\n",
- rxKickTick);
- return;
- }
+ DPRINTF(EthernetSM,
+ "receive kick rxState=%s (rxBuf.size=%d) %d-bit\n",
+ NsRxStateStrings[rxState], rxFifo.size(), is64bit ? 64 : 32);
+
+ Addr link, bufptr;
+ uint32_t &cmdsts = is64bit ? rxDesc64.cmdsts : rxDesc32.cmdsts;
+ uint32_t &extsts = is64bit ? rxDesc64.extsts : rxDesc32.extsts;
next:
+ if (clock) {
+ if (rxKickTick > curTick) {
+ DPRINTF(EthernetSM, "receive kick exiting, can't run till %d\n",
+ rxKickTick);
+
+ goto exit;
+ }
+
+ // Go to the next state machine clock tick.
+ rxKickTick = curTick + cycles(1);
+ }
+
switch(rxDmaState) {
case dmaReadWaiting:
if (doRxDmaRead())
break;
}
+ link = is64bit ? (Addr)rxDesc64.link : (Addr)rxDesc32.link;
+ bufptr = is64bit ? (Addr)rxDesc64.bufptr : (Addr)rxDesc32.bufptr;
+
// see state machine from spec for details
// the way this works is, if you finish work on one state and can
// go directly to another, you do that through jumping to the
rxState = rxDescRefr;
rxDmaAddr = regs.rxdp & 0x3fffffff;
- rxDmaData = &rxDescCache + offsetof(ns_desc, link);
- rxDmaLen = sizeof(rxDescCache.link);
+ rxDmaData =
+ is64bit ? (void *)&rxDesc64.link : (void *)&rxDesc32.link;
+ rxDmaLen = is64bit ? sizeof(rxDesc64.link) : sizeof(rxDesc32.link);
rxDmaFree = dmaDescFree;
descDmaReads++;
rxState = rxDescRead;
rxDmaAddr = regs.rxdp & 0x3fffffff;
- rxDmaData = &rxDescCache;
- rxDmaLen = sizeof(ns_desc);
+ rxDmaData = is64bit ? (void *)&rxDesc64 : (void *)&rxDesc32;
+ rxDmaLen = is64bit ? sizeof(rxDesc64) : sizeof(rxDesc32);
rxDmaFree = dmaDescFree;
descDmaReads++;
if (rxDmaState != dmaIdle)
goto exit;
- DPRINTF(EthernetDesc,
- "rxDescCache: addr=%08x read descriptor\n",
+ DPRINTF(EthernetDesc, "rxDesc: addr=%08x read descriptor\n",
regs.rxdp & 0x3fffffff);
DPRINTF(EthernetDesc,
- "rxDescCache: link=%08x bufptr=%08x cmdsts=%08x extsts=%08x\n",
- rxDescCache.link, rxDescCache.bufptr, rxDescCache.cmdsts,
- rxDescCache.extsts);
+ "rxDesc: link=%#x bufptr=%#x cmdsts=%08x extsts=%08x\n",
+ link, bufptr, cmdsts, extsts);
- if (rxDescCache.cmdsts & CMDSTS_OWN) {
+ if (cmdsts & CMDSTS_OWN) {
devIntrPost(ISR_RXIDLE);
rxState = rxIdle;
goto exit;
} else {
rxState = rxFifoBlock;
- rxFragPtr = rxDescCache.bufptr;
- rxDescCnt = rxDescCache.cmdsts & CMDSTS_LEN_MASK;
+ rxFragPtr = bufptr;
+ rxDescCnt = cmdsts & CMDSTS_LEN_MASK;
}
break;
DPRINTF(Ethernet, "ID is %d\n", ip->id());
TcpPtr tcp(ip);
if (tcp) {
- DPRINTF(Ethernet, "Src Port=%d, Dest Port=%d\n",
- tcp->sport(), tcp->dport());
+ DPRINTF(Ethernet,
+ "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n",
+ tcp->sport(), tcp->dport(), tcp->seq(),
+ tcp->ack());
}
}
}
assert(rxPktBytes == 0);
DPRINTF(EthernetSM, "done with receiving packet\n");
- rxDescCache.cmdsts |= CMDSTS_OWN;
- rxDescCache.cmdsts &= ~CMDSTS_MORE;
- rxDescCache.cmdsts |= CMDSTS_OK;
- rxDescCache.cmdsts &= 0xffff0000;
- rxDescCache.cmdsts += rxPacket->length; //i.e. set CMDSTS_SIZE
+ cmdsts |= CMDSTS_OWN;
+ cmdsts &= ~CMDSTS_MORE;
+ cmdsts |= CMDSTS_OK;
+ cmdsts &= 0xffff0000;
+ cmdsts += rxPacket->length; //i.e. set CMDSTS_SIZE
#if 0
/*
* functional purposes, just undef
*/
if (rxFilterEnable) {
- rxDescCache.cmdsts &= ~CMDSTS_DEST_MASK;
+ cmdsts &= ~CMDSTS_DEST_MASK;
const EthAddr &dst = rxFifoFront()->dst();
if (dst->unicast())
- rxDescCache.cmdsts |= CMDSTS_DEST_SELF;
+ cmdsts |= CMDSTS_DEST_SELF;
if (dst->multicast())
- rxDescCache.cmdsts |= CMDSTS_DEST_MULTI;
+ cmdsts |= CMDSTS_DEST_MULTI;
if (dst->broadcast())
- rxDescCache.cmdsts |= CMDSTS_DEST_MASK;
+ cmdsts |= CMDSTS_DEST_MASK;
}
#endif
IpPtr ip(rxPacket);
if (extstsEnable && ip) {
- rxDescCache.extsts |= EXTSTS_IPPKT;
+ extsts |= EXTSTS_IPPKT;
rxIpChecksums++;
if (cksum(ip) != 0) {
DPRINTF(EthernetCksum, "Rx IP Checksum Error\n");
- rxDescCache.extsts |= EXTSTS_IPERR;
+ extsts |= EXTSTS_IPERR;
}
TcpPtr tcp(ip);
UdpPtr udp(ip);
if (tcp) {
- rxDescCache.extsts |= EXTSTS_TCPPKT;
+ extsts |= EXTSTS_TCPPKT;
rxTcpChecksums++;
if (cksum(tcp) != 0) {
DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n");
- rxDescCache.extsts |= EXTSTS_TCPERR;
+ extsts |= EXTSTS_TCPERR;
}
} else if (udp) {
- rxDescCache.extsts |= EXTSTS_UDPPKT;
+ extsts |= EXTSTS_UDPPKT;
rxUdpChecksums++;
if (cksum(udp) != 0) {
DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n");
- rxDescCache.extsts |= EXTSTS_UDPERR;
+ extsts |= EXTSTS_UDPERR;
}
}
}
*/
DPRINTF(EthernetDesc,
- "rxDescCache: addr=%08x writeback cmdsts extsts\n",
+ "rxDesc: addr=%08x writeback cmdsts extsts\n",
regs.rxdp & 0x3fffffff);
DPRINTF(EthernetDesc,
- "rxDescCache: link=%08x bufptr=%08x cmdsts=%08x extsts=%08x\n",
- rxDescCache.link, rxDescCache.bufptr, rxDescCache.cmdsts,
- rxDescCache.extsts);
+ "rxDesc: link=%#x bufptr=%#x cmdsts=%08x extsts=%08x\n",
+ link, bufptr, cmdsts, extsts);
- rxDmaAddr = (regs.rxdp + offsetof(ns_desc, cmdsts)) & 0x3fffffff;
- rxDmaData = &(rxDescCache.cmdsts);
- rxDmaLen = sizeof(rxDescCache.cmdsts) + sizeof(rxDescCache.extsts);
+ rxDmaAddr = regs.rxdp & 0x3fffffff;
+ rxDmaData = &cmdsts;
+ if (is64bit) {
+ rxDmaAddr += offsetof(ns_desc64, cmdsts);
+ rxDmaLen = sizeof(rxDesc64.cmdsts) + sizeof(rxDesc64.extsts);
+ } else {
+ rxDmaAddr += offsetof(ns_desc32, cmdsts);
+ rxDmaLen = sizeof(rxDesc32.cmdsts) + sizeof(rxDesc32.extsts);
+ }
rxDmaFree = dmaDescFree;
descDmaWrites++;
if (rxDmaState != dmaIdle)
goto exit;
- assert(rxDescCache.cmdsts & CMDSTS_OWN);
+ assert(cmdsts & CMDSTS_OWN);
assert(rxPacket == 0);
devIntrPost(ISR_RXOK);
- if (rxDescCache.cmdsts & CMDSTS_INTR)
+ if (cmdsts & CMDSTS_INTR)
devIntrPost(ISR_RXDESC);
if (!rxEnable) {
break;
case rxAdvance:
- if (rxDescCache.link == 0) {
+ if (link == 0) {
devIntrPost(ISR_RXIDLE);
rxState = rxIdle;
CRDD = true;
goto exit;
} else {
+ if (rxDmaState != dmaIdle)
+ goto exit;
rxState = rxDescRead;
- regs.rxdp = rxDescCache.link;
+ regs.rxdp = link;
CRDD = false;
rxDmaAddr = regs.rxdp & 0x3fffffff;
- rxDmaData = &rxDescCache;
- rxDmaLen = sizeof(ns_desc);
+ rxDmaData = is64bit ? (void *)&rxDesc64 : (void *)&rxDesc32;
+ rxDmaLen = is64bit ? sizeof(rxDesc64) : sizeof(rxDesc32);
rxDmaFree = dmaDescFree;
if (doRxDmaRead())
DPRINTF(EthernetSM, "entering next rxState=%s\n",
NsRxStateStrings[rxState]);
-
goto next;
exit:
*/
DPRINTF(EthernetSM, "rx state machine exited rxState=%s\n",
NsRxStateStrings[rxState]);
+
+ if (clock && !rxKickEvent.scheduled())
+ rxKickEvent.schedule(rxKickTick);
}
void
DPRINTF(Ethernet, "ID is %d\n", ip->id());
TcpPtr tcp(ip);
if (tcp) {
- DPRINTF(Ethernet, "Src Port=%d, Dest Port=%d\n",
- tcp->sport(), tcp->dport());
+ DPRINTF(Ethernet,
+ "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n",
+ tcp->sport(), tcp->dport(), tcp->seq(),
+ tcp->ack());
}
}
}
#endif
- DDUMP(Ethernet, txFifo.front()->data, txFifo.front()->length);
+ DDUMP(EthernetData, txFifo.front()->data, txFifo.front()->length);
txBytes += txFifo.front()->length;
txPackets++;
if (!txFifo.empty() && !txEvent.scheduled()) {
DPRINTF(Ethernet, "reschedule transmit\n");
- txEvent.schedule(curTick + 1000);
+ txEvent.schedule(curTick + retryTime);
}
}
void
NSGigE::txKick()
{
- DPRINTF(EthernetSM, "transmit kick txState=%s\n",
- NsTxStateStrings[txState]);
+ bool is64bit = (bool)(regs.config & CFGR_M64ADDR);
- if (txKickTick > curTick) {
- DPRINTF(EthernetSM, "transmit kick exiting, can't run till %d\n",
- txKickTick);
+ DPRINTF(EthernetSM, "transmit kick txState=%s %d-bit\n",
+ NsTxStateStrings[txState], is64bit ? 64 : 32);
- return;
- }
+ Addr link, bufptr;
+ uint32_t &cmdsts = is64bit ? txDesc64.cmdsts : txDesc32.cmdsts;
+ uint32_t &extsts = is64bit ? txDesc64.extsts : txDesc32.extsts;
next:
+ if (clock) {
+ if (txKickTick > curTick) {
+ DPRINTF(EthernetSM, "transmit kick exiting, can't run till %d\n",
+ txKickTick);
+ goto exit;
+ }
+
+ // Go to the next state machine clock tick.
+ txKickTick = curTick + cycles(1);
+ }
+
switch(txDmaState) {
case dmaReadWaiting:
if (doTxDmaRead())
break;
}
+ link = is64bit ? (Addr)txDesc64.link : (Addr)txDesc32.link;
+ bufptr = is64bit ? (Addr)txDesc64.bufptr : (Addr)txDesc32.bufptr;
switch (txState) {
case txIdle:
if (!txEnable) {
txState = txDescRefr;
txDmaAddr = regs.txdp & 0x3fffffff;
- txDmaData = &txDescCache + offsetof(ns_desc, link);
- txDmaLen = sizeof(txDescCache.link);
+ txDmaData =
+ is64bit ? (void *)&txDesc64.link : (void *)&txDesc32.link;
+ txDmaLen = is64bit ? sizeof(txDesc64.link) : sizeof(txDesc32.link);
txDmaFree = dmaDescFree;
descDmaReads++;
txState = txDescRead;
txDmaAddr = regs.txdp & 0x3fffffff;
- txDmaData = &txDescCache;
- txDmaLen = sizeof(ns_desc);
+ txDmaData = is64bit ? (void *)&txDesc64 : (void *)&txDesc32;
+ txDmaLen = is64bit ? sizeof(txDesc64) : sizeof(txDesc32);
txDmaFree = dmaDescFree;
descDmaReads++;
if (txDmaState != dmaIdle)
goto exit;
+ DPRINTF(EthernetDesc, "txDesc: addr=%08x read descriptor\n",
+ regs.txdp & 0x3fffffff);
DPRINTF(EthernetDesc,
- "txDescCache: link=%08x bufptr=%08x cmdsts=%08x extsts=%08x\n",
- txDescCache.link, txDescCache.bufptr, txDescCache.cmdsts,
- txDescCache.extsts);
+ "txDesc: link=%#x bufptr=%#x cmdsts=%#08x extsts=%#08x\n",
+ link, bufptr, cmdsts, extsts);
- if (txDescCache.cmdsts & CMDSTS_OWN) {
+ if (cmdsts & CMDSTS_OWN) {
txState = txFifoBlock;
- txFragPtr = txDescCache.bufptr;
- txDescCnt = txDescCache.cmdsts & CMDSTS_LEN_MASK;
+ txFragPtr = bufptr;
+ txDescCnt = cmdsts & CMDSTS_LEN_MASK;
} else {
devIntrPost(ISR_TXIDLE);
txState = txIdle;
case txFifoBlock:
if (!txPacket) {
DPRINTF(EthernetSM, "****starting the tx of a new packet****\n");
- txPacket = new PacketData;
- txPacket->data = new uint8_t[16384];
+ txPacket = new PacketData(16384);
txPacketBufPtr = txPacket->data;
}
if (txDescCnt == 0) {
DPRINTF(EthernetSM, "the txDescCnt == 0, done with descriptor\n");
- if (txDescCache.cmdsts & CMDSTS_MORE) {
+ if (cmdsts & CMDSTS_MORE) {
DPRINTF(EthernetSM, "there are more descriptors to come\n");
txState = txDescWrite;
- txDescCache.cmdsts &= ~CMDSTS_OWN;
+ cmdsts &= ~CMDSTS_OWN;
- txDmaAddr = regs.txdp + offsetof(ns_desc, cmdsts);
- txDmaAddr &= 0x3fffffff;
- txDmaData = &(txDescCache.cmdsts);
- txDmaLen = sizeof(txDescCache.cmdsts);
+ txDmaAddr = regs.txdp & 0x3fffffff;
+ txDmaData = &cmdsts;
+ if (is64bit) {
+ txDmaAddr += offsetof(ns_desc64, cmdsts);
+ txDmaLen = sizeof(txDesc64.cmdsts);
+ } else {
+ txDmaAddr += offsetof(ns_desc32, cmdsts);
+ txDmaLen = sizeof(txDesc32.cmdsts);
+ }
txDmaFree = dmaDescFree;
if (doTxDmaWrite())
/* deal with the the packet that just finished */
if ((regs.vtcr & VTCR_PPCHK) && extstsEnable) {
IpPtr ip(txPacket);
- if (txDescCache.extsts & EXTSTS_UDPPKT) {
+ if (extsts & EXTSTS_UDPPKT) {
UdpPtr udp(ip);
udp->sum(0);
udp->sum(cksum(udp));
txUdpChecksums++;
- } else if (txDescCache.extsts & EXTSTS_TCPPKT) {
+ } else if (extsts & EXTSTS_TCPPKT) {
TcpPtr tcp(ip);
tcp->sum(0);
tcp->sum(cksum(tcp));
txTcpChecksums++;
}
- if (txDescCache.extsts & EXTSTS_IPPKT) {
+ if (extsts & EXTSTS_IPPKT) {
ip->sum(0);
ip->sum(cksum(ip));
txIpChecksums++;
txPacket->length = txPacketBufPtr - txPacket->data;
// this is just because the receive can't handle a
// packet bigger want to make sure
- assert(txPacket->length <= 1514);
+ if (txPacket->length > 1514)
+ panic("transmit packet too large, %s > 1514\n",
+ txPacket->length);
+
#ifndef NDEBUG
bool success =
#endif
* spec would complicate the code, we just do it here
*/
- txDescCache.cmdsts &= ~CMDSTS_OWN;
- txDescCache.cmdsts |= CMDSTS_OK;
+ cmdsts &= ~CMDSTS_OWN;
+ cmdsts |= CMDSTS_OK;
DPRINTF(EthernetDesc,
"txDesc writeback: cmdsts=%08x extsts=%08x\n",
- txDescCache.cmdsts, txDescCache.extsts);
+ cmdsts, extsts);
- txDmaAddr = regs.txdp + offsetof(ns_desc, cmdsts);
- txDmaAddr &= 0x3fffffff;
- txDmaData = &(txDescCache.cmdsts);
- txDmaLen = sizeof(txDescCache.cmdsts) +
- sizeof(txDescCache.extsts);
txDmaFree = dmaDescFree;
+ txDmaAddr = regs.txdp & 0x3fffffff;
+ txDmaData = &cmdsts;
+ if (is64bit) {
+ txDmaAddr += offsetof(ns_desc64, cmdsts);
+ txDmaLen =
+ sizeof(txDesc64.cmdsts) + sizeof(txDesc64.extsts);
+ } else {
+ txDmaAddr += offsetof(ns_desc32, cmdsts);
+ txDmaLen =
+ sizeof(txDesc32.cmdsts) + sizeof(txDesc32.extsts);
+ }
descDmaWrites++;
descDmaWrBytes += txDmaLen;
if (txDmaState != dmaIdle)
goto exit;
- if (txDescCache.cmdsts & CMDSTS_INTR)
+ if (cmdsts & CMDSTS_INTR)
devIntrPost(ISR_TXDESC);
- txState = txAdvance;
+ if (!txEnable) {
+ DPRINTF(EthernetSM, "halting TX state machine\n");
+ txState = txIdle;
+ goto exit;
+ } else
+ txState = txAdvance;
break;
case txAdvance:
- if (txDescCache.link == 0) {
+ if (link == 0) {
devIntrPost(ISR_TXIDLE);
txState = txIdle;
goto exit;
} else {
+ if (txDmaState != dmaIdle)
+ goto exit;
txState = txDescRead;
- regs.txdp = txDescCache.link;
+ regs.txdp = link;
CTDD = false;
- txDmaAddr = txDescCache.link & 0x3fffffff;
- txDmaData = &txDescCache;
- txDmaLen = sizeof(ns_desc);
+ txDmaAddr = link & 0x3fffffff;
+ txDmaData = is64bit ? (void *)&txDesc64 : (void *)&txDesc32;
+ txDmaLen = is64bit ? sizeof(txDesc64) : sizeof(txDesc32);
txDmaFree = dmaDescFree;
if (doTxDmaRead())
DPRINTF(EthernetSM, "entering next txState=%s\n",
NsTxStateStrings[txState]);
-
goto next;
exit:
*/
DPRINTF(EthernetSM, "tx state machine exited txState=%s\n",
NsTxStateStrings[txState]);
+
+ if (clock && !txKickEvent.scheduled())
+ txKickEvent.schedule(txKickTick);
+}
+
+/**
+ * Advance the EEPROM state machine
+ * Called on rising edge of EEPROM clock bit in MEAR
+ */
+void
+NSGigE::eepromKick()
+{
+ switch (eepromState) {
+
+ case eepromStart:
+
+ // Wait for start bit
+ if (regs.mear & MEAR_EEDI) {
+ // Set up to get 2 opcode bits
+ eepromState = eepromGetOpcode;
+ eepromBitsToRx = 2;
+ eepromOpcode = 0;
+ }
+ break;
+
+ case eepromGetOpcode:
+ eepromOpcode <<= 1;
+ eepromOpcode += (regs.mear & MEAR_EEDI) ? 1 : 0;
+ --eepromBitsToRx;
+
+ // Done getting opcode
+ if (eepromBitsToRx == 0) {
+ if (eepromOpcode != EEPROM_READ)
+ panic("only EEPROM reads are implemented!");
+
+ // Set up to get address
+ eepromState = eepromGetAddress;
+ eepromBitsToRx = 6;
+ eepromAddress = 0;
+ }
+ break;
+
+ case eepromGetAddress:
+ eepromAddress <<= 1;
+ eepromAddress += (regs.mear & MEAR_EEDI) ? 1 : 0;
+ --eepromBitsToRx;
+
+ // Done getting address
+ if (eepromBitsToRx == 0) {
+
+ if (eepromAddress >= EEPROM_SIZE)
+ panic("EEPROM read access out of range!");
+
+ switch (eepromAddress) {
+
+ case EEPROM_PMATCH2_ADDR:
+ eepromData = rom.perfectMatch[5];
+ eepromData <<= 8;
+ eepromData += rom.perfectMatch[4];
+ break;
+
+ case EEPROM_PMATCH1_ADDR:
+ eepromData = rom.perfectMatch[3];
+ eepromData <<= 8;
+ eepromData += rom.perfectMatch[2];
+ break;
+
+ case EEPROM_PMATCH0_ADDR:
+ eepromData = rom.perfectMatch[1];
+ eepromData <<= 8;
+ eepromData += rom.perfectMatch[0];
+ break;
+
+ default:
+ panic("FreeBSD driver only uses EEPROM to read PMATCH!");
+ }
+ // Set up to read data
+ eepromState = eepromRead;
+ eepromBitsToRx = 16;
+
+ // Clear data in bit
+ regs.mear &= ~MEAR_EEDI;
+ }
+ break;
+
+ case eepromRead:
+ // Clear Data Out bit
+ regs.mear &= ~MEAR_EEDO;
+ // Set bit to value of current EEPROM bit
+ regs.mear |= (eepromData & 0x8000) ? MEAR_EEDO : 0x0;
+
+ eepromData <<= 1;
+ --eepromBitsToRx;
+
+ // All done
+ if (eepromBitsToRx == 0) {
+ eepromState = eepromStart;
+ }
+ break;
+
+ default:
+ panic("invalid EEPROM state");
+ }
+
}
void
DPRINTF(Ethernet, "transfer complete: data in txFifo...schedule xmit\n");
if (txEvent.scheduled())
- txEvent.reschedule(curTick + 1);
+ txEvent.reschedule(curTick + cycles(1));
else
- txEvent.schedule(curTick + 1);
+ txEvent.schedule(curTick + cycles(1));
}
bool
if (acceptMulticast)
drop = false;
+ // Multicast hashing faked - all packets accepted
+ if (multicastHashEnable)
+ drop = false;
}
if (drop) {
if (!rxEnable) {
DPRINTF(Ethernet, "receive disabled...packet dropped\n");
- debug_break();
interface->recvDone();
return true;
}
- if (rxFilterEnable && rxFilter(packet)) {
+ if (!rxFilterEnable) {
+ DPRINTF(Ethernet,
+ "receive packet filtering disabled . . . packet dropped\n");
+ interface->recvDone();
+ return true;
+ }
+
+ if (rxFilter(packet)) {
DPRINTF(Ethernet, "packet filtered...dropped\n");
interface->recvDone();
return true;
}
if (rxFifo.avail() < packet->length) {
- DPRINTF(Ethernet,
- "packet will not fit in receive buffer...packet dropped\n");
+#if TRACING_ON
+ IpPtr ip(packet);
+ TcpPtr tcp(ip);
+ if (ip) {
+ DPRINTF(Ethernet,
+ "packet won't fit in receive buffer...pkt ID %d dropped\n",
+ ip->id());
+ if (tcp) {
+ DPRINTF(Ethernet, "Seq=%d\n", tcp->seq());
+ }
+ }
+#endif
+ droppedPackets++;
devIntrPost(ISR_RXORN);
return false;
}
SERIALIZE_SCALAR(regs.pcr);
SERIALIZE_SCALAR(regs.rfcr);
SERIALIZE_SCALAR(regs.rfdr);
+ SERIALIZE_SCALAR(regs.brar);
+ SERIALIZE_SCALAR(regs.brdr);
SERIALIZE_SCALAR(regs.srr);
SERIALIZE_SCALAR(regs.mibc);
SERIALIZE_SCALAR(regs.vrcr);
SERIALIZE_SCALAR(regs.tesr);
SERIALIZE_ARRAY(rom.perfectMatch, ETH_ADDR_LEN);
+ SERIALIZE_ARRAY(rom.filterHash, FHASH_SIZE);
SERIALIZE_SCALAR(ioEnable);
bool txPacketExists = txPacket;
SERIALIZE_SCALAR(txPacketExists);
if (txPacketExists) {
+ txPacket->length = txPacketBufPtr - txPacket->data;
txPacket->serialize("txPacket", os);
uint32_t txPktBufPtr = (uint32_t) (txPacketBufPtr - txPacket->data);
SERIALIZE_SCALAR(txPktBufPtr);
SERIALIZE_SCALAR(rxXferLen);
/*
- * Serialize DescCaches
+ * Serialize Cached Descriptors
*/
- SERIALIZE_SCALAR(txDescCache.link);
- SERIALIZE_SCALAR(txDescCache.bufptr);
- SERIALIZE_SCALAR(txDescCache.cmdsts);
- SERIALIZE_SCALAR(txDescCache.extsts);
- SERIALIZE_SCALAR(rxDescCache.link);
- SERIALIZE_SCALAR(rxDescCache.bufptr);
- SERIALIZE_SCALAR(rxDescCache.cmdsts);
- SERIALIZE_SCALAR(rxDescCache.extsts);
+ SERIALIZE_SCALAR(rxDesc64.link);
+ SERIALIZE_SCALAR(rxDesc64.bufptr);
+ SERIALIZE_SCALAR(rxDesc64.cmdsts);
+ SERIALIZE_SCALAR(rxDesc64.extsts);
+ SERIALIZE_SCALAR(txDesc64.link);
+ SERIALIZE_SCALAR(txDesc64.bufptr);
+ SERIALIZE_SCALAR(txDesc64.cmdsts);
+ SERIALIZE_SCALAR(txDesc64.extsts);
+ SERIALIZE_SCALAR(rxDesc32.link);
+ SERIALIZE_SCALAR(rxDesc32.bufptr);
+ SERIALIZE_SCALAR(rxDesc32.cmdsts);
+ SERIALIZE_SCALAR(rxDesc32.extsts);
+ SERIALIZE_SCALAR(txDesc32.link);
+ SERIALIZE_SCALAR(txDesc32.bufptr);
+ SERIALIZE_SCALAR(txDesc32.cmdsts);
+ SERIALIZE_SCALAR(txDesc32.extsts);
+ SERIALIZE_SCALAR(extstsEnable);
/*
* Serialize tx state machine
SERIALIZE_SCALAR(txDescCnt);
int txDmaState = this->txDmaState;
SERIALIZE_SCALAR(txDmaState);
+ SERIALIZE_SCALAR(txKickTick);
/*
* Serialize rx state machine
SERIALIZE_SCALAR(rxEnable);
SERIALIZE_SCALAR(CRDD);
SERIALIZE_SCALAR(rxPktBytes);
+ SERIALIZE_SCALAR(rxFragPtr);
SERIALIZE_SCALAR(rxDescCnt);
int rxDmaState = this->rxDmaState;
SERIALIZE_SCALAR(rxDmaState);
+ SERIALIZE_SCALAR(rxKickTick);
- SERIALIZE_SCALAR(extstsEnable);
+ /*
+ * Serialize EEPROM state machine
+ */
+ int eepromState = this->eepromState;
+ SERIALIZE_SCALAR(eepromState);
+ SERIALIZE_SCALAR(eepromClk);
+ SERIALIZE_SCALAR(eepromBitsToRx);
+ SERIALIZE_SCALAR(eepromOpcode);
+ SERIALIZE_SCALAR(eepromAddress);
+ SERIALIZE_SCALAR(eepromData);
/*
* If there's a pending transmit, store the time so we can
SERIALIZE_SCALAR(acceptUnicast);
SERIALIZE_SCALAR(acceptPerfect);
SERIALIZE_SCALAR(acceptArp);
+ SERIALIZE_SCALAR(multicastHashEnable);
/*
* Keep track of pending interrupt status.
UNSERIALIZE_SCALAR(regs.pcr);
UNSERIALIZE_SCALAR(regs.rfcr);
UNSERIALIZE_SCALAR(regs.rfdr);
+ UNSERIALIZE_SCALAR(regs.brar);
+ UNSERIALIZE_SCALAR(regs.brdr);
UNSERIALIZE_SCALAR(regs.srr);
UNSERIALIZE_SCALAR(regs.mibc);
UNSERIALIZE_SCALAR(regs.vrcr);
UNSERIALIZE_SCALAR(regs.tesr);
UNSERIALIZE_ARRAY(rom.perfectMatch, ETH_ADDR_LEN);
+ UNSERIALIZE_ARRAY(rom.filterHash, FHASH_SIZE);
UNSERIALIZE_SCALAR(ioEnable);
bool txPacketExists;
UNSERIALIZE_SCALAR(txPacketExists);
if (txPacketExists) {
- txPacket = new PacketData;
+ txPacket = new PacketData(16384);
txPacket->unserialize("txPacket", cp, section);
uint32_t txPktBufPtr;
UNSERIALIZE_SCALAR(txPktBufPtr);
UNSERIALIZE_SCALAR(rxPacketExists);
rxPacket = 0;
if (rxPacketExists) {
- rxPacket = new PacketData;
+ rxPacket = new PacketData(16384);
rxPacket->unserialize("rxPacket", cp, section);
uint32_t rxPktBufPtr;
UNSERIALIZE_SCALAR(rxPktBufPtr);
UNSERIALIZE_SCALAR(rxXferLen);
/*
- * Unserialize DescCaches
+ * Unserialize Cached Descriptors
*/
- UNSERIALIZE_SCALAR(txDescCache.link);
- UNSERIALIZE_SCALAR(txDescCache.bufptr);
- UNSERIALIZE_SCALAR(txDescCache.cmdsts);
- UNSERIALIZE_SCALAR(txDescCache.extsts);
- UNSERIALIZE_SCALAR(rxDescCache.link);
- UNSERIALIZE_SCALAR(rxDescCache.bufptr);
- UNSERIALIZE_SCALAR(rxDescCache.cmdsts);
- UNSERIALIZE_SCALAR(rxDescCache.extsts);
+ UNSERIALIZE_SCALAR(rxDesc64.link);
+ UNSERIALIZE_SCALAR(rxDesc64.bufptr);
+ UNSERIALIZE_SCALAR(rxDesc64.cmdsts);
+ UNSERIALIZE_SCALAR(rxDesc64.extsts);
+ UNSERIALIZE_SCALAR(txDesc64.link);
+ UNSERIALIZE_SCALAR(txDesc64.bufptr);
+ UNSERIALIZE_SCALAR(txDesc64.cmdsts);
+ UNSERIALIZE_SCALAR(txDesc64.extsts);
+ UNSERIALIZE_SCALAR(rxDesc32.link);
+ UNSERIALIZE_SCALAR(rxDesc32.bufptr);
+ UNSERIALIZE_SCALAR(rxDesc32.cmdsts);
+ UNSERIALIZE_SCALAR(rxDesc32.extsts);
+ UNSERIALIZE_SCALAR(txDesc32.link);
+ UNSERIALIZE_SCALAR(txDesc32.bufptr);
+ UNSERIALIZE_SCALAR(txDesc32.cmdsts);
+ UNSERIALIZE_SCALAR(txDesc32.extsts);
+ UNSERIALIZE_SCALAR(extstsEnable);
/*
* unserialize tx state machine
int txDmaState;
UNSERIALIZE_SCALAR(txDmaState);
this->txDmaState = (DmaState) txDmaState;
+ UNSERIALIZE_SCALAR(txKickTick);
+ if (txKickTick)
+ txKickEvent.schedule(txKickTick);
/*
* unserialize rx state machine
UNSERIALIZE_SCALAR(rxEnable);
UNSERIALIZE_SCALAR(CRDD);
UNSERIALIZE_SCALAR(rxPktBytes);
+ UNSERIALIZE_SCALAR(rxFragPtr);
UNSERIALIZE_SCALAR(rxDescCnt);
int rxDmaState;
UNSERIALIZE_SCALAR(rxDmaState);
this->rxDmaState = (DmaState) rxDmaState;
+ UNSERIALIZE_SCALAR(rxKickTick);
+ if (rxKickTick)
+ rxKickEvent.schedule(rxKickTick);
- UNSERIALIZE_SCALAR(extstsEnable);
+ /*
+ * Unserialize EEPROM state machine
+ */
+ int eepromState;
+ UNSERIALIZE_SCALAR(eepromState);
+ this->eepromState = (EEPROMState) eepromState;
+ UNSERIALIZE_SCALAR(eepromClk);
+ UNSERIALIZE_SCALAR(eepromBitsToRx);
+ UNSERIALIZE_SCALAR(eepromOpcode);
+ UNSERIALIZE_SCALAR(eepromAddress);
+ UNSERIALIZE_SCALAR(eepromData);
- /*
+ /*
* If there's a pending transmit, reschedule it now
*/
Tick transmitTick;
UNSERIALIZE_SCALAR(acceptUnicast);
UNSERIALIZE_SCALAR(acceptPerfect);
UNSERIALIZE_SCALAR(acceptArp);
+ UNSERIALIZE_SCALAR(multicastHashEnable);
/*
* Keep track of pending interrupt status.
BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigE)
- Param<Tick> tx_delay;
- Param<Tick> rx_delay;
- Param<Tick> intr_delay;
+ Param<Tick> clock;
+
+ Param<Addr> addr;
SimObjectParam<MemoryController *> mmu;
SimObjectParam<PhysicalMemory *> physmem;
- Param<bool> rx_filter;
- Param<string> hardware_address;
- SimObjectParam<Bus*> header_bus;
- SimObjectParam<Bus*> payload_bus;
+ SimObjectParam<PciConfigAll *> configspace;
+ SimObjectParam<PciConfigData *> configdata;
+ SimObjectParam<Platform *> platform;
+ Param<uint32_t> pci_bus;
+ Param<uint32_t> pci_dev;
+ Param<uint32_t> pci_func;
+
SimObjectParam<HierParams *> hier;
- Param<Tick> pio_latency;
+ SimObjectParam<Bus*> io_bus;
+ SimObjectParam<Bus*> payload_bus;
Param<bool> dma_desc_free;
Param<bool> dma_data_free;
Param<Tick> dma_read_delay;
Param<Tick> dma_write_delay;
Param<Tick> dma_read_factor;
Param<Tick> dma_write_factor;
- SimObjectParam<PciConfigAll *> configspace;
- SimObjectParam<PciConfigData *> configdata;
- SimObjectParam<Platform *> platform;
- Param<uint32_t> pci_bus;
- Param<uint32_t> pci_dev;
- Param<uint32_t> pci_func;
- Param<uint32_t> tx_fifo_size;
+ Param<bool> dma_no_allocate;
+ Param<Tick> pio_latency;
+ Param<Tick> intr_delay;
+
+ Param<Tick> rx_delay;
+ Param<Tick> tx_delay;
Param<uint32_t> rx_fifo_size;
+ Param<uint32_t> tx_fifo_size;
+
+ Param<bool> rx_filter;
+ Param<string> hardware_address;
+ Param<bool> dedicated;
END_DECLARE_SIM_OBJECT_PARAMS(NSGigE)
BEGIN_INIT_SIM_OBJECT_PARAMS(NSGigE)
- INIT_PARAM_DFLT(tx_delay, "Transmit Delay", 1000),
- INIT_PARAM_DFLT(rx_delay, "Receive Delay", 1000),
- INIT_PARAM_DFLT(intr_delay, "Interrupt Delay in microseconds", 0),
+ INIT_PARAM(clock, "State machine processor frequency"),
+
+ INIT_PARAM(addr, "Device Address"),
INIT_PARAM(mmu, "Memory Controller"),
INIT_PARAM(physmem, "Physical Memory"),
- INIT_PARAM_DFLT(rx_filter, "Enable Receive Filter", true),
- INIT_PARAM_DFLT(hardware_address, "Ethernet Hardware Address",
- "00:99:00:00:00:01"),
- INIT_PARAM_DFLT(header_bus, "The IO Bus to attach to for headers", NULL),
- INIT_PARAM_DFLT(payload_bus, "The IO Bus to attach to for payload", NULL),
- INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams),
- INIT_PARAM_DFLT(pio_latency, "Programmed IO latency in bus cycles", 1),
- INIT_PARAM_DFLT(dma_desc_free, "DMA of Descriptors is free", false),
- INIT_PARAM_DFLT(dma_data_free, "DMA of Data is free", false),
- INIT_PARAM_DFLT(dma_read_delay, "fixed delay for dma reads", 0),
- INIT_PARAM_DFLT(dma_write_delay, "fixed delay for dma writes", 0),
- INIT_PARAM_DFLT(dma_read_factor, "multiplier for dma reads", 0),
- INIT_PARAM_DFLT(dma_write_factor, "multiplier for dma writes", 0),
INIT_PARAM(configspace, "PCI Configspace"),
INIT_PARAM(configdata, "PCI Config data"),
INIT_PARAM(platform, "Platform"),
INIT_PARAM(pci_bus, "PCI bus"),
INIT_PARAM(pci_dev, "PCI device number"),
INIT_PARAM(pci_func, "PCI function code"),
- INIT_PARAM_DFLT(tx_fifo_size, "max size in bytes of txFifo", 131072),
- INIT_PARAM_DFLT(rx_fifo_size, "max size in bytes of rxFifo", 131072)
+
+ INIT_PARAM(hier, "Hierarchy global variables"),
+ INIT_PARAM(io_bus, "The IO Bus to attach to for headers"),
+ INIT_PARAM(payload_bus, "The IO Bus to attach to for payload"),
+ INIT_PARAM(dma_desc_free, "DMA of Descriptors is free"),
+ INIT_PARAM(dma_data_free, "DMA of Data is free"),
+ INIT_PARAM(dma_read_delay, "fixed delay for dma reads"),
+ INIT_PARAM(dma_write_delay, "fixed delay for dma writes"),
+ INIT_PARAM(dma_read_factor, "multiplier for dma reads"),
+ INIT_PARAM(dma_write_factor, "multiplier for dma writes"),
+ INIT_PARAM(dma_no_allocate, "Should DMA reads allocate cache lines"),
+ INIT_PARAM(pio_latency, "Programmed IO latency in bus cycles"),
+ INIT_PARAM(intr_delay, "Interrupt Delay in microseconds"),
+
+ INIT_PARAM(rx_delay, "Receive Delay"),
+ INIT_PARAM(tx_delay, "Transmit Delay"),
+ INIT_PARAM(rx_fifo_size, "max size in bytes of rxFifo"),
+ INIT_PARAM(tx_fifo_size, "max size in bytes of txFifo"),
+
+ INIT_PARAM(rx_filter, "Enable Receive Filter"),
+ INIT_PARAM(hardware_address, "Ethernet Hardware Address"),
+ INIT_PARAM(dedicated, "dedicate a kernel thread to the driver")
END_INIT_SIM_OBJECT_PARAMS(NSGigE)
NSGigE::Params *params = new NSGigE::Params;
params->name = getInstanceName();
+
+ params->clock = clock;
+
params->mmu = mmu;
+ params->pmem = physmem;
params->configSpace = configspace;
params->configData = configdata;
params->plat = platform;
params->deviceNum = pci_dev;
params->functionNum = pci_func;
- params->intr_delay = intr_delay;
- params->pmem = physmem;
- params->tx_delay = tx_delay;
- params->rx_delay = rx_delay;
params->hier = hier;
- params->header_bus = header_bus;
+ params->header_bus = io_bus;
params->payload_bus = payload_bus;
- params->pio_latency = pio_latency;
params->dma_desc_free = dma_desc_free;
params->dma_data_free = dma_data_free;
params->dma_read_delay = dma_read_delay;
params->dma_write_delay = dma_write_delay;
params->dma_read_factor = dma_read_factor;
params->dma_write_factor = dma_write_factor;
+ params->dma_no_allocate = dma_no_allocate;
+ params->pio_latency = pio_latency;
+ params->intr_delay = intr_delay;
+
+ params->rx_delay = rx_delay;
+ params->tx_delay = tx_delay;
+ params->rx_fifo_size = rx_fifo_size;
+ params->tx_fifo_size = tx_fifo_size;
+
params->rx_filter = rx_filter;
params->eaddr = hardware_address;
- params->tx_fifo_size = tx_fifo_size;
- params->rx_fifo_size = rx_fifo_size;
+ params->dedicated = dedicated;
+
return new NSGigE(params);
}