diff --git a/fpga/include/villas/fpga/ips/intc.hpp b/fpga/include/villas/fpga/ips/intc.hpp index 7bbe31db8..f44bc918f 100644 --- a/fpga/include/villas/fpga/ips/intc.hpp +++ b/fpga/include/villas/fpga/ips/intc.hpp @@ -18,32 +18,23 @@ namespace ip { class InterruptController : public Core { public: - using IrqMaskType = uint32_t; - static constexpr int maxIrqs = 32; + using IrqMaskType = uint32_t; + static constexpr int maxIrqs = 32; - virtual - ~InterruptController(); + virtual ~InterruptController(); - virtual - bool init() override; + virtual bool init() override; - bool enableInterrupt(IrqMaskType mask, bool polling); - bool enableInterrupt(IrqPort irq, bool polling) - { - return enableInterrupt(1 << irq.num, polling); - } + bool enableInterrupt(IrqMaskType mask, bool polling); + bool enableInterrupt(IrqPort irq, bool polling) { + return enableInterrupt(1 << irq.num, polling); + } - bool disableInterrupt(IrqMaskType mask); - bool disableInterrupt(IrqPort irq) - { - return disableInterrupt(1 << irq.num); - } +bool disableInterrupt(IrqMaskType mask); +bool disableInterrupt(IrqPort irq) { return disableInterrupt(1 << irq.num); } - int waitForInterrupt(int irq); - int waitForInterrupt(IrqPort irq) - { - return waitForInterrupt(irq.num); - } +ssize_t waitForInterrupt(int irq); +ssize_t waitForInterrupt(IrqPort irq) { return waitForInterrupt(irq.num); } private: diff --git a/fpga/lib/ips/dma.cpp b/fpga/lib/ips/dma.cpp index e8f8494e4..4e8484ddb 100644 --- a/fpga/lib/ips/dma.cpp +++ b/fpga/lib/ips/dma.cpp @@ -381,120 +381,135 @@ bool Dma::readScatterGather(void *buf, size_t len) Dma::Completion Dma::writeCompleteScatterGather() { - Completion c; - XAxiDma_Bd *bd = nullptr, *curBd; - auto txRing = XAxiDma_GetTxRing(&xDma); - int ret = XST_FAILURE; - static size_t errcnt = 32; + Completion c; + XAxiDma_Bd *bd = nullptr, *curBd; + auto txRing = XAxiDma_GetTxRing(&xDma); + int ret = XST_FAILURE; + static size_t errcnt = 32; - c.interrupts = irqs[mm2sInterrupt].irqController->waitForInterrupt(irqs[mm2sInterrupt].num); + c.interrupts = irqs[mm2sInterrupt].irqController->waitForInterrupt( + irqs[mm2sInterrupt].num); - hwLock.lock(); - if ((c.bds = XAxiDma_BdRingFromHw(txRing, writeCoalesce, &bd)) < writeCoalesce) - { - logger->warn("Send partial batch of {}/{} BDs.", c.bds, writeCoalesce); - if(errcnt-- == 0) { - hwLock.unlock(); - throw RuntimeError("too many partial batches"); - } - } + hwLock.lock(); + if ((c.bds = XAxiDma_BdRingFromHw(txRing, writeCoalesce, &bd)) < + writeCoalesce) { + logger->warn("Send partial batch of {}/{} BDs.", c.bds, writeCoalesce); + if (errcnt-- == 0) { + hwLock.unlock(); + throw RuntimeError("too many partial batches"); + } + } - // Acknowledge the interrupt - auto irqStatus = XAxiDma_BdRingGetIrq(txRing); - XAxiDma_BdRingAckIrq(txRing, irqStatus); + // Acknowledge the interrupt + auto irqStatus = XAxiDma_BdRingGetIrq(txRing); + XAxiDma_BdRingAckIrq(txRing, irqStatus); - if (c.bds == 0) { - c.bytes = 0; - hwLock.unlock(); - return c; - } + if (c.bds == 0) { + c.bytes = 0; + hwLock.unlock(); + return c; + } - if (bd == nullptr) { - hwLock.unlock(); - throw RuntimeError("Bd was null."); - } + if (bd == nullptr) { + hwLock.unlock(); + throw RuntimeError("Bd was null."); + } - curBd = bd; - for (size_t i = 0; i < c.bds; i++) { - ret = XAxiDma_BdGetSts(curBd); - if ((ret & XAXIDMA_BD_STS_ALL_ERR_MASK) || (!(ret & XAXIDMA_BD_STS_COMPLETE_MASK))) { - hwLock.unlock(); - throw RuntimeError("Bd Status register shows error: {}", ret); - break; - } + curBd = bd; + for (size_t i = 0; i < c.bds; i++) { + ret = XAxiDma_BdGetSts(curBd); + if ((ret & XAXIDMA_BD_STS_ALL_ERR_MASK) || + (!(ret & XAXIDMA_BD_STS_COMPLETE_MASK))) { + hwLock.unlock(); + throw RuntimeError("Bd Status register shows error: {}", ret); + } - c.bytes += XAxiDma_BdGetLength(bd, txRing->MaxTransferLen); - curBd = (XAxiDma_Bd *) XAxiDma_BdRingNext(txRing, curBd); - } + c.bytes += XAxiDma_BdGetLength(bd, txRing->MaxTransferLen); + curBd = (XAxiDma_Bd *)XAxiDma_BdRingNext(txRing, curBd); + } - ret = XAxiDma_BdRingFree(txRing, c.bds, bd); - if (ret != XST_SUCCESS) { - hwLock.unlock(); - throw RuntimeError("Failed to free {} TX BDs {}", c.bds, ret); - } + ret = XAxiDma_BdRingFree(txRing, c.bds, bd); + if (ret != XST_SUCCESS) { + hwLock.unlock(); + throw RuntimeError("Failed to free {} TX BDs {}", c.bds, ret); + } - hwLock.unlock(); - return c; + hwLock.unlock(); + return c; } Dma::Completion Dma::readCompleteScatterGather() { - Completion c; - XAxiDma_Bd *bd = nullptr, *curBd; - auto rxRing = XAxiDma_GetRxRing(&xDma); - int ret = XST_FAILURE; - static size_t errcnt = 32; + Completion c; + XAxiDma_Bd *bd = nullptr, *curBd; + auto rxRing = XAxiDma_GetRxRing(&xDma); + int ret = XST_FAILURE; + static size_t errcnt = 32; - c.interrupts = irqs[s2mmInterrupt].irqController->waitForInterrupt(irqs[s2mmInterrupt].num); + ssize_t intrs = irqs[s2mmInterrupt].irqController->waitForInterrupt( + irqs[s2mmInterrupt].num); - hwLock.lock(); - // Wait until the data has been received by the RX channel. - if ((c.bds = XAxiDma_BdRingFromHw(rxRing, readCoalesce, &bd)) < readCoalesce) - { - logger->warn("Got partial batch of {}/{} BDs.", c.bds, readCoalesce); - if(errcnt-- == 0) { - hwLock.unlock(); - throw RuntimeError("too many partial batches"); - } - } + if (intrs < 0) { + logger->warn("Interrupt error or timeout"); + c.interrupts = 0; + return c; + } else { + c.interrupts = intrs; + } + hwLock.lock(); + auto irqStatus = XAxiDma_BdRingGetIrq(rxRing); + XAxiDma_BdRingAckIrq(rxRing, irqStatus); + if (!(irqStatus & XAXIDMA_IRQ_IOC_MASK)) { + logger->error("Expected IOC interrupt but IRQ status is: {:#x}", irqStatus); + return c; + } + // logger->trace("Read IRQ status: {:#x}", irqStatus); - // Acknowledge the interrupt. Has no effect if no interrupt has occured. - auto irqStatus = XAxiDma_BdRingGetIrq(rxRing); - XAxiDma_BdRingAckIrq(rxRing, irqStatus); + // Wait until the data has been received by the RX channel. + if ((c.bds = XAxiDma_BdRingFromHw(rxRing, readCoalesce, &bd)) < + readCoalesce) { + logger->warn("Got partial batch of {}/{} BDs.", c.bds, readCoalesce); + if (errcnt-- == 0) { + hwLock.unlock(); + throw RuntimeError("too many partial batches"); + } + } - if (c.bds == 0) { - c.bytes = 0; - hwLock.unlock(); - return c; - } + if (c.bds == 0) { + c.bytes = 0; + hwLock.unlock(); + return c; + } - if (bd == nullptr) { - hwLock.unlock(); - throw RuntimeError("Bd was null."); - } + if (bd == nullptr) { + hwLock.unlock(); + throw RuntimeError("Bd was null."); + } - curBd = bd; - for (size_t i = 0; i < c.bds; i++) { - ret = XAxiDma_BdGetSts(curBd); - if ((ret & XAXIDMA_BD_STS_ALL_ERR_MASK) || (!(ret & XAXIDMA_BD_STS_COMPLETE_MASK))) { - hwLock.unlock(); - throw RuntimeError("Bd Status register shows error: {}", ret); - break; - } + curBd = bd; + for (size_t i = 0; i < c.bds; i++) { + // logger->trace("Read BD {}/{}: {:#x}", i, c.bds, + // XAxiDma_BdGetBufAddr(curBd)); + ret = XAxiDma_BdGetSts(curBd); + if ((ret & XAXIDMA_BD_STS_ALL_ERR_MASK) || + (!(ret & XAXIDMA_BD_STS_COMPLETE_MASK))) { + hwLock.unlock(); + throw RuntimeError("Bd Status register shows error: {}", ret); + } - c.bytes += XAxiDma_BdGetActualLength(bd, rxRing->MaxTransferLen); - curBd = (XAxiDma_Bd *) XAxiDma_BdRingNext(rxRing, curBd); - } + c.bytes += XAxiDma_BdGetActualLength(bd, rxRing->MaxTransferLen); + curBd = (XAxiDma_Bd *)XAxiDma_BdRingNext(rxRing, curBd); + } - // Free all processed RX BDs for future transmission. - ret = XAxiDma_BdRingFree(rxRing, c.bds, bd); - if (ret != XST_SUCCESS) { - hwLock.unlock(); - throw RuntimeError("Failed to free {} TX BDs {}.", c.bds, ret); - } + // Free all processed RX BDs for future transmission. + ret = XAxiDma_BdRingFree(rxRing, c.bds, bd); + if (ret != XST_SUCCESS) { + hwLock.unlock(); + throw RuntimeError("Failed to free {} TX BDs {}.", c.bds, ret); + } - hwLock.unlock(); - return c; + hwLock.unlock(); + return c; } bool Dma::writeSimple(const void *buf, size_t len) diff --git a/fpga/lib/ips/intc.cpp b/fpga/lib/ips/intc.cpp index f1cefc94a..99d9af2f7 100644 --- a/fpga/lib/ips/intc.cpp +++ b/fpga/lib/ips/intc.cpp @@ -117,38 +117,52 @@ InterruptController::disableInterrupt(InterruptController::IrqMaskType mask) return true; } -int -InterruptController::waitForInterrupt(int irq) -{ - assert(irq < maxIrqs); +ssize_t InterruptController::waitForInterrupt(int irq) { + assert(irq < maxIrqs); - const uintptr_t base = getBaseAddr(registerMemory); + const uintptr_t base = getBaseAddr(registerMemory); - if (this->polling[irq]) { - uint32_t isr, mask = 1 << irq; + if (this->polling[irq]) { + uint32_t isr, mask = 1 << irq; - do { - // Poll status register - isr = XIntc_In32(base + XIN_ISR_OFFSET); - pthread_testcancel(); - } while ((isr & mask) != mask); + do { + // Poll status register + isr = XIntc_In32(base + XIN_ISR_OFFSET); + pthread_testcancel(); + } while ((isr & mask) != mask); - // Acknowledge interrupt - XIntc_Out32(base + XIN_IAR_OFFSET, mask); + // Acknowledge interrupt + XIntc_Out32(base + XIN_IAR_OFFSET, mask); - // We can only tell that there has been (at least) one interrupt - return 1; - } - else { - uint64_t count; + // We can only tell that there has been (at least) one interrupt + return 1; + } else { + uint64_t count; + int sret; + fd_set rfds; + struct timeval tv = {.tv_sec = 1, .tv_usec = 0}; + FD_ZERO(&rfds); + FD_SET(efds[irq], &rfds); - // Block until there has been an interrupt, read number of interrupts - ssize_t ret = read(efds[irq], &count, sizeof(count)); - if (ret != sizeof(count)) - return -1; + sret = select(efds[irq] + 1, &rfds, NULL, NULL, &tv); + if (sret == -1) { + logger->error("select() failed: {}", strerror(errno)); + return -1; + } else if (sret == 0) { + logger->warn("timeout waiting for interrupt {}", irq); + return -1; + } + // Block until there has been an interrupt, read number of interrupts + ssize_t ret = read(efds[irq], &count, sizeof(count)); + if (ret != sizeof(count)) { + logger->error("Failed to read from eventfd: {}", strerror(errno)); + return -1; + } - return static_cast(count); - } + logger->debug("Received {} interrupts on {}", count, irq); + + return count; + } } static char n[] = "intc"; diff --git a/fpga/src/villas-fpga-ctrl.cpp b/fpga/src/villas-fpga-ctrl.cpp index ba332ce4e..c6abee39c 100644 --- a/fpga/src/villas-fpga-ctrl.cpp +++ b/fpga/src/villas-fpga-ctrl.cpp @@ -121,6 +121,7 @@ void writeToDmaFromStdIn(std::shared_ptr dma) { void readFromDmaToStdOut( std::shared_ptr dma, std::unique_ptr formatter) { + auto &alloc = villas::HostRam::getAllocator(); const std::shared_ptr block[] = { @@ -138,19 +139,19 @@ void readFromDmaToStdOut( // Setup read transfer dma->read(*block[0], block[0]->getSize()); + int cnt = 0; while (true) { - logger->trace("Read from stream and write to address {}:{:p}", - block[next]->getAddrSpaceId(), block[next]->getOffset()); + SPDLOG_TRACE("Read from stream and write to address {}:{:#x}", + block[next]->getAddrSpaceId(), block[next]->getOffset()); // We could use the number of interrupts to determine if we missed a chunk of data dma->read(*block[next], block[next]->getSize()); auto c = dma->readComplete(); if (c.interrupts > 1) { - logger->warn("Missed {} interrupts", c.interrupts - 1); + SPDLOG_WARN("Missed {} interrupts", c.interrupts - 1); } - logger->debug("bytes: {}, intrs: {}, bds: {}", c.bytes, c.interrupts, - c.bds); + SPDLOG_TRACE("bytes: {}, intrs: {}, bds: {}", c.bytes, c.interrupts, c.bds); try { for (size_t i = 0; i * 4 < c.bytes; i++) { int32_t ival = mem[cur][i]; @@ -160,11 +161,11 @@ void readFromDmaToStdOut( *((float *)(&ival)); // cppcheck-suppress invalidPointerCast #pragma GCC diagnostic pop formatter->format(fval); - printf("%#x\n", ival); + printf("%d: %#x\n", cnt++, ival); } formatter->output(std::cout); } catch (const std::exception &e) { - logger->warn("Failed to output data: {}", e.what()); + SPDLOG_WARN("Failed to output data: {}", e.what()); } cur = next; @@ -202,7 +203,7 @@ int main(int argc, char *argv[]) { // Logging setup - logging.setLevel(spdlog::level::debug); + logging.setLevel(spdlog::level::trace); fpga::setupColorHandling(); if (configFile.empty()) {