arm: move SPI interrupt offset calculation to FDT code
Most common values for interrupt-cells are 1 or 2. - one cell: the single cell defines the index of the interrupt within the controller. - two cells: the first cell defines the index of the interrupt within the controller, while the second cell is specifies interrupt flags like active-high/active-low, edge triggered or level-sensitive. ARM Generic Interrupt Controller uses 3 cells: - the 1st cell is the interrupt type: 0 for SPI, 1 for PPI - the 2nd cell contains the interrupt number - the 3rd cell contains interrupt flags, similarly to the 2-cell format SPI interrupts are numbered from 0 in the device tree but they start from 32 on the GIC so an offset should be applied. On the other hand, ACPI tables contain interrupt numbers as they are expected by the GIC so no offset should be applied when interrupts are read from ACPI. see: https://www.kernel.org/doc/Documentation/devicetree/bindings/interrupt-controller/interrupts.txt https://www.kernel.org/doc/Documentation/devicetree/bindings/interrupt-controller/arm%2Cgic.txt https://developer.arm.com/documentation/198123/0301/Arm-CoreLink-GIC-fundamentals Change-Id: Ia41371bd965347f89c17d62e391480d7b2083bae Reviewed-on: https://review.haiku-os.org/c/haiku/+/5490 Tested-by: Commit checker robot <[email protected]> Reviewed-by: Adrien Destugues <[email protected]>
This commit is contained in:
committed by
Adrien Destugues
parent
1a61e82bd4
commit
6a1f97581f
@@ -2,7 +2,7 @@
|
||||
* Copyright 2014, Ithamar R. Adema <[email protected]>
|
||||
* 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;
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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 <int.h>
|
||||
@@ -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;
|
||||
|
||||
@@ -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 <int.h>
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user