summaryrefslogtreecommitdiffstats
path: root/drivers/acpi
diff options
context:
space:
mode:
authorHanjun Guo <hanjun.guo@linaro.org>2017-10-13 09:09:49 +0200
committerLorenzo Pieralisi <lorenzo.pieralisi@arm.com>2017-10-16 15:30:05 +0200
commit86456a3f19c505049341eeb51cf9bb874d3b4752 (patch)
treed8a7ab1653fbba1dd617d93f3ae197a2d5773908 /drivers/acpi
parentACPI/IORT: Enable special index ITS group mappings for IORT nodes (diff)
downloadlinux-86456a3f19c505049341eeb51cf9bb874d3b4752.tar.xz
linux-86456a3f19c505049341eeb51cf9bb874d3b4752.zip
ACPI/IORT: Add SMMUv3 specific special index mapping handling
IORT revision C introduced a mapping entry binding to describe ITS device ID mapping for SMMUv3 MSI interrupts. Enable the single mapping flag (ie that is used by SMMUv3 component for its special index mappings) for the SMMUv3 node in the IORT mapping API and add IORT code to handle special index mapping entry for the SMMUv3 IORT nodes to enable their MSI interrupts. In case the ACPICA for SMMUv3 device ID mapping is not ready, use the ACPICA version as a guard for function iort_get_id_mapping_index(). Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org> [lorenzo.pieralisi@arm.com: patch split, typos fixing, rewrote the log] Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Diffstat (limited to 'drivers/acpi')
-rw-r--r--drivers/acpi/arm64/iort.c39
1 files changed, 38 insertions, 1 deletions
diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index 55fbf645a777..3d7e3cd2eae8 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -356,7 +356,8 @@ static struct acpi_iort_node *iort_node_get_id(struct acpi_iort_node *node,
if (map->flags & ACPI_IORT_ID_SINGLE_MAPPING) {
if (node->type == ACPI_IORT_NODE_NAMED_COMPONENT ||
- node->type == ACPI_IORT_NODE_PCI_ROOT_COMPLEX) {
+ node->type == ACPI_IORT_NODE_PCI_ROOT_COMPLEX ||
+ node->type == ACPI_IORT_NODE_SMMU_V3) {
*id_out = map->output_base;
return parent;
}
@@ -365,10 +366,46 @@ static struct acpi_iort_node *iort_node_get_id(struct acpi_iort_node *node,
return NULL;
}
+#if (ACPI_CA_VERSION > 0x20170929)
+static int iort_get_id_mapping_index(struct acpi_iort_node *node)
+{
+ struct acpi_iort_smmu_v3 *smmu;
+
+ switch (node->type) {
+ case ACPI_IORT_NODE_SMMU_V3:
+ /*
+ * SMMUv3 dev ID mapping index was introduced in revision 1
+ * table, not available in revision 0
+ */
+ if (node->revision < 1)
+ return -EINVAL;
+
+ smmu = (struct acpi_iort_smmu_v3 *)node->node_data;
+ /*
+ * ID mapping index is only ignored if all interrupts are
+ * GSIV based
+ */
+ 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;
+ }
+
+ return smmu->id_mapping_index;
+ default:
+ return -EINVAL;
+ }
+}
+#else
static inline int iort_get_id_mapping_index(struct acpi_iort_node *node)
{
return -EINVAL;
}
+#endif
static struct acpi_iort_node *iort_node_map_id(struct acpi_iort_node *node,
u32 id_in, u32 *id_out,