diff --git a/linux/ipcore/PdecHandler.cpp b/linux/ipcore/PdecHandler.cpp index aedfef9f..5ea85516 100644 --- a/linux/ipcore/PdecHandler.cpp +++ b/linux/ipcore/PdecHandler.cpp @@ -146,8 +146,6 @@ ReturnValue_t PdecHandler::irqOperation() { // Used to unmask IRQ uint32_t info = 1; - ssize_t nb = 0; - int ret = 0; interruptWindowCd.resetTimer(); @@ -171,62 +169,7 @@ ReturnValue_t PdecHandler::irqOperation() { state = State::RUNNING; break; case State::RUNNING: { - nb = write(fd, &info, sizeof(info)); - if (nb != static_cast(sizeof(info))) { - sif::error << "PdecHandler::irqOperation: Unmasking IRQ failed" << std::endl; - triggerEvent(WRITE_SYSCALL_ERROR_PDEC, errno); - close(fd); - state = State::INIT; - return returnvalue::FAILED; - } - struct pollfd fds = {.fd = fd, .events = POLLIN, .revents = 0}; - ret = poll(&fds, 1, IRQ_TIMEOUT_MS); - if (ret == 0) { - // No TCs for timeout period - checkLocks(); - genericCheckCd.resetTimer(); - resetIrqLimiters(); - } else if (ret >= 1) { - nb = read(fd, &info, sizeof(info)); - interruptCounter++; - if (nb == static_cast(sizeof(info))) { - uint32_t pisr = *(registerBaseAddress + PDEC_PISR_OFFSET); - if ((pisr & TC_NEW_MASK) == TC_NEW_MASK) { - // handle TC - handleNewTc(); - } - if ((pisr & TC_ABORT_MASK) == TC_ABORT_MASK) { - tcAbortCounter += 1; - } - if ((pisr & NEW_FAR_MASK) == NEW_FAR_MASK) { - // Read FAR here - CURRENT_FAR = readFar(); - checkFrameAna(CURRENT_FAR); - } - if (genericCheckCd.hasTimedOut()) { - checkLocks(); - genericCheckCd.resetTimer(); - if (interruptWindowCd.timeOut()) { - if (interruptCounter >= MAX_ALLOWED_IRQS_PER_WINDOW) { - sif::error << "PdecHandler::irqOperation: Possible IRQ storm" << std::endl; - triggerEvent(TOO_MANY_IRQS, MAX_ALLOWED_IRQS_PER_WINDOW); - TaskFactory::delayTask(400); - break; - } - resetIrqLimiters(); - } - } - // Clear interrupts with dummy read - dummy = *(registerBaseAddress + PDEC_PIR_OFFSET); - } - } else { - sif::error << "PdecHandler::irqOperation: Poll error with errno " << errno << ": " - << strerror(errno) << std::endl; - triggerEvent(POLL_SYSCALL_ERROR_PDEC, errno); - close(fd); - state = State::INIT; - return returnvalue::FAILED; - } + checkAndHandleIrqs(fd, info); break; } case State::WAIT_FOR_RECOVERY: @@ -244,6 +187,71 @@ ReturnValue_t PdecHandler::irqOperation() { return returnvalue::OK; } +ReturnValue_t PdecHandler::checkAndHandleIrqs(int fd, uint32_t& info) { + ssize_t nb = write(fd, &info, sizeof(info)); + if (nb != static_cast(sizeof(info))) { + sif::error << "PdecHandler::irqOperation: Unmasking IRQ failed" << std::endl; + triggerEvent(WRITE_SYSCALL_ERROR_PDEC, errno); + close(fd); + state = State::INIT; + return returnvalue::FAILED; + } + struct pollfd fds = {.fd = fd, .events = POLLIN, .revents = 0}; + int ret = poll(&fds, 1, IRQ_TIMEOUT_MS); + if (ret == 0) { + // No TCs for timeout period + checkLocks(); + genericCheckCd.resetTimer(); + resetIrqLimiters(); + } else if (ret >= 1) { + // Interrupt handling. + nb = read(fd, &info, sizeof(info)); + interruptCounter++; + if (nb == static_cast(sizeof(info))) { + uint32_t pisr = *(registerBaseAddress + PDEC_PISR_OFFSET); + if ((pisr & TC_NEW_MASK) == TC_NEW_MASK) { + // handle TC + handleNewTc(); + } + if ((pisr & TC_ABORT_MASK) == TC_ABORT_MASK) { + tcAbortCounter += 1; + } + if ((pisr & NEW_FAR_MASK) == NEW_FAR_MASK) { + // Read FAR here + CURRENT_FAR = readFar(); + checkFrameAna(CURRENT_FAR); + } + // Clear interrupts with dummy read. Volatile is important here to prevent + // compiler opitmizations in release builds! + volatile uint32_t dummy = *(registerBaseAddress + PDEC_PIR_OFFSET); + static_cast(dummy); + + if (genericCheckCd.hasTimedOut()) { + checkLocks(); + genericCheckCd.resetTimer(); + if (interruptWindowCd.hasTimedOut()) { + if (interruptCounter >= MAX_ALLOWED_IRQS_PER_WINDOW) { + sif::error << "PdecHandler::irqOperation: Possible IRQ storm" << std::endl; + triggerEvent(TOO_MANY_IRQS, MAX_ALLOWED_IRQS_PER_WINDOW); + resetIrqLimiters(); + TaskFactory::delayTask(400); + return returnvalue::FAILED; + } + resetIrqLimiters(); + } + } + } + } else { + sif::error << "PdecHandler::irqOperation: Poll error with errno " << errno << ": " + << strerror(errno) << std::endl; + triggerEvent(POLL_SYSCALL_ERROR_PDEC, errno); + close(fd); + state = State::INIT; + return returnvalue::FAILED; + } + return returnvalue::OK; +} + void PdecHandler::readCommandQueue(void) { CommandMessage commandMessage; ReturnValue_t result = returnvalue::FAILED; diff --git a/linux/ipcore/PdecHandler.h b/linux/ipcore/PdecHandler.h index 5348f120..51cf750e 100644 --- a/linux/ipcore/PdecHandler.h +++ b/linux/ipcore/PdecHandler.h @@ -266,6 +266,7 @@ class PdecHandler : public SystemObject, public ExecutableObjectIF, public HasAc ReturnValue_t polledOperation(); ReturnValue_t irqOperation(); + ReturnValue_t checkAndHandleIrqs(int fd, uint32_t& info); uint32_t readFar();