summaryrefslogtreecommitdiff
path: root/sys/arch/arm64/stand/efiboot/efiacpi.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/arch/arm64/stand/efiboot/efiacpi.c')
-rw-r--r--sys/arch/arm64/stand/efiboot/efiacpi.c36
1 files changed, 33 insertions, 3 deletions
diff --git a/sys/arch/arm64/stand/efiboot/efiacpi.c b/sys/arch/arm64/stand/efiboot/efiacpi.c
index 889b6f430d0..6f593cba8e8 100644
--- a/sys/arch/arm64/stand/efiboot/efiacpi.c
+++ b/sys/arch/arm64/stand/efiboot/efiacpi.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: efiacpi.c,v 1.16 2023/10/09 22:05:27 patrick Exp $ */
+/* $OpenBSD: efiacpi.c,v 1.17 2024/06/23 15:37:31 kettenis Exp $ */
/*
* Copyright (c) 2018 Mark Kettenis <kettenis@openbsd.org>
@@ -402,7 +402,8 @@ static int gic_version;
static uint64_t gicc_base;
static uint64_t gicd_base;
static uint64_t gicr_base;
-static uint32_t gicr_size;
+static uint64_t gicr_size;
+static uint64_t gicr_stride;
void
efi_acpi_madt_gicc(struct acpi_madt_gicc *gicc)
@@ -436,6 +437,30 @@ efi_acpi_madt_gicc(struct acpi_madt_gicc *gicc)
/* Stash GIC information. */
gicc_base = gicc->base_address;
+
+ /*
+ * The redistributor base address may be specified per-CPU.
+ * In that case we will need to reconstruct the base, size and
+ * stride to use for the redistributor registers.
+ */
+ if (gicc->gicr_base_address > 0) {
+ if (gicr_base > 0) {
+ uint32_t size;
+
+ if (gicc->gicr_base_address < gicr_base)
+ size = gicr_base - gicc->gicr_base_address;
+ else
+ size = gicc->gicr_base_address - gicr_base;
+ if (gicr_stride == 0 || size < gicr_stride)
+ gicr_stride = size;
+ if (gicr_size == 0 || size > gicr_size)
+ gicr_size = size;
+ gicr_base = MIN(gicr_base, gicc->gicr_base_address);
+ } else {
+ gicr_base = gicc->gicr_base_address;
+ gicr_size = 0x20000;
+ }
+ }
}
void
@@ -579,7 +604,7 @@ efi_acpi_madt(struct acpi_table_header *hdr)
reg[0] = htobe64(gicd_base);
reg[1] = htobe64(0x10000);
reg[2] = htobe64(gicr_base);
- reg[3] = htobe64(gicr_size);
+ reg[3] = htobe64(gicr_size + gicr_stride);
break;
default:
return;
@@ -589,6 +614,11 @@ efi_acpi_madt(struct acpi_table_header *hdr)
node = fdt_find_node("/interrupt-controller");
fdt_node_set_string_property(node, "compatible", compat);
fdt_node_set_property(node, "reg", reg, sizeof(reg));
+ if (gicr_stride > 0) {
+ uint64_t stride = htobe64(gicr_stride);
+ fdt_node_add_property(node, "redistributor-stride",
+ &stride, sizeof(stride));
+ }
fdt_node_set_string_property(node, "status", "okay");
}