abhishek-kakkar / BeagleLogic

A Software Suite that implements a logic analyzer with the PRU on the BeagleBone / BeagleBone Black.
www.beaglelogic.net
GNU General Public License v3.0
465 stars 71 forks source link

from_bl_irq_1 lost IRQs #47

Open acf-bwl opened 3 years ago

acf-bwl commented 3 years ago

Hello,

It appears that some of the from_bl_irq_1 IRQs are lost on my system. This happens presumably because the interrupt request flag set by the PRU has only two states, so setting the already set flag again won't cause the interrupt handler to be run a second time. I assume this is happening due to the ARM CPU being stuck in some other higher-priority interrupt or something of that sort.

As the kernel driver assumes the interrupt handler will be run once for each buffer written by the PRU, read calls are blocked awaiting interrupts which will never arrive. The capture in PulseView stalls out, and the system must be rebooted before another capture can be made.

I have created a patch that resolves this problem by changing the interrupt handler to process all buffers written by the PRU since the last interrupt. Note that my patch is against commit 83b48e33cea160577e673830069c94c4fa965024 as I am still running the 4.9.36-ti-r46 kernel.

diff --git a/firmware/beaglelogic-pru0-core.asm b/firmware/beaglelogic-pru0-core.asm
index 669b673..a712782 100644
--- a/firmware/beaglelogic-pru0-core.asm
+++ b/firmware/beaglelogic-pru0-core.asm
@@ -21,7 +21,7 @@ run:
    LDI R1, 0
 $run$0:
    ; Load scatter/gather list entries
-   ADD R16, R14, 24
+   ADD R16, R14, 28
 $run$1:
    ; Load start and end address of mem chunk
    ; If it's zero, we're done
@@ -39,6 +39,7 @@ $run$2:

    ; Signal ARM that one buffer is now ready
    ; Also check if we received the kill signal
+   SBBO    &R16, R14, 24, 4
    LDI R31, 32 | (SYSEV_PRU0_TO_ARM_A - 16)
    QBBS    $run$exit, R31, 31

diff --git a/firmware/beaglelogic-pru0.c b/firmware/beaglelogic-pru0.c
index a5bfbce..0838090 100644
--- a/firmware/beaglelogic-pru0.c
+++ b/firmware/beaglelogic-pru0.c
@@ -59,6 +59,8 @@ struct capture_context {
    uint32_t sampleunit;    // 0 = 16-bit, 1 = 8-bit
    uint32_t triggerflags;  // 0 = one-shot, 1 = continuous sampling

+   uint32_t last_offset_written;
+
    bufferlist list[MAX_BUFLIST_ENTRIES];
 } cxt __attribute__((location(0))) = {0};

@@ -145,6 +147,7 @@ int main(void) {
        if (state_run == 1) {
            /* Clear all pending interrupts */
            CT_INTC.SECR0 = 0xFFFFFFFF;
+           cxt.last_offset_written = 0;

            resume_other_pru();
            run(&cxt, cxt.triggerflags);
diff --git a/kernel/beaglelogic.c b/kernel/beaglelogic.c
index a6f6867..05e1044 100644
--- a/kernel/beaglelogic.c
+++ b/kernel/beaglelogic.c
@@ -79,6 +79,8 @@ struct capture_context {
    uint32_t sampleunit;    // 0 = 16-bit, 1 = 8-bit
    uint32_t triggerflags;  // 0 = one-shot, 1 = continuous sampling

+   uint32_t last_offset_written;
+
    struct buflist list_head;
 };

@@ -451,18 +453,22 @@ irqreturn_t beaglelogic_serve_irq(int irqno, void *data)
    struct beaglelogicdev *bldev = data;
    struct device *dev = bldev->miscdev.this_device;
    uint32_t state = bldev->state;
+   uint32_t last_index_written = (bldev->cxt_pru->last_offset_written - offsetof(struct capture_context, list_head)) / 8;
+   struct logic_buffer *lastdone = &bldev->buffers[last_index_written];

    dev_dbg(dev, "Beaglelogic IRQ #%d\n", irqno);
    if (irqno == bldev->from_bl_irq_1) {
        /* Manage the buffers */
-       bldev->lastbufready = bldev->bufbeingread;
-       beaglelogic_unmap_buffer(dev, bldev->lastbufready);
-
-       /* Avoid a false buffer overrun warning on the last run */
-       if (bldev->triggerflags != BL_TRIGGERFLAGS_ONESHOT ||
-           bldev->bufbeingread->next->index != 0) {
-           bldev->bufbeingread = bldev->bufbeingread->next;
-           beaglelogic_map_buffer(dev, bldev->bufbeingread);
+       while (bldev->lastbufready != lastdone) {
+           bldev->lastbufready = bldev->bufbeingread;
+           beaglelogic_unmap_buffer(dev, bldev->lastbufready);
+
+           /* Avoid a false buffer overrun warning on the last run */
+           if (bldev->triggerflags != BL_TRIGGERFLAGS_ONESHOT ||
+               bldev->bufbeingread->next->index != 0) {
+               bldev->bufbeingread = bldev->bufbeingread->next;
+               beaglelogic_map_buffer(dev, bldev->bufbeingread);
+           }
        }
        wake_up_interruptible(&bldev->wait);
    } else if (irqno == bldev->from_bl_irq_2) {

Thanks, Alan

abhishek-kakkar commented 3 years ago

Thanks for the patch. I'll pass it on for inclusion in the 4.9 kernel release for BeagleBoard.org and make the change in the new kernel version release.

abhishek-kakkar commented 3 years ago

Will mark this fixed once the fix has been merged into BeagleBoard.org kernels.