@@ -366,6 +366,34 @@ struct acpi_iort_node *iort_node_get_id(struct acpi_iort_node *node,
return NULL;
}
+static int iort_get_smmu_v3_id_mapping_index(struct acpi_iort_node *node,
+ u32 *index)
+{
+ struct acpi_iort_smmu_v3 *smmu;
+
+ /*
+ * SMMUv3 dev ID mapping index was introdueced in revision 1
+ * table, not avaible in revision 0
+ */
+ if (node->revision < 1)
+ return -EINVAL;
+
+ smmu = (struct acpi_iort_smmu_v3 *)node->node_data;
+ /* if any of the gsi for control interrupts is not 0, ignore the MSI */
+ if (smmu->event_gsiv || smmu->pri_gsiv || smmu->gerr_gsiv
+ || smmu->sync_gsiv)
+ return -EINVAL;
+
+ if (smmu->id_mapping_index >= node->mapping_count) {
+ pr_err(FW_BUG "[node %p type %d] ID mapping index overflows valid mappings\n",
+ node, node->type);
+ return -EINVAL;
+ }
+
+ *index = smmu->id_mapping_index;
+ return 0;
+}
+
static struct acpi_iort_node *iort_node_map_id(struct acpi_iort_node *node,
u32 id_in, u32 *id_out,
u8 type_mask)
@@ -375,7 +403,9 @@ static struct acpi_iort_node *iort_node_map_id(struct acpi_iort_node *node,
/* Parse the ID mapping tree to find specified node type */
while (node) {
struct acpi_iort_id_mapping *map;
- int i;
+ int i, ret = -EINVAL;
+ /* big enough for an invalid id index in practical */
+ u32 index = U32_MAX;
if (IORT_TYPE_MASK(node->type) & type_mask) {
if (id_out)
@@ -396,8 +426,19 @@ static struct acpi_iort_node *iort_node_map_id(struct acpi_iort_node *node,
goto fail_map;
}
+ /*
+ * we need to get SMMUv3 dev ID mapping index and skip its
+ * associated ID map for single mapping cases.
+ */
+ if (node->type == ACPI_IORT_NODE_SMMU_V3)
+ ret = iort_get_smmu_v3_id_mapping_index(node, &index);
+
/* Do the ID translation */
for (i = 0; i < node->mapping_count; i++, map++) {
+ /* if it's a SMMUv3 device id mapping index, skip it */
+ if (!ret && i == index)
+ continue;
+
if (!iort_id_map(map, node->type, id, &id))
break;
}