Merge zizzer:/bk/m5

into  zeep.eecs.umich.edu:/z/saidi/work/m5

--HG--
extra : convert_revision : 3cc23080d19cc464a8ba7c1c93b6e5d45af7d463
This commit is contained in:
Ali Saidi
2005-11-02 14:56:18 -05:00
19 changed files with 936 additions and 845 deletions

View File

@@ -127,7 +127,7 @@ NSGigE::NSGigE(Params *p)
p->header_bus, 1,
p->dma_no_allocate);
} else if (p->payload_bus) {
pioInterface = newPioInterface(name() + ".pio2", p->hier,
pioInterface = newPioInterface(name() + ".pio", p->hier,
p->payload_bus, this,
&NSGigE::cacheAccess);
@@ -2531,20 +2531,17 @@ NSGigE::recvPacket(PacketPtr packet)
if (!rxEnable) {
DPRINTF(Ethernet, "receive disabled...packet dropped\n");
interface->recvDone();
return true;
}
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;
}
@@ -2567,7 +2564,6 @@ NSGigE::recvPacket(PacketPtr packet)
}
rxFifo.push(packet);
interface->recvDone();
rxKick();
return true;

View File

@@ -94,8 +94,8 @@ Device::Device(Params *p)
reset();
if (p->io_bus) {
pioInterface = newPioInterface(p->name, p->hier, p->io_bus, this,
&Device::cacheAccess);
pioInterface = newPioInterface(p->name + ".pio", p->hier, p->io_bus,
this, &Device::cacheAccess);
pioLatency = p->pio_latency * p->io_bus->clockRate;
@@ -108,7 +108,8 @@ Device::Device(Params *p)
p->io_bus, 1,
p->dma_no_allocate);
} else if (p->payload_bus) {
pioInterface = newPioInterface(p->name, p->hier, p->payload_bus, this,
pioInterface = newPioInterface(p->name + ".pio", p->hier,
p->payload_bus, this,
&Device::cacheAccess);
pioLatency = p->pio_latency * p->payload_bus->clockRate;
@@ -315,9 +316,26 @@ Device::writeConfig(int offset, int size, const uint8_t *data)
}
}
void
Device::prepareRead()
{
using namespace Regs;
// update rx registers
regs.RxDone = set_RxDone_Packets(regs.RxDone, rxFifo.packets());
regs.RxWait = regs.RxDone;
// update tx regsiters
regs.TxDone = set_TxDone_Packets(regs.TxDone, txFifo.packets());
regs.TxDone = set_TxDone_Full(regs.TxDone,
txFifo.avail() < regs.TxMaxCopy);
regs.TxDone = set_TxDone_Low(regs.TxDone,
txFifo.size() < regs.TxFifoMark);
regs.TxWait = regs.TxDone;
}
/**
* This reads the device registers, which are detailed in the NS83820
* spec sheet
* I/O read of device register
*/
Fault
Device::read(MemReqPtr &req, uint8_t *data)
@@ -327,118 +345,115 @@ Device::read(MemReqPtr &req, uint8_t *data)
//The mask is to give you only the offset into the device register file
Addr daddr = req->paddr & 0xfff;
if (Regs::regSize(daddr) == 0)
panic("invalid address: da=%#x pa=%#x va=%#x size=%d",
if (!regValid(daddr))
panic("invalid register: da=%#x pa=%#x va=%#x size=%d",
daddr, req->paddr, req->vaddr, req->size);
if (req->size != Regs::regSize(daddr))
const Regs::Info &info = regInfo(daddr);
if (!info.read)
panic("reading write only register: %s: da=%#x pa=%#x va=%#x size=%d",
info.name, daddr, req->paddr, req->vaddr, req->size);
if (req->size != info.size)
panic("invalid size for reg %s: da=%#x pa=%#x va=%#x size=%d",
Regs::regName(daddr), daddr, req->paddr, req->vaddr, req->size);
info.name, daddr, req->paddr, req->vaddr, req->size);
DPRINTF(EthernetPIO, "read reg=%s da=%#x pa=%#x va=%#x size=%d\n",
Regs::regName(daddr), daddr, req->paddr, req->vaddr, req->size);
prepareRead();
uint32_t &reg32 = *(uint32_t *)data;
uint64_t &reg64 = *(uint64_t *)data;
switch (daddr) {
case Regs::Config:
reg32 = regs.Config;
break;
case Regs::RxMaxCopy:
reg32 = regs.RxMaxCopy;
break;
case Regs::TxMaxCopy:
reg32 = regs.TxMaxCopy;
break;
case Regs::RxThreshold:
reg32 = regs.RxThreshold;
break;
case Regs::TxThreshold:
reg32 = regs.TxThreshold;
break;
case Regs::IntrStatus:
reg32 = regs.IntrStatus;
devIntrClear();
break;
case Regs::IntrMask:
reg32 = regs.IntrMask;
break;
case Regs::RxData:
reg64 = regs.RxData;
break;
case Regs::RxDone:
case Regs::RxWait:
reg64 = Regs::set_RxDone_FifoLen(regs.RxDone,
min(rxFifo.packets(), 255));
break;
case Regs::TxData:
reg64 = regs.TxData;
break;
case Regs::TxDone:
case Regs::TxWait:
reg64 = Regs::set_TxDone_FifoLen(regs.TxDone,
min(txFifo.packets(), 255));
break;
case Regs::HwAddr:
reg64 = params()->eaddr;
break;
default:
panic("reading write only register %s: da=%#x pa=%#x va=%#x size=%d",
Regs::regName(daddr), daddr, req->paddr, req->vaddr, req->size);
uint64_t value = 0;
if (req->size == 4) {
uint32_t &reg = *(uint32_t *)data;
reg = regData32(daddr);
value = reg;
}
DPRINTF(EthernetPIO, "read reg=%s done val=%#x\n", Regs::regName(daddr),
Regs::regSize(daddr) == 4 ? reg32 : reg64);
if (req->size == 8) {
uint64_t &reg = *(uint64_t *)data;
reg = regData64(daddr);
value = reg;
}
DPRINTF(EthernetPIO, "read reg=%s da=%#x pa=%#x va=%#x size=%d val=%#x\n",
info.name, daddr, req->paddr, req->vaddr, req->size, value);
// reading the interrupt status register has the side effect of
// clearing it
if (daddr == Regs::IntrStatus)
devIntrClear();
return No_Fault;
}
/**
* IPR read of device register
*/
Fault
Device::iprRead(Addr daddr, uint64_t &result)
{
if (!regValid(daddr))
panic("invalid address: da=%#x", daddr);
const Regs::Info &info = regInfo(daddr);
if (!info.read)
panic("reading write only register %s: da=%#x", info.name, daddr);
DPRINTF(EthernetPIO, "read reg=%s da=%#x\n", info.name, daddr);
prepareRead();
if (info.size == 4)
result = regData32(daddr);
if (info.size == 8)
result = regData64(daddr);
DPRINTF(EthernetPIO, "IPR read reg=%s da=%#x val=%#x\n",
info.name, result);
return No_Fault;
}
/**
* I/O write of device register
*/
Fault
Device::write(MemReqPtr &req, const uint8_t *data)
{
assert(config.command & PCI_CMD_MSE);
//The mask is to give you only the offset into the device register file
Addr daddr = req->paddr & 0xfff;
if (Regs::regSize(daddr) == 0)
if (!regValid(daddr))
panic("invalid address: da=%#x pa=%#x va=%#x size=%d",
daddr, req->paddr, req->vaddr, req->size);
if (req->size != Regs::regSize(daddr))
panic("invalid size: reg=%s da=%#x pa=%#x va=%#x size=%d",
Regs::regName(daddr), daddr, req->paddr, req->vaddr, req->size);
const Regs::Info &info = regInfo(daddr);
if (!info.write)
panic("writing read only register %s: da=%#x", info.name, daddr);
if (req->size != info.size)
panic("invalid size for reg %s: da=%#x pa=%#x va=%#x size=%d",
info.name, daddr, req->paddr, req->vaddr, req->size);
uint32_t reg32 = *(uint32_t *)data;
uint64_t reg64 = *(uint64_t *)data;
DPRINTF(EthernetPIO, "write reg=%s val=%#x da=%#x pa=%#x va=%#x size=%d\n",
Regs::regName(daddr), Regs::regSize(daddr) == 4 ? reg32 : reg64,
daddr, req->paddr, req->vaddr, req->size);
info.name, info.size == 4 ? reg32 : reg64, daddr, req->paddr,
req->vaddr, req->size);
switch (daddr) {
case Regs::Config:
changeConfig(reg32);
break;
case Regs::RxThreshold:
regs.RxThreshold = reg32;
case Regs::Command:
command(reg32);
break;
case Regs::TxThreshold:
regs.TxThreshold = reg32;
case Regs::IntrStatus:
devIntrClear(regs.IntrStatus & reg32);
break;
case Regs::IntrMask:
@@ -447,9 +462,10 @@ Device::write(MemReqPtr &req, const uint8_t *data)
case Regs::RxData:
if (rxState != rxIdle)
panic("receive machine busy with another request!");
panic("receive machine busy with another request! rxState=%s",
RxStateStrings[rxState]);
regs.RxDone = 0;
regs.RxDone = Regs::RxDone_Busy;
regs.RxData = reg64;
if (rxEnable) {
rxState = rxFifoBlock;
@@ -459,19 +475,16 @@ Device::write(MemReqPtr &req, const uint8_t *data)
case Regs::TxData:
if (txState != txIdle)
panic("transmit machine busy with another request!");
panic("transmit machine busy with another request! txState=%s",
TxStateStrings[txState]);
regs.TxDone = 0;
regs.TxDone = Regs::TxDone_Busy;
regs.TxData = reg64;
if (txEnable) {
txState = txFifoBlock;
txKick();
}
break;
default:
panic("writing read only register %s: da=%#x pa=%#x va=%#x size=%d",
Regs::regName(daddr), daddr, req->paddr, req->vaddr, req->size);
}
return No_Fault;
@@ -489,9 +502,25 @@ Device::devIntrPost(uint32_t interrupts)
"interrupt written to intStatus: intr=%#x status=%#x mask=%#x\n",
interrupts, regs.IntrStatus, regs.IntrMask);
if ((regs.IntrStatus & regs.IntrMask)) {
interrupts = regs.IntrStatus & regs.IntrMask;
// Intr_RxHigh is special, we only signal it if we've emptied the fifo
// and then filled it above the high watermark
if (rxEmpty)
rxEmpty = false;
else
interrupts &= ~Regs::Intr_RxHigh;
// Intr_TxLow is special, we only signal it if we've filled up the fifo
// and then dropped below the low watermark
if (txFull)
txFull = false;
else
interrupts &= ~Regs::Intr_TxLow;
if (interrupts) {
Tick when = curTick;
if ((regs.IntrStatus & regs.IntrMask & Regs::Intr_NoDelay) == 0)
if ((interrupts & Regs::Intr_NoDelay) == 0)
when += intrDelay;
cpuIntrPost(when);
}
@@ -627,12 +656,6 @@ Device::changeConfig(uint32_t newconf)
regs.Config = newconf;
if ((changed & Regs::Config_Reset)) {
assert(regs.Config & Regs::Config_Reset);
reset();
regs.Config &= ~Regs::Config_Reset;
}
if ((changed & Regs::Config_IntEn)) {
cpuIntrEnable = regs.Config & Regs::Config_IntEn;
if (cpuIntrEnable) {
@@ -656,20 +679,40 @@ Device::changeConfig(uint32_t newconf)
}
}
void
Device::command(uint32_t command)
{
if (command & Regs::Command_Reset)
reset();
}
void
Device::reset()
{
using namespace Regs;
memset(&regs, 0, sizeof(regs));
regs.Config = 0;
if (params()->dedicated)
regs.Config |= Config_Thread;
regs.IntrMask = Intr_RxHigh | Intr_RxDMA | Intr_TxLow;
regs.RxMaxCopy = params()->rx_max_copy;
regs.TxMaxCopy = params()->tx_max_copy;
regs.IntrMask = Intr_TxFifo | Intr_RxFifo | Intr_RxData;
regs.RxMaxIntr = params()->rx_max_intr;
regs.RxFifoSize = params()->rx_fifo_size;
regs.TxFifoSize = params()->tx_fifo_size;
regs.RxFifoMark = params()->rx_fifo_threshold;
regs.TxFifoMark = params()->tx_fifo_threshold;
regs.HwAddr = params()->eaddr;
rxState = rxIdle;
txState = txIdle;
rxFifo.clear();
txFifo.clear();
rxEmpty = false;
txFull = false;
}
void
@@ -680,13 +723,18 @@ Device::rxDmaCopy()
physmem->dma_write(rxDmaAddr, (uint8_t *)rxDmaData, rxDmaLen);
DPRINTF(EthernetDMA, "rx dma write paddr=%#x len=%d\n",
rxDmaAddr, rxDmaLen);
DDUMP(EthernetDMA, rxDmaData, rxDmaLen);
DDUMP(EthernetData, rxDmaData, rxDmaLen);
}
void
Device::rxDmaDone()
{
rxDmaCopy();
// If the transmit state machine has a pending DMA, let it go first
if (txState == txBeginCopy)
txKick();
rxKick();
}
@@ -706,6 +754,8 @@ Device::rxKick()
switch (rxState) {
case rxIdle:
if (rxPioRequest) {
DPRINTF(EthernetPIO, "rxIdle: PIO waiting responding at %d\n",
curTick + pioLatency);
pioInterface->respond(rxPioRequest, curTick);
rxPioRequest = 0;
}
@@ -761,20 +811,20 @@ Device::rxKick()
break;
case rxBeginCopy:
if (dmaInterface && dmaInterface->busy())
goto exit;
rxDmaAddr = plat->pciToDma(Regs::get_RxData_Addr(regs.RxData));
rxDmaLen = min<int>(Regs::get_RxData_Len(regs.RxData), rxPktBytes);
rxDmaData = rxPacketBufPtr;
rxState = rxCopy;
if (dmaInterface) {
if (!dmaInterface->busy()) {
dmaInterface->doDMA(WriteInvalidate, rxDmaAddr, rxDmaLen,
curTick, &rxDmaEvent, true);
rxState = rxCopy;
}
dmaInterface->doDMA(WriteInvalidate, rxDmaAddr, rxDmaLen,
curTick, &rxDmaEvent, true);
goto exit;
}
rxState = rxCopy;
if (dmaWriteDelay != 0 || dmaWriteFactor != 0) {
Tick factor = ((rxDmaLen + ULL(63)) >> ULL(6)) * dmaWriteFactor;
Tick start = curTick + dmaWriteDelay + factor;
@@ -802,7 +852,7 @@ Device::rxKick()
}
regs.RxDone |= Regs::RxDone_Complete;
devIntrPost(Regs::Intr_RxData);
devIntrPost(Regs::Intr_RxDMA);
rxState = rxIdle;
break;
@@ -831,13 +881,18 @@ Device::txDmaCopy()
physmem->dma_read((uint8_t *)txDmaData, txDmaAddr, txDmaLen);
DPRINTF(EthernetDMA, "tx dma read paddr=%#x len=%d\n",
txDmaAddr, txDmaLen);
DDUMP(EthernetDMA, txDmaData, txDmaLen);
DDUMP(EthernetData, txDmaData, txDmaLen);
}
void
Device::txDmaDone()
{
txDmaCopy();
// If the receive state machine has a pending DMA, let it go first
if (rxState == rxBeginCopy)
rxKick();
txKick();
}
@@ -849,6 +904,7 @@ Device::transmit()
return;
}
uint32_t interrupts;
PacketPtr packet = txFifo.front();
if (!interface->sendPacket(packet)) {
DPRINTF(Ethernet, "Packet Transmit: failed txFifo available %d\n",
@@ -857,7 +913,6 @@ Device::transmit()
}
txFifo.pop();
#if TRACING_ON
if (DTRACE(Ethernet)) {
IpPtr ip(packet);
@@ -872,17 +927,17 @@ Device::transmit()
}
#endif
DDUMP(Ethernet, packet->data, packet->length);
DDUMP(EthernetData, packet->data, packet->length);
txBytes += packet->length;
txPackets++;
DPRINTF(Ethernet, "Packet Transmit: successful txFifo Available %d\n",
txFifo.avail());
if (txFifo.size() <= params()->tx_fifo_threshold)
devIntrPost(Regs::Intr_TxFifo);
devIntrPost(Regs::Intr_TxDone);
interrupts = Regs::Intr_TxPacket;
if (txFifo.size() < regs.TxFifoMark)
interrupts |= Regs::Intr_TxLow;
devIntrPost(interrupts);
reschedule:
if (!txFifo.empty() && !txEvent.scheduled()) {
@@ -907,6 +962,8 @@ Device::txKick()
switch (txState) {
case txIdle:
if (txPioRequest) {
DPRINTF(EthernetPIO, "txIdle: PIO waiting responding at %d\n",
curTick + pioLatency);
pioInterface->respond(txPioRequest, curTick + pioLatency);
txPioRequest = 0;
}
@@ -929,21 +986,20 @@ Device::txKick()
break;
case txBeginCopy:
if (dmaInterface && dmaInterface->busy())
goto exit;
txDmaAddr = plat->pciToDma(Regs::get_TxData_Addr(regs.TxData));
txDmaLen = Regs::get_TxData_Len(regs.TxData);
txDmaData = txPacketBufPtr;
txState = txCopy;
if (dmaInterface) {
if (!dmaInterface->busy()) {
dmaInterface->doDMA(Read, txDmaAddr, txDmaLen,
curTick, &txDmaEvent, true);
txState = txCopy;
}
dmaInterface->doDMA(Read, txDmaAddr, txDmaLen,
curTick, &txDmaEvent, true);
goto exit;
}
txState = txCopy;
if (dmaReadDelay != 0 || dmaReadFactor != 0) {
Tick factor = ((txDmaLen + ULL(63)) >> ULL(6)) * dmaReadFactor;
Tick start = curTick + dmaReadDelay + factor;
@@ -987,12 +1043,16 @@ Device::txKick()
}
}
txFifo.push(txPacket);
if (txFifo.avail() < regs.TxMaxCopy) {
devIntrPost(Regs::Intr_TxFull);
txFull = true;
}
txPacket = 0;
transmit();
}
regs.TxDone = txDmaLen | Regs::TxDone_Complete;
devIntrPost(Regs::Intr_TxData);
devIntrPost(Regs::Intr_TxDMA);
txState = txIdle;
break;
@@ -1085,18 +1145,16 @@ Device::recvPacket(PacketPtr packet)
if (!rxEnable) {
DPRINTF(Ethernet, "receive disabled...packet dropped\n");
interface->recvDone();
return true;
}
if (rxFilter(packet)) {
DPRINTF(Ethernet, "packet filtered...dropped\n");
interface->recvDone();
return true;
}
if (rxFifo.size() >= params()->rx_fifo_threshold)
devIntrPost(Regs::Intr_RxFifo);
if (rxFifo.size() >= regs.RxFifoMark)
devIntrPost(Regs::Intr_RxHigh);
if (!rxFifo.push(packet)) {
DPRINTF(Ethernet,
@@ -1104,8 +1162,7 @@ Device::recvPacket(PacketPtr packet)
return false;
}
interface->recvDone();
devIntrPost(Regs::Intr_RxDone);
devIntrPost(Regs::Intr_RxPacket);
rxKick();
return true;
}
@@ -1163,22 +1220,23 @@ Device::serialize(ostream &os)
// Serialize the PciDev base class
Base::serialize(os);
if (rxDmaEvent.scheduled())
rxDmaCopy();
if (rxState == rxCopy)
panic("can't serialize with an in flight dma request rxState=%s",
RxStateStrings[rxState]);
if (txDmaEvent.scheduled())
txDmaCopy();
if (txState == txCopy)
panic("can't serialize with an in flight dma request txState=%s",
TxStateStrings[txState]);
/*
* Serialize the device registers
*/
SERIALIZE_SCALAR(regs.Config);
SERIALIZE_SCALAR(regs.RxMaxCopy);
SERIALIZE_SCALAR(regs.TxMaxCopy);
SERIALIZE_SCALAR(regs.RxThreshold);
SERIALIZE_SCALAR(regs.TxThreshold);
SERIALIZE_SCALAR(regs.IntrStatus);
SERIALIZE_SCALAR(regs.IntrMask);
SERIALIZE_SCALAR(regs.RxMaxCopy);
SERIALIZE_SCALAR(regs.TxMaxCopy);
SERIALIZE_SCALAR(regs.RxMaxIntr);
SERIALIZE_SCALAR(regs.RxData);
SERIALIZE_SCALAR(regs.RxDone);
SERIALIZE_SCALAR(regs.TxData);
@@ -1189,6 +1247,7 @@ Device::serialize(ostream &os)
*/
int rxState = this->rxState;
SERIALIZE_SCALAR(rxState);
SERIALIZE_SCALAR(rxEmpty);
rxFifo.serialize("rxFifo", os);
bool rxPacketExists = rxPacket;
SERIALIZE_SCALAR(rxPacketExists);
@@ -1205,6 +1264,7 @@ Device::serialize(ostream &os)
*/
int txState = this->txState;
SERIALIZE_SCALAR(txState);
SERIALIZE_SCALAR(txFull);
txFifo.serialize("txFifo", os);
bool txPacketExists = txPacket;
SERIALIZE_SCALAR(txPacketExists);
@@ -1233,12 +1293,11 @@ Device::unserialize(Checkpoint *cp, const std::string &section)
* Unserialize the device registers
*/
UNSERIALIZE_SCALAR(regs.Config);
UNSERIALIZE_SCALAR(regs.RxMaxCopy);
UNSERIALIZE_SCALAR(regs.TxMaxCopy);
UNSERIALIZE_SCALAR(regs.RxThreshold);
UNSERIALIZE_SCALAR(regs.TxThreshold);
UNSERIALIZE_SCALAR(regs.IntrStatus);
UNSERIALIZE_SCALAR(regs.IntrMask);
UNSERIALIZE_SCALAR(regs.RxMaxCopy);
UNSERIALIZE_SCALAR(regs.TxMaxCopy);
UNSERIALIZE_SCALAR(regs.RxMaxIntr);
UNSERIALIZE_SCALAR(regs.RxData);
UNSERIALIZE_SCALAR(regs.RxDone);
UNSERIALIZE_SCALAR(regs.TxData);
@@ -1249,6 +1308,7 @@ Device::unserialize(Checkpoint *cp, const std::string &section)
*/
int rxState;
UNSERIALIZE_SCALAR(rxState);
UNSERIALIZE_SCALAR(rxEmpty);
this->rxState = (RxState) rxState;
rxFifo.unserialize("rxFifo", cp, section);
bool rxPacketExists;
@@ -1269,6 +1329,7 @@ Device::unserialize(Checkpoint *cp, const std::string &section)
*/
int txState;
UNSERIALIZE_SCALAR(txState);
UNSERIALIZE_SCALAR(txFull);
this->txState = (TxState) txState;
txFifo.unserialize("txFifo", cp, section);
bool txPacketExists;
@@ -1310,15 +1371,19 @@ Device::cacheAccess(MemReqPtr &req)
Tick when = curTick + pioLatency;
switch (daddr) {
case Regs::RxDone:
case Regs::RxWait:
if (rxState != rxIdle) {
DPRINTF(EthernetPIO, "rxState=%s (not idle)... waiting\n",
TxStateStrings[txState]);
rxPioRequest = req;
when = 0;
}
break;
case Regs::TxDone:
case Regs::TxWait:
if (txState != txIdle) {
DPRINTF(EthernetPIO, "txState=%s (not idle)... waiting\n",
TxStateStrings[txState]);
txPioRequest = req;
when = 0;
}
@@ -1387,6 +1452,7 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(Device)
Param<Tick> tx_delay;
Param<uint32_t> rx_max_copy;
Param<uint32_t> tx_max_copy;
Param<uint32_t> rx_max_intr;
Param<uint32_t> rx_fifo_size;
Param<uint32_t> tx_fifo_size;
Param<uint32_t> rx_fifo_threshold;
@@ -1394,6 +1460,7 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(Device)
Param<bool> rx_filter;
Param<string> hardware_address;
Param<bool> dedicated;
END_DECLARE_SIM_OBJECT_PARAMS(Device)
@@ -1426,13 +1493,15 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(Device)
INIT_PARAM(tx_delay, "Transmit Delay"),
INIT_PARAM(rx_max_copy, "rx max copy"),
INIT_PARAM(tx_max_copy, "rx max copy"),
INIT_PARAM(rx_max_intr, "rx max intr"),
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_fifo_threshold, "max size in bytes of rxFifo"),
INIT_PARAM(tx_fifo_threshold, "max size in bytes of txFifo"),
INIT_PARAM(rx_filter, "Enable Receive Filter"),
INIT_PARAM(hardware_address, "Ethernet Hardware Address")
INIT_PARAM(hardware_address, "Ethernet Hardware Address"),
INIT_PARAM(dedicated, "dedicate a kernel thread to the driver")
END_INIT_SIM_OBJECT_PARAMS(Device)
@@ -1444,6 +1513,7 @@ CREATE_SIM_OBJECT(Device)
params->name = getInstanceName();
params->clock = clock;
params->mmu = mmu;
params->physmem = physmem;
params->configSpace = configspace;
@@ -1468,6 +1538,7 @@ CREATE_SIM_OBJECT(Device)
params->rx_delay = rx_delay;
params->rx_max_copy = rx_max_copy;
params->tx_max_copy = tx_max_copy;
params->rx_max_intr = rx_max_intr;
params->rx_fifo_size = rx_fifo_size;
params->tx_fifo_size = tx_fifo_size;
params->rx_fifo_threshold = rx_fifo_threshold;
@@ -1475,6 +1546,7 @@ CREATE_SIM_OBJECT(Device)
params->rx_filter = rx_filter;
params->eaddr = hardware_address;
params->dedicated = dedicated;
return new Device(params);
}

View File

@@ -115,19 +115,31 @@ class Device : public Base
/** device register file */
struct {
uint32_t Config;
uint32_t RxMaxCopy;
uint32_t TxMaxCopy;
uint32_t RxThreshold;
uint32_t TxThreshold;
uint32_t IntrStatus;
uint32_t IntrMask;
uint64_t RxData;
uint64_t RxDone;
uint64_t TxData;
uint64_t TxDone;
uint32_t Config; // 0x00
uint32_t Command; // 0x04
uint32_t IntrStatus; // 0x08
uint32_t IntrMask; // 0x0c
uint32_t RxMaxCopy; // 0x10
uint32_t TxMaxCopy; // 0x14
uint32_t RxMaxIntr; // 0x18
uint32_t Reserved0; // 0x1c
uint32_t RxFifoSize; // 0x20
uint32_t TxFifoSize; // 0x24
uint32_t RxFifoMark; // 0x28
uint32_t TxFifoMark; // 0x2c
uint64_t RxData; // 0x30
uint64_t RxDone; // 0x38
uint64_t RxWait; // 0x40
uint64_t TxData; // 0x48
uint64_t TxDone; // 0x50
uint64_t TxWait; // 0x58
uint64_t HwAddr; // 0x60
} regs;
uint8_t &regData8(Addr daddr) { return *((uint8_t *)&regs + daddr); }
uint32_t &regData32(Addr daddr) { return *(uint32_t *)&regData8(daddr); }
uint64_t &regData64(Addr daddr) { return *(uint64_t *)&regData8(daddr); }
private:
Addr addr;
static const Addr size = Regs::Size;
@@ -135,6 +147,7 @@ class Device : public Base
protected:
RxState rxState;
PacketFifo rxFifo;
bool rxEmpty;
PacketPtr rxPacket;
uint8_t *rxPacketBufPtr;
int rxPktBytes;
@@ -145,6 +158,7 @@ class Device : public Base
TxState txState;
PacketFifo txFifo;
bool txFull;
PacketPtr txPacket;
uint8_t *txPacketBufPtr;
int txPktBytes;
@@ -191,6 +205,7 @@ class Device : public Base
* device configuration
*/
void changeConfig(uint32_t newconfig);
void command(uint32_t command);
/**
* device ethernet interface
@@ -212,7 +227,7 @@ class Device : public Base
void txDmaCopy();
void txDmaDone();
friend class EventWrapper<Device, &Device::txDmaDone>;
EventWrapper<Device, &Device::rxDmaDone> txDmaEvent;
EventWrapper<Device, &Device::txDmaDone> txDmaEvent;
Tick dmaReadDelay;
Tick dmaReadFactor;
@@ -244,6 +259,8 @@ class Device : public Base
* Memory Interface
*/
public:
void prepareRead();
Fault iprRead(Addr daddr, uint64_t &result);
virtual Fault read(MemReqPtr &req, uint8_t *data);
virtual Fault write(MemReqPtr &req, const uint8_t *data);
Tick cacheAccess(MemReqPtr &req);
@@ -308,6 +325,7 @@ class Device : public Base
Net::EthAddr eaddr;
uint32_t rx_max_copy;
uint32_t tx_max_copy;
uint32_t rx_max_intr;
uint32_t rx_fifo_size;
uint32_t tx_fifo_size;
uint32_t rx_fifo_threshold;
@@ -317,6 +335,7 @@ class Device : public Base
Tick dma_write_delay;
Tick dma_write_factor;
bool dma_no_allocate;
bool dedicated;
};
protected:

View File

@@ -57,23 +57,28 @@ namespace Regs {
// Registers
__SINIC_REG32(Config, 0x00); // 32: configuration register
__SINIC_REG32(RxMaxCopy, 0x04); // 32: max rx copy
__SINIC_REG32(TxMaxCopy, 0x08); // 32: max tx copy
__SINIC_REG32(RxThreshold, 0x0c); // 32: receive fifo threshold
__SINIC_REG32(TxThreshold, 0x10); // 32: transmit fifo threshold
__SINIC_REG32(IntrStatus, 0x14); // 32: interrupt status
__SINIC_REG32(IntrMask, 0x18); // 32: interrupt mask
__SINIC_REG32(RxData, 0x20); // 64: receive data
__SINIC_REG32(RxDone, 0x28); // 64: receive done
__SINIC_REG32(RxWait, 0x30); // 64: receive done (busy wait)
__SINIC_REG32(TxData, 0x38); // 64: transmit data
__SINIC_REG32(TxDone, 0x40); // 64: transmit done
__SINIC_REG32(TxWait, 0x48); // 64: transmit done (busy wait)
__SINIC_REG32(HwAddr, 0x50); // 64: mac address
__SINIC_REG32(Size, 0x58);
__SINIC_REG32(Command, 0x04); // 32: command register
__SINIC_REG32(IntrStatus, 0x08); // 32: interrupt status
__SINIC_REG32(IntrMask, 0x0c); // 32: interrupt mask
__SINIC_REG32(RxMaxCopy, 0x10); // 32: max bytes per rx copy
__SINIC_REG32(TxMaxCopy, 0x14); // 32: max bytes per tx copy
__SINIC_REG32(RxMaxIntr, 0x18); // 32: max receives per interrupt
__SINIC_REG32(Reserved0, 0x1c); // 32: reserved
__SINIC_REG32(RxFifoSize, 0x20); // 32: rx fifo capacity in bytes
__SINIC_REG32(TxFifoSize, 0x24); // 32: tx fifo capacity in bytes
__SINIC_REG32(RxFifoMark, 0x28); // 32: rx fifo high watermark
__SINIC_REG32(TxFifoMark, 0x2c); // 32: tx fifo low watermark
__SINIC_REG32(RxData, 0x30); // 64: receive data
__SINIC_REG32(RxDone, 0x38); // 64: receive done
__SINIC_REG32(RxWait, 0x40); // 64: receive done (busy wait)
__SINIC_REG32(TxData, 0x48); // 64: transmit data
__SINIC_REG32(TxDone, 0x50); // 64: transmit done
__SINIC_REG32(TxWait, 0x58); // 64: transmit done (busy wait)
__SINIC_REG32(HwAddr, 0x60); // 64: mac address
__SINIC_REG32(Size, 0x68); // register addres space size
// Config register bits
__SINIC_VAL32(Config_Reset, 31, 1); // reset chip
__SINIC_VAL32(Config_Thread, 8, 1); // enable receive filter
__SINIC_VAL32(Config_Filter, 7, 1); // enable receive filter
__SINIC_VAL32(Config_Vlan, 6, 1); // enable vlan tagging
__SINIC_VAL32(Config_Virtual, 5, 1); // enable virtual addressing
@@ -83,105 +88,103 @@ __SINIC_VAL32(Config_IntEn, 2, 1); // enable interrupts
__SINIC_VAL32(Config_TxEn, 1, 1); // enable transmit
__SINIC_VAL32(Config_RxEn, 0, 1); // enable receive
// Command register bits
__SINIC_VAL32(Command_Reset, 0, 1); // reset chip
// Interrupt register bits
__SINIC_VAL32(Intr_TxFifo, 5, 1); // Fifo oflow/uflow/threshold
__SINIC_VAL32(Intr_TxData, 4, 1); // DMA Completed w/ interrupt
__SINIC_VAL32(Intr_TxDone, 3, 1); // Packet transmitted
__SINIC_VAL32(Intr_RxFifo, 2, 1); // Fifo oflow/uflow/threshold
__SINIC_VAL32(Intr_RxData, 1, 1); // DMA Completed w/ interrupt
__SINIC_VAL32(Intr_RxDone, 0, 1); // Packet received
__SINIC_REG32(Intr_All, 0x3f);
__SINIC_REG32(Intr_NoDelay, 0x24);
__SINIC_REG32(Intr_Res, ~0x3f);
__SINIC_VAL32(Intr_TxLow, 7, 1); // tx fifo dropped below watermark
__SINIC_VAL32(Intr_TxFull, 6, 1); // tx fifo full
__SINIC_VAL32(Intr_TxDMA, 5, 1); // tx dma completed w/ interrupt
__SINIC_VAL32(Intr_TxPacket, 4, 1); // packet transmitted
__SINIC_VAL32(Intr_RxHigh, 3, 1); // rx fifo above high watermark
__SINIC_VAL32(Intr_RxEmpty, 2, 1); // rx fifo empty
__SINIC_VAL32(Intr_RxDMA, 1, 1); // rx dma completed w/ interrupt
__SINIC_VAL32(Intr_RxPacket, 0, 1); // packet received
__SINIC_REG32(Intr_All, 0xff); // all valid interrupts
__SINIC_REG32(Intr_NoDelay, 0xcc); // interrupts that shouldn't be coalesced
__SINIC_REG32(Intr_Res, ~0xff); // reserved interrupt bits
// RX Data Description
__SINIC_VAL64(RxData_Len, 40, 20); // 0 - 1M
__SINIC_VAL64(RxData_Addr, 0, 40); // Address 1TB
// TX Data Description
__SINIC_VAL64(TxData_More, 63, 1);
__SINIC_VAL64(TxData_Checksum, 62, 1);
__SINIC_VAL64(TxData_More, 63, 1); // Packet not complete (will dma more)
__SINIC_VAL64(TxData_Checksum, 62, 1); // do checksum
__SINIC_VAL64(TxData_Len, 40, 20); // 0 - 1M
__SINIC_VAL64(TxData_Addr, 0, 40); // Address 1TB
// RX Done/Busy Information
__SINIC_VAL64(RxDone_Complete, 63, 1);
__SINIC_VAL64(RxDone_IpPacket, 45, 1);
__SINIC_VAL64(RxDone_TcpPacket, 44, 1);
__SINIC_VAL64(RxDone_UdpPacket, 43, 1);
__SINIC_VAL64(RxDone_IpError, 42, 1);
__SINIC_VAL64(RxDone_TcpError, 41, 1);
__SINIC_VAL64(RxDone_UdpError, 40, 1);
__SINIC_VAL64(RxDone_More, 32, 1);
__SINIC_VAL64(RxDone_FifoLen, 20, 8); // up to 255 packets
__SINIC_VAL64(RxDone_Packets, 32, 16); // number of packets in rx fifo
__SINIC_VAL64(RxDone_Busy, 31, 1); // receive dma busy copying
__SINIC_VAL64(RxDone_Complete, 30, 1); // valid data (packet complete)
__SINIC_VAL64(RxDone_More, 29, 1); // Packet has more data (dma again)
__SINIC_VAL64(RxDone_TcpError, 25, 1); // TCP packet error (bad checksum)
__SINIC_VAL64(RxDone_UdpError, 24, 1); // UDP packet error (bad checksum)
__SINIC_VAL64(RxDone_IpError, 23, 1); // IP packet error (bad checksum)
__SINIC_VAL64(RxDone_TcpPacket, 22, 1); // this is a TCP packet
__SINIC_VAL64(RxDone_UdpPacket, 21, 1); // this is a UDP packet
__SINIC_VAL64(RxDone_IpPacket, 20, 1); // this is an IP packet
__SINIC_VAL64(RxDone_CopyLen, 0, 20); // up to 256k
// TX Done/Busy Information
__SINIC_VAL64(TxDone_Complete, 63, 1);
__SINIC_VAL64(TxDone_FifoLen, 20, 8); // up to 255 packets
__SINIC_VAL64(TxDone_CopyLen, 0, 20); // up to 256k
__SINIC_VAL64(TxDone_Packets, 32, 16); // number of packets in tx fifo
__SINIC_VAL64(TxDone_Busy, 31, 1); // transmit dma busy copying
__SINIC_VAL64(TxDone_Complete, 30, 1); // valid data (packet complete)
__SINIC_VAL64(TxDone_Full, 29, 1); // tx fifo is full
__SINIC_VAL64(TxDone_Low, 28, 1); // tx fifo is below the watermark
__SINIC_VAL64(TxDone_CopyLen, 0, 20); // up to 256k
inline int
regSize(int offset)
struct Info
{
static const char sizes[] = {
4,
4,
4,
4,
4,
4,
4,
0,
8, 0,
8, 0,
8, 0,
8, 0,
8, 0,
8, 0,
8, 0
};
if (offset & 0x3)
return 0;
if (offset >= Size)
return 0;
return sizes[offset / 4];
}
inline const char *
regName(int offset)
{
static const char *names[] = {
"Config",
"RxMaxCopy",
"TxMaxCopy",
"RxThreshold",
"TxThreshold",
"IntrStatus",
"IntrMask",
"invalid",
"RxData", "invalid",
"RxDone", "invalid",
"RxWait", "invalid",
"TxData", "invalid",
"TxDone", "invalid",
"TxWait", "invalid",
"HwAddr", "invalid"
};
if (offset & 0x3)
return "invalid";
if (offset >= Size)
return "invalid";
return names[offset / 4];
}
uint8_t size;
bool read;
bool write;
const char *name;
};
/* namespace Regs */ }
inline const Regs::Info&
regInfo(Addr daddr)
{
static Regs::Info info [] = {
{ 4, true, true, "Config" },
{ 4, false, true, "Command" },
{ 4, true, true, "IntrStatus" },
{ 4, true, true, "IntrMask" },
{ 4, true, false, "RxMaxCopy" },
{ 4, true, false, "TxMaxCopy" },
{ 4, true, false, "RxMaxIntr" },
{ 0, false, false, "invalid" },
{ 4, true, false, "RxFifoSize" },
{ 4, true, false, "TxFifoSize" },
{ 4, true, false, "RxFifoMark" },
{ 4, true, false, "TxFifoMark" },
{ 8, true, true, "RxData" }, { 0, false, false, "invalid" },
{ 8, true, false, "RxDone" }, { 0, false, false, "invalid" },
{ 8, true, false, "RxWait" }, { 0, false, false, "invalid" },
{ 8, true, true, "TxData" }, { 0, false, false, "invalid" },
{ 8, true, false, "TxDone" }, { 0, false, false, "invalid" },
{ 8, true, false, "TxWait" }, { 0, false, false, "invalid" },
{ 8, true, false, "HwAddr" }, { 0, false, false, "invalid" }
};
return info[daddr / 4];
}
inline bool
regValid(Addr daddr)
{
if (daddr > Regs::Size)
return false;
if (regInfo(daddr).size == 0)
return false;
return true;
}
/* namespace Sinic */ }
#endif // __DEV_SINICREG_HH__