diff --git a/src/add-ons/kernel/bus_managers/fdt/fdt_module.cpp b/src/add-ons/kernel/bus_managers/fdt/fdt_module.cpp index 95cca23f46..7ef6ac8e6d 100644 --- a/src/add-ons/kernel/bus_managers/fdt/fdt_module.cpp +++ b/src/add-ons/kernel/bus_managers/fdt/fdt_module.cpp @@ -2,7 +2,7 @@ * Copyright 2014, Ithamar R. Adema * All rights reserved. Distributed under the terms of the MIT License. * - * Copyright 2015-2021, Haiku, Inc. All rights reserved. + * Copyright 2015-2022, Haiku, Inc. All rights reserved. * Distributed under the terms of the MIT License. */ @@ -32,6 +32,15 @@ extern "C" { #endif +#define GIC_INTERRUPT_CELL_TYPE 0 +#define GIC_INTERRUPT_CELL_ID 1 +#define GIC_INTERRUPT_CELL_FLAGS 2 +#define GIC_INTERRUPT_TYPE_SPI 0 +#define GIC_INTERRUPT_TYPE_PPI 1 +#define GIC_INTERRUPT_BASE_SPI 32 +#define GIC_INTERRUPT_BASE_PPI 16 + + extern void* gFDT; device_manager_info* gDeviceManager; @@ -403,7 +412,7 @@ fdt_get_interrupt_cells(uint32 interrupt_parent_phandle) static bool -fdt_device_get_interrupt(fdt_device* dev, uint32 ord, +fdt_device_get_interrupt(fdt_device* dev, uint32 index, device_node** interruptController, uint64* interrupt) { ASSERT(dev != NULL); @@ -413,29 +422,39 @@ fdt_device_get_interrupt(fdt_device* dev, uint32 ord, dev->node, "fdt/node", &fdtNode, false) >= B_OK); int propLen; - const void* prop = fdt_getprop(gFDT, (int)fdtNode, "interrupts-extended", + const uint32 *prop = (uint32*)fdt_getprop(gFDT, (int)fdtNode, "interrupts-extended", &propLen); if (prop == NULL) { uint32 interruptParent = fdt_get_interrupt_parent(dev, fdtNode); uint32 interruptCells = fdt_get_interrupt_cells(interruptParent); - prop = fdt_getprop(gFDT, (int)fdtNode, "interrupts", + prop = (uint32*)fdt_getprop(gFDT, (int)fdtNode, "interrupts", &propLen); if (prop == NULL) return false; - if ((ord + 1) * interruptCells * sizeof(uint32) > (uint32)propLen) + if ((index + 1) * interruptCells * sizeof(uint32) > (uint32)propLen) return false; - uint32 offs; - if (interruptCells == 3) { - offs = 3 * ord + 1; + uint32 offset = interruptCells * index; + uint32 interruptNumber = 0; + + if ((interruptCells == 1) || (interruptCells == 2)) { + interruptNumber = fdt32_to_cpu(*(prop + offset)); + } else if (interruptCells == 3) { + uint32 interruptType = fdt32_to_cpu(prop[offset + GIC_INTERRUPT_CELL_TYPE]); + interruptNumber = fdt32_to_cpu(prop[offset + GIC_INTERRUPT_CELL_ID]); + + if (interruptType == GIC_INTERRUPT_TYPE_SPI) + interruptNumber += GIC_INTERRUPT_BASE_SPI; + else if (interruptType == GIC_INTERRUPT_TYPE_PPI) + interruptNumber += GIC_INTERRUPT_BASE_PPI; } else { - offs = interruptCells * ord; + panic("unsupported interruptCells"); } if (interrupt != NULL) - *interrupt = fdt32_to_cpu(*(((uint32*)prop) + offs)); + *interrupt = interruptNumber; if (interruptController != NULL && interruptParent != 0) { fdt_bus* bus; @@ -446,11 +465,11 @@ fdt_device_get_interrupt(fdt_device* dev, uint32 ord, return true; } - if ((ord + 1) * 8 > (uint32)propLen) + if ((index + 1) * 8 > (uint32)propLen) return false; if (interruptController != NULL) { - uint32 phandle = fdt32_to_cpu(*(((uint32*)prop) + 2 * ord)); + uint32 phandle = fdt32_to_cpu(*(prop + 2 * index)); fdt_bus* bus; ASSERT(gDeviceManager->get_driver( @@ -460,7 +479,7 @@ fdt_device_get_interrupt(fdt_device* dev, uint32 ord, } if (interrupt != NULL) - *interrupt = fdt32_to_cpu(*(((uint32*)prop) + 2*ord + 1)); + *interrupt = fdt32_to_cpu(*(prop + 2 * index + 1)); return true; } diff --git a/src/system/boot/platform/efi/dtb.cpp b/src/system/boot/platform/efi/dtb.cpp index 0d4f853d8a..92d63a3270 100644 --- a/src/system/boot/platform/efi/dtb.cpp +++ b/src/system/boot/platform/efi/dtb.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2019-2020 Haiku, Inc. All rights reserved. + * Copyright 2019-2022 Haiku, Inc. All rights reserved. * Distributed under the terms of the MIT License. * * Authors: @@ -40,6 +40,15 @@ extern "C" { #include "serial.h" +#define GIC_INTERRUPT_CELL_TYPE 0 +#define GIC_INTERRUPT_CELL_ID 1 +#define GIC_INTERRUPT_CELL_FLAGS 2 +#define GIC_INTERRUPT_TYPE_SPI 0 +#define GIC_INTERRUPT_TYPE_PPI 1 +#define GIC_INTERRUPT_BASE_SPI 32 +#define GIC_INTERRUPT_BASE_PPI 16 + + #define INFO(x...) dprintf("efi/fdt: " x) #define ERROR(x...) dprintf("efi/fdt: " x) @@ -455,10 +464,19 @@ dtb_get_interrupt(const void* fdt, int node) return fdt32_to_cpu(*(prop + 1)); } if (uint32* prop = (uint32*)fdt_getprop(fdt, node, "interrupts", NULL)) { - if (interruptCells == 3) { - return fdt32_to_cpu(*(prop + 1)); - } else { + if ((interruptCells == 1) || (interruptCells == 2)) { return fdt32_to_cpu(*prop); + } else if (interruptCells == 3) { + uint32 interruptType = fdt32_to_cpu(prop[GIC_INTERRUPT_CELL_TYPE]); + uint32 interruptNumber = fdt32_to_cpu(prop[GIC_INTERRUPT_CELL_ID]); + if (interruptType == GIC_INTERRUPT_TYPE_SPI) + interruptNumber += GIC_INTERRUPT_BASE_SPI; + else if (interruptType == GIC_INTERRUPT_TYPE_PPI) + interruptNumber += GIC_INTERRUPT_BASE_PPI; + + return interruptNumber; + } else { + panic("unsupported interruptCells"); } } dprintf("[!] no interrupt field\n"); diff --git a/src/system/kernel/arch/arm/arch_int_gicv2.cpp b/src/system/kernel/arch/arm/arch_int_gicv2.cpp index 142bd42511..ed0e197ea7 100644 --- a/src/system/kernel/arch/arm/arch_int_gicv2.cpp +++ b/src/system/kernel/arch/arm/arch_int_gicv2.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2021 Haiku, Inc. All rights reserved. + * Copyright 2021-2022 Haiku, Inc. All rights reserved. * Distributed under the terms of the MIT License. */ #include @@ -10,8 +10,6 @@ #include "arch_int_gicv2.h" #include "gicv2_regs.h" -#define GIC_SPI_IRQ_START 32 - GICv2InterruptController::GICv2InterruptController(uint32_t gicd_addr, uint32_t gicc_addr) : InterruptController() @@ -56,8 +54,6 @@ GICv2InterruptController::GICv2InterruptController(uint32_t gicd_addr, uint32_t void GICv2InterruptController::EnableInterrupt(int irq) { - irq += GIC_SPI_IRQ_START; - uint32_t ena_reg = GICD_REG_ISENABLER + irq / 32; uint32_t ena_val = 1 << (irq % 32); fGicdRegs[ena_reg] = ena_val; @@ -71,7 +67,6 @@ void GICv2InterruptController::EnableInterrupt(int irq) void GICv2InterruptController::DisableInterrupt(int irq) { - irq += GIC_SPI_IRQ_START; fGicdRegs[GICD_REG_ICENABLER + irq / 32] = 1 << (irq % 32); } @@ -83,7 +78,7 @@ void GICv2InterruptController::HandleInterrupt() if ((irqnr == 1022) || (irqnr == 1023)) { dprintf("spurious interrupt\n"); } else { - int_io_interrupt_handler(irqnr-GIC_SPI_IRQ_START, true); + int_io_interrupt_handler(irqnr, true); } fGiccRegs[GICC_REG_EOIR] = iar; diff --git a/src/system/kernel/arch/arm64/arch_int.cpp b/src/system/kernel/arch/arm64/arch_int.cpp index fcfd3922a6..20b718ac4c 100644 --- a/src/system/kernel/arch/arm64/arch_int.cpp +++ b/src/system/kernel/arch/arm64/arch_int.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2019 Haiku, Inc. All Rights Reserved. + * Copyright 2019-2022 Haiku, Inc. All Rights Reserved. * Distributed under the terms of the MIT License. */ #include @@ -56,6 +56,7 @@ arch_int_assign_to_cpu(int32 irq, int32 cpu) status_t arch_int_init(kernel_args *args) { + reserve_io_interrupt_vectors(128, 32, INTERRUPT_TYPE_IRQ); return B_OK; }