Forum Discussion
A few things to try:
1. If your soft IP is generating the interrupts at X times per second, could you try clearing the interrupt status after every IRQ received at your application.
Example,
uint32_t irq_status = *(volatile uint32_t *)(mmio_base + IRQ_STATUS_REG); // Read status
*(volatile uint32_t *)(mmio_base + IRQ_CLEAR_REG) = irq_status; // Clear it
There is a possibility that, this create some form of an interrupt storm if you don't. Not clearing it may cause the interrupts pilling up.
2. if you disable the interrupt at the FPGA, and poll for the events from the FPGA IP from a user application or a kernel device driver by polling a FPGA register for the events, does the CPU utilization issue goes away? This test tells us if the interrupts caused the high CPU utilization.
3. You could also try to modify the FPGA soft IP to clear the interrupt every time an interrupt is triggered. But this requires more work.
4. You don't have to acknowledge the interrupt. Remove this "ssize_t nb = write(pHandle->txTrigIrqFd, &info, sizeof(info));". This is only done after a read(). So, this is kind of wrong. A Read() is a blocking operation and once it unblocks, it means an interrupt has occured. You could then, acknowledge it after that if you want. Something like this,
Example,
// Function to handle the interrupt
bool wait_for_irq(TX_IRQ_HANDLE_S* pHandle) {
if (!pHandle || pHandle->txTrigIrqFd < 0) {
std::cerr << "ERROR: Invalid handle" << std::endl;
return false;
}
uint32_t info;
ssize_t nb = read(pHandle->txTrigIrqFd, &info, sizeof(info)); // Read the interrupt info
if (nb != sizeof(info)) {
std::cerr << "ERROR: Read failed" << std::endl;
return false;
}
std::cout << "Interrupt received, processing..." << std::endl;
// After processing the interrupt, acknowledge it by writing back to the UIO device
nb = write(pHandle->txTrigIrqFd, &info, sizeof(info)); // Acknowledge interrupt
if (nb != sizeof(info)) {
std::cerr << "ERROR: Write failed" << std::endl;
return false;
}
return true;
}
Thanks
- yepp7 months ago
New Contributor
Thank you!
Unfortunately none of them work.
1. It is UIO irq only device, no memory region assigned to it.
2. Yes, I have done it before, it works, but I need the more stricter timing with IRQ.
3. It is an edge-triggered irq.
4. I've already tried everything (except the solution :D), nothing worked. I've made it clear/not to clear, tried with poll/select , swapped the orders etc.
- TiensungA_Altera7 months ago
New Contributor
2. Yes, I have done it before, it works, but I need the more stricter timing with IRQ.
>The only clue I have is that, it seems the interrupt handling may be the culprit. Even though it is edge triggered, apparently the interrupt did not get cleared properly and results in an interrupt storm. Can you check if the Linux UIO kernel driver is receiving the interrupt storm and hence causing the CPU spike? Probably using "cat /proc/interrupts" to see the interrupt statistics.
You mentioned the FPGA "The installed FPGA image is doing nothing more than making interrupts to an UIO device, 50 times a sec." Is this part of the Arria10 GHRD? Can you share us more information on the design?
DT you shared:
tx_trig_irq { /* /dev/uio4 */ compatible = "test_irq", "generic-uio"; interrupts = < 0 0x16 IRQ_TYPE_EDGE_RISING >; interrupt-parent = <&intc>; };You are using 0x16 = 22 , so, the IRQ = 22 + 32 = 55 (F2S_FPGA_IRQ4). This seems right.
The FPGQ IRQs for Arria10 begins 51 with https://www.intel.com/content/www/us/en/docs/programmable/683711/21-2/gic-interrupt-map-for-the-arria-10-soc-hps.html
51
FPGA
F2S_FPGA_IRQ0 -
Level or Edge
52
FPGA
F2S_FPGA_IRQ1 -
Level or Edge
53
FPGA
F2S_FPGA_IRQ2 -
Level or Edge
54
FPGA
F2S_FPGA_IRQ3 -
Level or Edge
55
FPGA
F2S_FPGA_IRQ4 -
Level or Edge
56
FPGA
F2S_FPGA_IRQ5 -
Level or Edge
57
FPGA
F2S_FPGA_IRQ6 -
Level or Edge
- yepp7 months ago
New Contributor
The FPGA design is very simple: it generates a single pulse every 20ms. this pulse signal is directly connected to the f2h_irq line 3. (22 + 32 = 54 (F2S_FPGA_IRQ3) ) . This is only IRQ line which is connected.
I've already checked a few times for a storm:
- the cat /proc/interrupts shows no increment when the irq-s are not handled by the sw. (or the re-enable bit is not written back)
- I've double checked the kernel (compiled it with lots of debug messages), there is no storm for sure.
- TiensungA_Altera7 months ago
New Contributor
Item 4: Still some question on the user application design:
Just to double confirm, WRITE() must always be after READ() and only after you are done with any data processing/event handling.
In the interrupt handler, any interrupt trigger will automatically disable the IRQ. The READ() will get a wakeup and at this point, the IRQ is disabled. The call to write() will re-enable the IRQ.
If you don't do a WRITE at all, do you see the CPU spikes? In this scenario, the IRQ should be disabled and not entertaining edge interrupt triggers. Check "cat /proc/interrupts" to see if the counts stopped.
And if you do a WRITE() from your test,
Check "cat /proc/interrupts" to see if the counts increment as expected or it storms with a huge number.
bool wait_for_irq (TX_IRQ_HANDLE_S* pHandle) { if (!pHandle || pHandle->txTrigIrqFd < 0) { std::cout << "ERROR: handle"; return false; } uint32_t info = 1; ssize_t nb = write(pHandle->txTrigIrqFd, &info, sizeof(info)); <- this re-enables IRQ, should always be only when you are ready to for the next event. if (nb != (ssize_t)sizeof(info)) { std::cout << "ERROR: writing"; return false; } nb = read(pHandle->txTrigIrqFd, &info, sizeof(info)); if (nb == (ssize_t)sizeof(info)) { return true; } return false; }
- yepp7 months ago
New Contributor
This was a "minimal" program for the forum, but yes, the re-enable (write) should be after the read, and also before the first read, we should enable the irq. I pasted to this minimal code appearently in the wrong order, however I tried every combination. Also with the correct READ->WRITE .
Yes, the interrupts are stopped coming when I don't re-enable it (= do not call write), but continued to waiting for it with read/poll/select. Also the /proc/interrupts counter is stopped, and the spikes in the CPU usage are gone.When I continue to re-enable the interrupts in the program, the irq counter continues from the number when it was stopped (not re-enabled).
I've already checked a few times for a storm:
- the cat /proc/interrupts shows no increment when the irq-s are not handled by the sw. (or the re-enable bit is not written back)
- I've double checked the kernel (compiled it with lots of debug messages), there is no storm for sure.