summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2025-04-03 11:38:22 -0600
committerTom Rini <trini@konsulko.com>2025-04-03 11:38:22 -0600
commit39ff722b3ee0bd569388a3b89c59899511ac1a24 (patch)
tree8c91ba9b78d75de37ed28661f53ca12df4223f49
parentccb38260542d42100c9eb29e3f3293d76e6a1f63 (diff)
parent636b62c265f8932f12b2fe1ce8b256868d16fbda (diff)
Merge patch series "acpi_table: Fix IORT RC node"
This series from Patrick Rudolph <patrick.rudolph@9elements.com> brings in an assortment of ACPI related fixes. Link: https://lore.kernel.org/r/20250316083300.2692377-1-patrick.rudolph@9elements.com
-rw-r--r--lib/acpi/acpi_table.c29
-rw-r--r--test/dm/acpigen.c115
2 files changed, 143 insertions, 1 deletions
diff --git a/lib/acpi/acpi_table.c b/lib/acpi/acpi_table.c
index c0ed24984af..4ad1f56e961 100644
--- a/lib/acpi/acpi_table.c
+++ b/lib/acpi/acpi_table.c
@@ -615,6 +615,7 @@ int acpi_iort_add_named_component(struct acpi_ctx *ctx,
node->length += strlen(device_name) + 1;
comp = (struct acpi_iort_named_component *)node->node_data;
+ memset(comp, '\0', sizeof(struct acpi_iort_named_component));
comp->node_flags = node_flags;
comp->memory_properties = memory_properties;
@@ -635,6 +636,7 @@ int acpi_iort_add_rc(struct acpi_ctx *ctx,
const struct acpi_iort_id_mapping *map)
{
struct acpi_iort_id_mapping *mapping;
+ struct acpi_iort_node *output_node;
struct acpi_iort_node *node;
struct acpi_iort_rc *rc;
int offset;
@@ -646,12 +648,18 @@ int acpi_iort_add_rc(struct acpi_ctx *ctx,
node->type = ACPI_IORT_NODE_PCI_ROOT_COMPLEX;
node->revision = 2;
+ node->mapping_count = num_mappings;
+ if (num_mappings)
+ node->mapping_offset = sizeof(struct acpi_iort_node) +
+ sizeof(struct acpi_iort_rc);
node->length = sizeof(struct acpi_iort_node);
node->length += sizeof(struct acpi_iort_rc);
node->length += sizeof(struct acpi_iort_id_mapping) * num_mappings;
rc = (struct acpi_iort_rc *)node->node_data;
+ memset(rc, '\0', sizeof(struct acpi_iort_rc));
+
rc->mem_access_properties = mem_access_properties;
rc->ats_attributes = ats_attributes;
rc->pci_segment_number = pci_segment_number;
@@ -659,6 +667,13 @@ int acpi_iort_add_rc(struct acpi_ctx *ctx,
mapping = (struct acpi_iort_id_mapping *)(rc + 1);
for (int i = 0; i < num_mappings; i++) {
+ /* Validate input */
+ output_node = (struct acpi_iort_node *)ctx->tab_start + map[i].output_reference;
+ /* ID mappings can use SMMUs or ITS groups as output references */
+ assert(output_node && ((output_node->type == ACPI_IORT_NODE_ITS_GROUP) ||
+ (output_node->type == ACPI_IORT_NODE_SMMU) ||
+ (output_node->type == ACPI_IORT_NODE_SMMU_V3)));
+
memcpy(mapping, &map[i], sizeof(struct acpi_iort_id_mapping));
mapping++;
}
@@ -683,6 +698,7 @@ int acpi_iort_add_smmu_v3(struct acpi_ctx *ctx,
const struct acpi_iort_id_mapping *map)
{
struct acpi_iort_node *node;
+ struct acpi_iort_node *output_node;
struct acpi_iort_smmu_v3 *smmu;
struct acpi_iort_id_mapping *mapping;
int offset;
@@ -695,13 +711,16 @@ int acpi_iort_add_smmu_v3(struct acpi_ctx *ctx,
node->type = ACPI_IORT_NODE_SMMU_V3;
node->revision = 5;
node->mapping_count = num_mappings;
- node->mapping_offset = sizeof(struct acpi_iort_node) + sizeof(struct acpi_iort_smmu_v3);
+ if (num_mappings)
+ node->mapping_offset = sizeof(struct acpi_iort_node) +
+ sizeof(struct acpi_iort_smmu_v3);
node->length = sizeof(struct acpi_iort_node);
node->length += sizeof(struct acpi_iort_smmu_v3);
node->length += sizeof(struct acpi_iort_id_mapping) * num_mappings;
smmu = (struct acpi_iort_smmu_v3 *)node->node_data;
+ memset(smmu, '\0', sizeof(struct acpi_iort_smmu_v3));
smmu->base_address = base_address;
smmu->flags = flags;
@@ -716,6 +735,14 @@ int acpi_iort_add_smmu_v3(struct acpi_ctx *ctx,
mapping = (struct acpi_iort_id_mapping *)(smmu + 1);
for (int i = 0; i < num_mappings; i++) {
+ /* Validate input */
+ output_node = (struct acpi_iort_node *)ctx->tab_start + map[i].output_reference;
+ /*
+ * ID mappings of an SMMUv3 node can only have ITS group nodes
+ * as output references.
+ */
+ assert(output_node && output_node->type == ACPI_IORT_NODE_ITS_GROUP);
+
memcpy(mapping, &map[i], sizeof(struct acpi_iort_id_mapping));
mapping++;
}
diff --git a/test/dm/acpigen.c b/test/dm/acpigen.c
index 23c16bd9866..ee9517f9c29 100644
--- a/test/dm/acpigen.c
+++ b/test/dm/acpigen.c
@@ -1742,3 +1742,118 @@ static int dm_test_acpi_write_tsd_package(struct unit_test_state *uts)
return 0;
}
DM_TEST(dm_test_acpi_write_tsd_package, 0);
+
+static int dm_test_acpi_iort_smmu_v3(struct unit_test_state *uts)
+{
+ struct acpi_ctx *ctx;
+ int smmu_offset;
+ u8 *ptr;
+
+ ut_assertok(alloc_context(&ctx));
+ ctx->tab_start = ctx->current;
+ acpi_inc(ctx, sizeof(struct acpi_table_iort));
+
+ ptr = acpigen_get_current(ctx);
+
+ smmu_offset = acpi_iort_add_smmu_v3(ctx,
+ 0xaabbccddeeffULL, // Base address
+ 1, // Flags
+ 0xffeeddccaabbULL, // VATOS address
+ 0, // SMMUv3 Model
+ 3, // Event
+ 4, // Pri
+ 5, // Gerror
+ 6, // Sync
+ 7, // Proximity domain
+ 8, // DevIDMappingIndex
+ 0,
+ NULL);
+ ut_assert(smmu_offset);
+
+ ut_asserteq(ACPI_IORT_NODE_SMMU_V3, ptr[0]);
+ ut_asserteq(68, get_unaligned((u16 *)(ptr + 1)));
+ ut_asserteq(0, get_unaligned((u16 *)(ptr + 4)));
+ ut_asserteq(0, get_unaligned((u32 *)(ptr + 8)));
+ ut_asserteq(0, get_unaligned((u32 *)(ptr + 12)));
+
+ ut_asserteq_64(0xaabbccddeeffULL, get_unaligned((u64 *)(ptr + 16)));
+ ut_asserteq(1, get_unaligned((u32 *)(ptr + 24)));
+ ut_asserteq(0, get_unaligned((u32 *)(ptr + 28)));
+ ut_asserteq_64(0xffeeddccaabbULL, get_unaligned((u64 *)(ptr + 32)));
+ ut_asserteq(0, get_unaligned((u32 *)(ptr + 40)));
+ ut_asserteq(3, get_unaligned((u32 *)(ptr + 44)));
+ ut_asserteq(4, get_unaligned((u32 *)(ptr + 48)));
+ ut_asserteq(5, get_unaligned((u32 *)(ptr + 52)));
+ ut_asserteq(6, get_unaligned((u32 *)(ptr + 56)));
+ ut_asserteq(7, get_unaligned((u32 *)(ptr + 60)));
+ ut_asserteq(8, get_unaligned((u32 *)(ptr + 64)));
+
+ free_context(&ctx);
+
+ return 0;
+}
+DM_TEST(dm_test_acpi_iort_smmu_v3, 0);
+
+static int dm_test_acpi_iort_rc(struct unit_test_state *uts)
+{
+ struct acpi_ctx *ctx;
+ int its_group_offset, offset;
+ u8 *ptr;
+
+ ut_assertok(alloc_context(&ctx));
+ ctx->tab_start = ctx->current;
+ acpi_inc(ctx, sizeof(struct acpi_table_iort));
+
+ u32 identifiers[] = { 0 };
+
+ its_group_offset = acpi_iort_add_its_group(ctx, ARRAY_SIZE(identifiers),
+ identifiers);
+
+ ptr = acpigen_get_current(ctx);
+
+ struct acpi_iort_id_mapping map_rc[] = {
+ {0, 0xfff, 0, its_group_offset, 0},
+ {0x1000, 0xffff, 0x1000, its_group_offset, 0}
+ };
+
+ offset = acpi_iort_add_rc(ctx,
+ 0xaabbccddeeffULL, // Mem Access Properties
+ 2, // ATS attributes
+ 3, // PCI segment
+ 4, // Memory address size limit
+ ARRAY_SIZE(map_rc),
+ map_rc);
+
+ ut_assert(offset);
+ ut_asserteq(ACPI_IORT_NODE_PCI_ROOT_COMPLEX, ptr[0]);
+ ut_asserteq(36 + ARRAY_SIZE(map_rc) * sizeof(struct acpi_iort_id_mapping),
+ get_unaligned((u16 *)(ptr + 1)));
+ ut_asserteq(0, get_unaligned((u16 *)(ptr + 4)));
+ ut_asserteq(2, get_unaligned((u32 *)(ptr + 8)));
+ ut_asserteq(36, get_unaligned((u32 *)(ptr + 12)));
+
+ ut_asserteq_64(0xaabbccddeeffULL, get_unaligned((u64 *)(ptr + 16)));
+ ut_asserteq(2, get_unaligned((u32 *)(ptr + 24)));
+ ut_asserteq(3, get_unaligned((u32 *)(ptr + 28)));
+ ut_asserteq(4, ptr[32]);
+ ut_asserteq(0, ptr[33]);
+ ut_asserteq(0, ptr[34]);
+ ut_asserteq(0, ptr[35]);
+
+ ut_asserteq(0, get_unaligned((u32 *)(ptr + 36)));
+ ut_asserteq(0xfff, get_unaligned((u32 *)(ptr + 40)));
+ ut_asserteq(0, get_unaligned((u32 *)(ptr + 44)));
+ ut_asserteq(its_group_offset, get_unaligned((u32 *)(ptr + 48)));
+ ut_asserteq(0, get_unaligned((u32 *)(ptr + 52)));
+
+ ut_asserteq(0x1000, get_unaligned((u32 *)(ptr + 56)));
+ ut_asserteq(0xffff, get_unaligned((u32 *)(ptr + 60)));
+ ut_asserteq(0x1000, get_unaligned((u32 *)(ptr + 64)));
+ ut_asserteq(its_group_offset, get_unaligned((u32 *)(ptr + 68)));
+ ut_asserteq(0, get_unaligned((u32 *)(ptr + 72)));
+
+ free_context(&ctx);
+
+ return 0;
+}
+DM_TEST(dm_test_acpi_iort_rc, 0); \ No newline at end of file