diff --git a/dev/sinic.cc b/dev/sinic.cc index e3e1ffba0..1a1456e5f 100644 --- a/dev/sinic.cc +++ b/dev/sinic.cc @@ -316,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) @@ -328,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 ®32 = *(uint32_t *)data; - uint64_t ®64 = *(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 ® = *(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 ® = *(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: @@ -448,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; @@ -460,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; @@ -490,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); } @@ -628,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) { @@ -657,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(®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 @@ -681,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(); } @@ -707,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; } @@ -762,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(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; @@ -803,7 +852,7 @@ Device::rxKick() } regs.RxDone |= Regs::RxDone_Complete; - devIntrPost(Regs::Intr_RxData); + devIntrPost(Regs::Intr_RxDMA); rxState = rxIdle; break; @@ -832,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(); } @@ -850,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", @@ -858,7 +913,6 @@ Device::transmit() } txFifo.pop(); - #if TRACING_ON if (DTRACE(Ethernet)) { IpPtr ip(packet); @@ -873,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()) { @@ -908,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; } @@ -930,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; @@ -988,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; @@ -1094,8 +1153,8 @@ Device::recvPacket(PacketPtr packet) 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, @@ -1103,7 +1162,7 @@ Device::recvPacket(PacketPtr packet) return false; } - devIntrPost(Regs::Intr_RxDone); + devIntrPost(Regs::Intr_RxPacket); rxKick(); return true; } @@ -1161,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); @@ -1187,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); @@ -1203,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); @@ -1231,12 +1293,11 @@ Device::unserialize(Checkpoint *cp, const std::string §ion) * 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); @@ -1247,6 +1308,7 @@ Device::unserialize(Checkpoint *cp, const std::string §ion) */ int rxState; UNSERIALIZE_SCALAR(rxState); + UNSERIALIZE_SCALAR(rxEmpty); this->rxState = (RxState) rxState; rxFifo.unserialize("rxFifo", cp, section); bool rxPacketExists; @@ -1267,6 +1329,7 @@ Device::unserialize(Checkpoint *cp, const std::string §ion) */ int txState; UNSERIALIZE_SCALAR(txState); + UNSERIALIZE_SCALAR(txFull); this->txState = (TxState) txState; txFifo.unserialize("txFifo", cp, section); bool txPacketExists; @@ -1308,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; } @@ -1385,6 +1452,7 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(Device) Param tx_delay; Param rx_max_copy; Param tx_max_copy; + Param rx_max_intr; Param rx_fifo_size; Param tx_fifo_size; Param rx_fifo_threshold; @@ -1392,6 +1460,7 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(Device) Param rx_filter; Param hardware_address; + Param dedicated; END_DECLARE_SIM_OBJECT_PARAMS(Device) @@ -1424,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) @@ -1442,6 +1513,7 @@ CREATE_SIM_OBJECT(Device) params->name = getInstanceName(); params->clock = clock; + params->mmu = mmu; params->physmem = physmem; params->configSpace = configspace; @@ -1466,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; @@ -1473,6 +1546,7 @@ CREATE_SIM_OBJECT(Device) params->rx_filter = rx_filter; params->eaddr = hardware_address; + params->dedicated = dedicated; return new Device(params); } diff --git a/dev/sinic.hh b/dev/sinic.hh index 924c6eeeb..e01015061 100644 --- a/dev/sinic.hh +++ b/dev/sinic.hh @@ -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 ®Data8(Addr daddr) { return *((uint8_t *)®s + daddr); } + uint32_t ®Data32(Addr daddr) { return *(uint32_t *)®Data8(daddr); } + uint64_t ®Data64(Addr daddr) { return *(uint64_t *)®Data8(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; - EventWrapper txDmaEvent; + EventWrapper 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: diff --git a/dev/sinicreg.hh b/dev/sinicreg.hh index 78b175f71..12f545255 100644 --- a/dev/sinicreg.hh +++ b/dev/sinicreg.hh @@ -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__ diff --git a/python/m5/objects/Ethernet.py b/python/m5/objects/Ethernet.py index c2f818325..a97e58bda 100644 --- a/python/m5/objects/Ethernet.py +++ b/python/m5/objects/Ethernet.py @@ -83,6 +83,7 @@ class EtherDevBase(PciDevice): rx_filter = Param.Bool(True, "Enable Receive Filter") intr_delay = Param.Latency('10us', "Interrupt Propagation Delay") + dedicated = Param.Bool(False, "dedicate a kernel thread to the driver") class NSGigE(EtherDevBase): type = 'NSGigE' @@ -90,7 +91,6 @@ class NSGigE(EtherDevBase): dma_data_free = Param.Bool(False, "DMA of Data is free") dma_desc_free = Param.Bool(False, "DMA of Descriptors is free") - dedicated = Param.Bool(False, "dedicate a kernel thread to the driver") class NSGigEInt(EtherInt): type = 'NSGigEInt' @@ -101,6 +101,7 @@ class Sinic(EtherDevBase): rx_max_copy = Param.MemorySize('1514B', "rx max copy") tx_max_copy = Param.MemorySize('16kB', "tx max copy") + rx_max_intr = Param.UInt32(10, "max rx packets per interrupt") rx_fifo_threshold = Param.MemorySize('48kB', "rx fifo high threshold") tx_fifo_threshold = Param.MemorySize('16kB', "tx fifo low threshold")