}
}
+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)
//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))
- panic("invalid size for reg %s: da=%#x pa=%#x va=%#x size=%d",
- Regs::regName(daddr), 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);
-
- uint32_t ®32 = *(uint32_t *)data;
- uint64_t ®64 = *(uint64_t *)data;
+ 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);
- switch (daddr) {
- case Regs::Config:
- reg32 = regs.Config;
- break;
+ 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);
- case Regs::RxMaxCopy:
- reg32 = regs.RxMaxCopy;
- break;
+ prepareRead();
- case Regs::TxMaxCopy:
- reg32 = regs.TxMaxCopy;
- break;
+ uint64_t value = 0;
+ if (req->size == 4) {
+ uint32_t ® = *(uint32_t *)data;
+ reg = regData32(daddr);
+ value = reg;
+ }
- case Regs::RxThreshold:
- reg32 = regs.RxThreshold;
- break;
+ if (req->size == 8) {
+ uint64_t ® = *(uint64_t *)data;
+ reg = regData64(daddr);
+ value = reg;
+ }
- case Regs::TxThreshold:
- reg32 = regs.TxThreshold;
- break;
+ 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);
- case Regs::IntrStatus:
- reg32 = regs.IntrStatus;
+ // reading the interrupt status register has the side effect of
+ // clearing it
+ if (daddr == Regs::IntrStatus)
devIntrClear();
- break;
- case Regs::IntrMask:
- reg32 = regs.IntrMask;
- break;
+ return No_Fault;
+}
- case Regs::RxData:
- reg64 = regs.RxData;
- break;
+/**
+ * IPR read of device register
+ */
+Fault
+Device::iprRead(Addr daddr, uint64_t &result)
+{
+ if (!regValid(daddr))
+ panic("invalid address: da=%#x", daddr);
- case Regs::RxDone:
- case Regs::RxWait:
- reg64 = Regs::set_RxDone_FifoLen(regs.RxDone,
- min(rxFifo.packets(), 255));
- break;
+ const Regs::Info &info = regInfo(daddr);
+ if (!info.read)
+ panic("reading write only register %s: da=%#x", info.name, daddr);
- case Regs::TxData:
- reg64 = regs.TxData;
- break;
+ DPRINTF(EthernetPIO, "read reg=%s da=%#x\n", info.name, daddr);
- case Regs::TxDone:
- case Regs::TxWait:
- reg64 = Regs::set_TxDone_FifoLen(regs.TxDone,
- min(txFifo.packets(), 255));
- break;
+ prepareRead();
- case Regs::HwAddr:
- reg64 = params()->eaddr;
- break;
+ if (info.size == 4)
+ result = regData32(daddr);
- 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);
- }
+ if (info.size == 8)
+ result = regData64(daddr);
- DPRINTF(EthernetPIO, "read reg=%s done val=%#x\n", Regs::regName(daddr),
- Regs::regSize(daddr) == 4 ? reg32 : reg64);
+ 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:
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;
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;
"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);
}
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) {
}
}
+void
+Device::command(uint32_t command)
+{
+ if (command & Regs::Command_Reset)
+ reset();
+}
+
void
Device::reset()
{
using namespace Regs;
+
memset(®s, 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
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();
}
switch (rxState) {
case rxIdle:
if (rxPioRequest) {
+ DPRINTF(EthernetPIO, "rxIdle: PIO waiting responding at %d\n",
+ curTick + pioLatency);
pioInterface->respond(rxPioRequest, curTick);
rxPioRequest = 0;
}
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;
}
regs.RxDone |= Regs::RxDone_Complete;
- devIntrPost(Regs::Intr_RxData);
+ devIntrPost(Regs::Intr_RxDMA);
rxState = rxIdle;
break;
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();
}
return;
}
+ uint32_t interrupts;
PacketPtr packet = txFifo.front();
if (!interface->sendPacket(packet)) {
DPRINTF(Ethernet, "Packet Transmit: failed txFifo available %d\n",
}
txFifo.pop();
-
#if TRACING_ON
if (DTRACE(Ethernet)) {
IpPtr ip(packet);
}
#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()) {
switch (txState) {
case txIdle:
if (txPioRequest) {
+ DPRINTF(EthernetPIO, "txIdle: PIO waiting responding at %d\n",
+ curTick + pioLatency);
pioInterface->respond(txPioRequest, curTick + pioLatency);
txPioRequest = 0;
}
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;
}
}
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;
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,
return false;
}
- devIntrPost(Regs::Intr_RxDone);
+ devIntrPost(Regs::Intr_RxPacket);
rxKick();
return true;
}
// 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);
*/
int rxState = this->rxState;
SERIALIZE_SCALAR(rxState);
+ SERIALIZE_SCALAR(rxEmpty);
rxFifo.serialize("rxFifo", os);
bool rxPacketExists = rxPacket;
SERIALIZE_SCALAR(rxPacketExists);
*/
int txState = this->txState;
SERIALIZE_SCALAR(txState);
+ SERIALIZE_SCALAR(txFull);
txFifo.serialize("txFifo", os);
bool txPacketExists = txPacket;
SERIALIZE_SCALAR(txPacketExists);
* 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);
*/
int rxState;
UNSERIALIZE_SCALAR(rxState);
+ UNSERIALIZE_SCALAR(rxEmpty);
this->rxState = (RxState) rxState;
rxFifo.unserialize("rxFifo", cp, section);
bool rxPacketExists;
*/
int txState;
UNSERIALIZE_SCALAR(txState);
+ UNSERIALIZE_SCALAR(txFull);
this->txState = (TxState) txState;
txFifo.unserialize("txFifo", cp, section);
bool txPacketExists;
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;
}
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;
Param<bool> rx_filter;
Param<string> hardware_address;
+ Param<bool> dedicated;
END_DECLARE_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)
params->name = getInstanceName();
params->clock = clock;
+
params->mmu = mmu;
params->physmem = physmem;
params->configSpace = configspace;
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;
params->rx_filter = rx_filter;
params->eaddr = hardware_address;
+ params->dedicated = dedicated;
return new Device(params);
}
// 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
__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
-
-inline int
-regSize(int offset)
+__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
+
+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
- };
+ uint8_t size;
+ bool read;
+ bool write;
+ const char *name;
+};
- if (offset & 0x3)
- return 0;
+/* namespace Regs */ }
- if (offset >= Size)
- return 0;
+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 sizes[offset / 4];
+ return info[daddr / 4];
}
-inline const char *
-regName(int offset)
+inline bool
+regValid(Addr daddr)
{
- 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 (daddr > Regs::Size)
+ return false;
- if (offset & 0x3)
- return "invalid";
+ if (regInfo(daddr).size == 0)
+ return false;
- if (offset >= Size)
- return "invalid";
-
- return names[offset / 4];
+ return true;
}
-/* namespace Regs */ }
/* namespace Sinic */ }
#endif // __DEV_SINICREG_HH__