GPIO not forwarding interrupt to PLIC

I’m trying to set up an isr for a simple pushbutton, not using the metal bsp, but configuring the registers.
This is what I’m doing:

   int main(){
        int rc;

        set_freq_320MHz();
        interrupt_enable();
        plic_interrupt_enable();

        GPIO_REG(GPIO_OUTPUT_EN) |= (1 << variant_pin_map[3].bit_pos);
        GPIO_REG(GPIO_INPUT_EN)  |= (1 << variant_pin_map[PIN].bit_pos);

        unsigned int gpio = variant_pin_map[PIN].bit_pos;


        irq_functions[gpio + IRQ_GPIO - 1].active = 1;
        irq_functions[gpio + IRQ_GPIO - 1].priority = 7;
        irq_functions[gpio + IRQ_GPIO - 1].irq_handler = handler;

        PLIC_REG(PLIC_ENABLE_OFFSET) |= (1 << (IRQ_GPIO + gpio));
        PLIC_REG(PLIC_PRIORITY_OFFSET + 4 * (IRQ_GPIO + gpio)) = 7;
    	GPIO_REG(GPIO_FALL_IE) |= (1 << gpio);


        while (1)
        {
        	if(taken)
        	{
        		GPIO_REG(GPIO_OUTPUT_VAL) ^= (1 << variant_pin_map[3].bit_pos);
        		taken = 0;
        	}
        	wait_timer();
        }

        return 0;
    }
        void handler()
        {
            PLIC_REG(PLIC_ENABLE_OFFSET) &= ~(1 << (IRQ_GPIO + 23));
        	taken = GPIO_REG(GPIO_FALL_IP);
        	GPIO_REG(GPIO_FALL_IP) = taken;
            PLIC_REG(PLIC_ENABLE_OFFSET) |= (1 << (IRQ_GPIO + 23));
        }

The problem is that the GPIO correctly forwards the interrupt to the PLIC (and the plic to the hart) only the first time. I’ve checked every register possible: they are the same before and after the interrupt is correctly handled. The full project is here: Sifive_HiFive_RevB_Projects/src at master · NicolaGiardino/Sifive_HiFive_RevB_Projects · GitHub

This is what I’m doing in the handler:

  • Check mcause
  • Pass the control to the PLIC handler (Base mode, not vectored)
  • Claim the interrupt
  • Executing handling function (handler())
  • mret

Hi Nicola,

I don’t see the interrupt function attribute for the handler() function. This interrupt function attribute allows the compiler to generate interrupt handler entry/exit sequences.

https://gcc.gnu.org/onlinedocs/gcc/RISC-V-Function-Attributes.html

If you’re talking about the one for the handler whose address goes into mtvec, it’s in a separate header, with the attributes aligned(64) and interrupt
The problem is that on the first push the interrupt is handled, while on the second gpio.fall_ip is enabled, but the relative ip register bit in plic is not, so mip is not set and mcause is not updated.
I’ve tried setting up a timer interrupt, and it works well, so the problem is with the plic

Hi Nicola,

I see the interrupt function attribute now and it looks good.

Can you provide more information about the machine state including GPIO, PLIC, mstatus, mie, mip CSR’s at the time that you are expecting a GPIO interrupt and not receiving one?

I’d like to confirm that there is an interrupt pending at the GPIO and trace the path of the interrupt to understand why it’s not propagating to the core.

Sorry, I forgot to update the thread. I do not understand how it’s possible, but apparently I deleted the debug folder, recompiled everything, and it just started working. I noticed inconsistencies in the assembly code while debugging. I added the lines for the claim/complete on the PLIC, but they weren’t in the Disassembly section while debugging.
Very strange bug, I’ve never seen something like that before

Thanks for the update Nicola.

It seems like the issue may have been build related? You may want to review any errors or warnings that are generated while building.

If the error is reproduceable again please let us know and we may want to check the build logs.