* [PATCH v2 1/4] ACPI/IORT: Look up IORT node through struct fwnode_handle pointer
2017-10-13 7:09 [PATCH v2 0/4] IORT SMMUv3 MSI support Hanjun Guo
@ 2017-10-13 7:09 ` Hanjun Guo
2017-10-13 7:09 ` [PATCH v2 2/4] ACPI/IORT: Enable special index ITS group mappings for IORT nodes Hanjun Guo
` (2 subsequent siblings)
3 siblings, 0 replies; 7+ messages in thread
From: Hanjun Guo @ 2017-10-13 7:09 UTC (permalink / raw)
To: Lorenzo Pieralisi, Robin Murphy
Cc: Marc Zyngier, Rafael J. Wysocki, linux-acpi, linux-arm-kernel,
linuxarm, Hanjun Guo
From: Hanjun Guo <hanjun.guo@linaro.org>
Current IORT code provides a function (ie iort_get_fwnode())
which looks up a struct fwnode_handle pointer through a
struct acpi_iort_node pointer for SMMU components but it
lacks a function that implements the reverse look-up, namely
struct fwnode_handle* -> struct acpi_iort_node*.
Devices that are not IORT named components cannot be retrieved through
their associated IORT named component scan interface because they just
are not represented in the ACPI namespace; the reverse look-up is
therefore required for all platform devices that represent IORT nodes
(eg SMMUs) so that the struct acpi_iort_node* can be retrieved from the
struct device->fwnode pointer.
Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
[lorenzo.pieralisi@arm.com: re-indented/rewrote the commit log]
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
---
drivers/acpi/arm64/iort.c | 43 ++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 42 insertions(+), 1 deletion(-)
diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index 0ff7020..03d3dd2 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -126,6 +126,31 @@ static inline void iort_delete_fwnode(struct acpi_iort_node *node)
spin_unlock(&iort_fwnode_lock);
}
+/**
+ * iort_get_iort_node() - Retrieve iort_node associated with an fwnode
+ *
+ * @fwnode: fwnode associated with device to be looked-up
+ *
+ * Returns: iort_node pointer on success, NULL on failure
+ */
+static inline struct acpi_iort_node *iort_get_iort_node(
+ struct fwnode_handle *fwnode)
+{
+ struct iort_fwnode *curr;
+ struct acpi_iort_node *iort_node = NULL;
+
+ spin_lock(&iort_fwnode_lock);
+ list_for_each_entry(curr, &iort_fwnode_list, list) {
+ if (curr->fwnode == fwnode) {
+ iort_node = curr->iort_node;
+ break;
+ }
+ }
+ spin_unlock(&iort_fwnode_lock);
+
+ return iort_node;
+}
+
typedef acpi_status (*iort_find_node_callback)
(struct acpi_iort_node *node, void *context);
@@ -422,9 +447,25 @@ static struct acpi_iort_node *iort_find_dev_node(struct device *dev)
{
struct pci_bus *pbus;
- if (!dev_is_pci(dev))
+ if (!dev_is_pci(dev)) {
+ struct acpi_iort_node *node;
+ /*
+ * scan iort_fwnode_list to see if it's an iort platform
+ * device (such as SMMU, PMCG),its iort node already cached
+ * and associated with fwnode when iort platform devices
+ * were initialized.
+ */
+ node = iort_get_iort_node(dev->fwnode);
+ if (node)
+ return node;
+
+ /*
+ * if not, then it should be a platform device defined in
+ * DSDT/SSDT (with Named Component node in IORT)
+ */
return iort_scan_node(ACPI_IORT_NODE_NAMED_COMPONENT,
iort_match_node_callback, dev);
+ }
/* Find a PCI root bus */
pbus = to_pci_dev(dev)->bus;
--
1.7.12.4
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH v2 2/4] ACPI/IORT: Enable special index ITS group mappings for IORT nodes
2017-10-13 7:09 [PATCH v2 0/4] IORT SMMUv3 MSI support Hanjun Guo
2017-10-13 7:09 ` [PATCH v2 1/4] ACPI/IORT: Look up IORT node through struct fwnode_handle pointer Hanjun Guo
@ 2017-10-13 7:09 ` Hanjun Guo
2017-10-13 7:09 ` [PATCH v2 3/4] ACPI/IORT: Add SMMUv3 specific special index mapping handling Hanjun Guo
2017-10-13 7:09 ` [PATCH v2 4/4] ACPI/IORT: Enable SMMUv3/PMCG IORT MSI domain set-up Hanjun Guo
3 siblings, 0 replies; 7+ messages in thread
From: Hanjun Guo @ 2017-10-13 7:09 UTC (permalink / raw)
To: Lorenzo Pieralisi, Robin Murphy
Cc: Marc Zyngier, Rafael J. Wysocki, linux-acpi, linux-arm-kernel,
linuxarm, Hanjun Guo
From: Hanjun Guo <hanjun.guo@linaro.org>
IORT revision C introduced SMMUv3 and PMCG MSI support by adding
specific mapping entries in the SMMUv3/PMCG subtables to retrieve
the device ID and the ITS group it maps to for a given SMMUv3/PMCG
IORT node.
Introduce a mapping function (ie iort_get_id_mapping_index()), that
for a given IORT node looks up if an ITS specific ID mapping entry
exists and if so retrieve the corresponding mapping index in the IORT
node mapping array.
Since an ITS specific index mapping can be present for an IORT
node that is not a leaf node (eg SMMUv3 - to describe its own
ITS device ID) special handling is required for two steps mapping
cases such as PCI/NamedComponent--->SMMUv3--->ITS because the SMMUv3
ITS specific index mapping entry should be skipped to prevent the
IORT API from considering the mapping entry as a regular mapping one.
If we take the following IORT topology example:
|----------------------|
| Root Complex Node |
|----------------------|
| map entry[x] |
|----------------------|
| id value |
| output_reference |
|---|------------------|
|
| |----------------------|
|-->| SMMUv3 |
|----------------------|
| SMMUv3 dev ID |
| mapping index 0 |
|----------------------|
| map entry[0] |
|----------------------|
| id value |
| output_reference-----------> ITS 1 (SMMU MSI domain)
|----------------------|
| map entry[1] |
|----------------------|
| id value |
| output_reference-----------> ITS 2 (PCI MSI domain)
|----------------------|
where the SMMUv3 ITS specific mapping entry is index 0 and it
represents the SMMUv3 ITS specific index mapping entry (describing its
own ITS device ID), we need to skip that mapping entry while carrying
out the Root Complex Node regular mappings to prevent erroneous
translations.
Reuse the iort_get_id_mapping_index() function to detect the ITS
specific mapping index for a specific IORT node and skip it in the IORT
mapping API (ie iort_node_map_id()) loop to prevent considering it a
normal PCI/Named Component ID mapping entry.
Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
[lorenzo.pieralisi@arm.com: split patch/rewrote commit log]
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
---
drivers/acpi/arm64/iort.c | 32 ++++++++++++++++++++++++++++----
1 file changed, 28 insertions(+), 4 deletions(-)
diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index 03d3dd2..c3f3ac3 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -365,6 +365,11 @@ static struct acpi_iort_node *iort_node_get_id(struct acpi_iort_node *node,
return NULL;
}
+static inline int iort_get_id_mapping_index(struct acpi_iort_node *node)
+{
+ return -EINVAL;
+}
+
static struct acpi_iort_node *iort_node_map_id(struct acpi_iort_node *node,
u32 id_in, u32 *id_out,
u8 type_mask)
@@ -374,7 +379,7 @@ 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, index;
if (IORT_TYPE_MASK(node->type) & type_mask) {
if (id_out)
@@ -395,8 +400,19 @@ static struct acpi_iort_node *iort_node_map_id(struct acpi_iort_node *node,
goto fail_map;
}
+ /*
+ * Get the special ID mapping index (if any) and skip its
+ * associated ID map to prevent erroneous multi-stage
+ * IORT ID translations.
+ */
+ index = iort_get_id_mapping_index(node);
+
/* Do the ID translation */
for (i = 0; i < node->mapping_count; i++, map++) {
+ /* if it is special mapping index, skip it */
+ if (i == index)
+ continue;
+
if (!iort_id_map(map, node->type, id, &id))
break;
}
@@ -505,16 +521,24 @@ u32 iort_msi_map_rid(struct device *dev, u32 req_id)
*/
int iort_pmsi_get_dev_id(struct device *dev, u32 *dev_id)
{
- int i;
+ int i, index;
struct acpi_iort_node *node;
node = iort_find_dev_node(dev);
if (!node)
return -ENODEV;
- for (i = 0; i < node->mapping_count; i++) {
- if (iort_node_map_platform_id(node, dev_id, IORT_MSI_TYPE, i))
+ index = iort_get_id_mapping_index(node);
+ /* if there is a valid index, go get the dev_id directly */
+ if (index >= 0) {
+ if (iort_node_get_id(node, dev_id, index))
return 0;
+ } else {
+ for (i = 0; i < node->mapping_count; i++) {
+ if (iort_node_map_platform_id(node, dev_id,
+ IORT_MSI_TYPE, i))
+ return 0;
+ }
}
return -ENODEV;
--
1.7.12.4
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH v2 3/4] ACPI/IORT: Add SMMUv3 specific special index mapping handling
2017-10-13 7:09 [PATCH v2 0/4] IORT SMMUv3 MSI support Hanjun Guo
2017-10-13 7:09 ` [PATCH v2 1/4] ACPI/IORT: Look up IORT node through struct fwnode_handle pointer Hanjun Guo
2017-10-13 7:09 ` [PATCH v2 2/4] ACPI/IORT: Enable special index ITS group mappings for IORT nodes Hanjun Guo
@ 2017-10-13 7:09 ` Hanjun Guo
2017-10-13 13:04 ` Lorenzo Pieralisi
2017-10-13 7:09 ` [PATCH v2 4/4] ACPI/IORT: Enable SMMUv3/PMCG IORT MSI domain set-up Hanjun Guo
3 siblings, 1 reply; 7+ messages in thread
From: Hanjun Guo @ 2017-10-13 7:09 UTC (permalink / raw)
To: Lorenzo Pieralisi, Robin Murphy
Cc: Marc Zyngier, Rafael J. Wysocki, linux-acpi, linux-arm-kernel,
linuxarm, Hanjun Guo
From: Hanjun Guo <hanjun.guo@linaro.org>
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: split the patch, rewrote the log]
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
---
drivers/acpi/arm64/iort.c | 39 ++++++++++++++++++++++++++++++++++++++-
1 file changed, 38 insertions(+), 1 deletion(-)
diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index c3f3ac3..ca5dd21 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 introdueced 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,
--
1.7.12.4
^ permalink raw reply related [flat|nested] 7+ messages in thread* Re: [PATCH v2 3/4] ACPI/IORT: Add SMMUv3 specific special index mapping handling
2017-10-13 7:09 ` [PATCH v2 3/4] ACPI/IORT: Add SMMUv3 specific special index mapping handling Hanjun Guo
@ 2017-10-13 13:04 ` Lorenzo Pieralisi
2017-10-13 12:59 ` Rafael J. Wysocki
0 siblings, 1 reply; 7+ messages in thread
From: Lorenzo Pieralisi @ 2017-10-13 13:04 UTC (permalink / raw)
To: Hanjun Guo, Rafael J. Wysocki, Robert Moore
Cc: Robin Murphy, Marc Zyngier, linux-acpi, linux-arm-kernel,
linuxarm, Hanjun Guo, will.deacon
[+Robert, Will]
Rafael, Robert,
On Fri, Oct 13, 2017 at 03:09:49PM +0800, Hanjun Guo wrote:
[...]
> +#if (ACPI_CA_VERSION > 0x20170929)
Any objection to handling 4.15 trees dependency by using ACPICA
version as a temporary guard (that I will promptly remove at -rc1) ?
This series will go via arm64 tree and I see no other obvious way of
handling the dependency with ACPICA, unless I can send an ACPI IORT pull
request to Rafael and ACPICA changes go via Rafael's tree too.
Please let me know, I would like to send the pull request to arm64
shortly.
Thanks,
Lorenzo
> +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 introdueced 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,
> --
> 1.7.12.4
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 7+ messages in thread* Re: [PATCH v2 3/4] ACPI/IORT: Add SMMUv3 specific special index mapping handling
2017-10-13 13:04 ` Lorenzo Pieralisi
@ 2017-10-13 12:59 ` Rafael J. Wysocki
0 siblings, 0 replies; 7+ messages in thread
From: Rafael J. Wysocki @ 2017-10-13 12:59 UTC (permalink / raw)
To: Lorenzo Pieralisi
Cc: Hanjun Guo, Rafael J. Wysocki, Robert Moore, Robin Murphy,
Marc Zyngier, linux-acpi, linux-arm-kernel, linuxarm, Hanjun Guo,
will.deacon
On Friday, October 13, 2017 3:04:45 PM CEST Lorenzo Pieralisi wrote:
> [+Robert, Will]
>
> Rafael, Robert,
>
> On Fri, Oct 13, 2017 at 03:09:49PM +0800, Hanjun Guo wrote:
>
> [...]
>
> > +#if (ACPI_CA_VERSION > 0x20170929)
>
> Any objection to handling 4.15 trees dependency by using ACPICA
> version as a temporary guard (that I will promptly remove at -rc1) ?
Well, fine by me, as long as you take care of dropping this going forward.
Thanks,
Rafael
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v2 4/4] ACPI/IORT: Enable SMMUv3/PMCG IORT MSI domain set-up
2017-10-13 7:09 [PATCH v2 0/4] IORT SMMUv3 MSI support Hanjun Guo
` (2 preceding siblings ...)
2017-10-13 7:09 ` [PATCH v2 3/4] ACPI/IORT: Add SMMUv3 specific special index mapping handling Hanjun Guo
@ 2017-10-13 7:09 ` Hanjun Guo
3 siblings, 0 replies; 7+ messages in thread
From: Hanjun Guo @ 2017-10-13 7:09 UTC (permalink / raw)
To: Lorenzo Pieralisi, Robin Murphy
Cc: Marc Zyngier, Rafael J. Wysocki, linux-acpi, linux-arm-kernel,
linuxarm, Hanjun Guo
From: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
ITS specific mappings for SMMUv3/PMCG components can be retrieved
through special index mapping entries introduced in IORT revision C.
Introduce a new API iort_set_device_domain() to set the MSI domain for
SMMUv3/PMCG nodes (extendable to any future IORT node requiring special
index ITS mapping entries) that represent MSI through special index
mappings in order to enable MSI support for the devices their nodes
represent.
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
---
drivers/acpi/arm64/iort.c | 45 +++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 45 insertions(+)
diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index ca5dd21..373c58f 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -638,6 +638,49 @@ struct irq_domain *iort_get_device_domain(struct device *dev, u32 req_id)
return irq_find_matching_fwnode(handle, DOMAIN_BUS_PCI_MSI);
}
+static void iort_set_device_domain(struct device *dev,
+ struct acpi_iort_node *node)
+{
+ struct acpi_iort_its_group *its;
+ struct acpi_iort_node *msi_parent;
+ struct acpi_iort_id_mapping *map;
+ struct fwnode_handle *iort_fwnode;
+ struct irq_domain *domain;
+ int index;
+
+ index = iort_get_id_mapping_index(node);
+ if (index < 0)
+ return;
+
+ map = ACPI_ADD_PTR(struct acpi_iort_id_mapping, node,
+ node->mapping_offset + index * sizeof(*map));
+
+ /* Firmware bug! */
+ if (!map->output_reference ||
+ !(map->flags & ACPI_IORT_ID_SINGLE_MAPPING)) {
+ pr_err(FW_BUG "[node %p type %d] Invalid MSI mapping\n",
+ node, node->type);
+ return;
+ }
+
+ msi_parent = ACPI_ADD_PTR(struct acpi_iort_node, iort_table,
+ map->output_reference);
+
+ if (!msi_parent || msi_parent->type != ACPI_IORT_NODE_ITS_GROUP)
+ return;
+
+ /* Move to ITS specific data */
+ its = (struct acpi_iort_its_group *)msi_parent->node_data;
+
+ iort_fwnode = iort_find_domain_token(its->identifiers[0]);
+ if (!iort_fwnode)
+ return;
+
+ domain = irq_find_matching_fwnode(iort_fwnode, DOMAIN_BUS_PLATFORM_MSI);
+ if (domain)
+ dev_set_msi_domain(dev, domain);
+}
+
/**
* iort_get_platform_device_domain() - Find MSI domain related to a
* platform device
@@ -1261,6 +1304,8 @@ static int __init iort_add_platform_device(struct acpi_iort_node *node,
/* Configure DMA for the page table walker */
acpi_dma_configure(&pdev->dev, attr);
+ iort_set_device_domain(&pdev->dev, node);
+
ret = platform_device_add(pdev);
if (ret)
goto dma_deconfigure;
--
1.7.12.4
^ permalink raw reply related [flat|nested] 7+ messages in thread