* [PATCH v7 1/5] Doc: iommu/arm-smmu-v3: Add workaround for HiSilicon erratum 161010801
2017-09-14 12:57 [PATCH v7 0/5] iommu/smmu-v3: Workaround for hisilicon 161010801 erratum(reserve HW MSI) Shameer Kolothum
@ 2017-09-14 12:57 ` Shameer Kolothum
2017-09-19 14:53 ` Rob Herring
2017-09-14 12:57 ` [PATCH v7 2/5] ACPI/IORT: Add msi address regions reservation helper Shameer Kolothum
` (3 subsequent siblings)
4 siblings, 1 reply; 10+ messages in thread
From: Shameer Kolothum @ 2017-09-14 12:57 UTC (permalink / raw)
To: linux-arm-kernel
From: John Garry <john.garry@huawei.com>
The HiSilicon erratum 161010801 describes the limitation of HiSilicon platforms
hip06/hip07 to support the SMMU mappings for MSI transactions.
On these platforms, GICv3 ITS translator is presented with the deviceID
by extending the MSI payload data to 64 bits to include the deviceID.
Hence, the PCIe controller on this platforms has to differentiate the MSI
payload against other DMA payload and has to modify the MSI payload.
This basically makes it difficult for this platforms to have a SMMU
translation for MSI.
This patch adds a SMMUv3 binding to flag that the SMMU breaks msi
translation at ITS.
Also, the arm64 silicon errata is updated with this same erratum.
Signed-off-by: John Garry <john.garry@huawei.com>
Signed-off-by: Shameer Kolothum <shameerali.kolothum.thodi@huawei.com>
---
Documentation/arm64/silicon-errata.txt | 1 +
Documentation/devicetree/bindings/iommu/arm,smmu-v3.txt | 3 +++
2 files changed, 4 insertions(+)
diff --git a/Documentation/arm64/silicon-errata.txt b/Documentation/arm64/silicon-errata.txt
index 66e8ce1..02816b1 100644
--- a/Documentation/arm64/silicon-errata.txt
+++ b/Documentation/arm64/silicon-errata.txt
@@ -70,6 +70,7 @@ stable kernels.
| | | | |
| Hisilicon | Hip0{5,6,7} | #161010101 | HISILICON_ERRATUM_161010101 |
| Hisilicon | Hip0{6,7} | #161010701 | N/A |
+| Hisilicon | Hip0{6,7} | #161010801 | N/A |
| | | | |
| Qualcomm Tech. | Falkor v1 | E1003 | QCOM_FALKOR_ERRATUM_1003 |
| Qualcomm Tech. | Falkor v1 | E1009 | QCOM_FALKOR_ERRATUM_1009 |
diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu-v3.txt b/Documentation/devicetree/bindings/iommu/arm,smmu-v3.txt
index c9abbf3..1f5f7f9 100644
--- a/Documentation/devicetree/bindings/iommu/arm,smmu-v3.txt
+++ b/Documentation/devicetree/bindings/iommu/arm,smmu-v3.txt
@@ -55,6 +55,9 @@ the PCIe specification.
- hisilicon,broken-prefetch-cmd
: Avoid sending CMD_PREFETCH_* commands to the SMMU.
+- hisilicon,broken-untranslated-msi
+ : Reserve ITS HW region to avoid translating msi.
+
- cavium,cn9900-broken-page1-regspace
: Replaces all page 1 offsets used for EVTQ_PROD/CONS,
PRIQ_PROD/CONS register access with page 0 offsets.
--
1.9.1
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH v7 1/5] Doc: iommu/arm-smmu-v3: Add workaround for HiSilicon erratum 161010801
2017-09-14 12:57 ` [PATCH v7 1/5] Doc: iommu/arm-smmu-v3: Add workaround for HiSilicon erratum 161010801 Shameer Kolothum
@ 2017-09-19 14:53 ` Rob Herring
2017-09-19 16:09 ` Shameerali Kolothum Thodi
0 siblings, 1 reply; 10+ messages in thread
From: Rob Herring @ 2017-09-19 14:53 UTC (permalink / raw)
To: linux-arm-kernel
On Thu, Sep 14, 2017 at 01:57:52PM +0100, Shameer Kolothum wrote:
> From: John Garry <john.garry@huawei.com>
>
> The HiSilicon erratum 161010801 describes the limitation of HiSilicon platforms
> hip06/hip07 to support the SMMU mappings for MSI transactions.
>
> On these platforms, GICv3 ITS translator is presented with the deviceID
> by extending the MSI payload data to 64 bits to include the deviceID.
> Hence, the PCIe controller on this platforms has to differentiate the MSI
> payload against other DMA payload and has to modify the MSI payload.
> This basically makes it difficult for this platforms to have a SMMU
> translation for MSI.
>
> This patch adds a SMMUv3 binding to flag that the SMMU breaks msi
> translation at ITS.
>
> Also, the arm64 silicon errata is updated with this same erratum.
>
> Signed-off-by: John Garry <john.garry@huawei.com>
> Signed-off-by: Shameer Kolothum <shameerali.kolothum.thodi@huawei.com>
> ---
> Documentation/arm64/silicon-errata.txt | 1 +
> Documentation/devicetree/bindings/iommu/arm,smmu-v3.txt | 3 +++
> 2 files changed, 4 insertions(+)
>
> diff --git a/Documentation/arm64/silicon-errata.txt b/Documentation/arm64/silicon-errata.txt
> index 66e8ce1..02816b1 100644
> --- a/Documentation/arm64/silicon-errata.txt
> +++ b/Documentation/arm64/silicon-errata.txt
> @@ -70,6 +70,7 @@ stable kernels.
> | | | | |
> | Hisilicon | Hip0{5,6,7} | #161010101 | HISILICON_ERRATUM_161010101 |
> | Hisilicon | Hip0{6,7} | #161010701 | N/A |
> +| Hisilicon | Hip0{6,7} | #161010801 | N/A |
> | | | | |
> | Qualcomm Tech. | Falkor v1 | E1003 | QCOM_FALKOR_ERRATUM_1003 |
> | Qualcomm Tech. | Falkor v1 | E1009 | QCOM_FALKOR_ERRATUM_1009 |
> diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu-v3.txt b/Documentation/devicetree/bindings/iommu/arm,smmu-v3.txt
> index c9abbf3..1f5f7f9 100644
> --- a/Documentation/devicetree/bindings/iommu/arm,smmu-v3.txt
> +++ b/Documentation/devicetree/bindings/iommu/arm,smmu-v3.txt
> @@ -55,6 +55,9 @@ the PCIe specification.
> - hisilicon,broken-prefetch-cmd
> : Avoid sending CMD_PREFETCH_* commands to the SMMU.
>
> +- hisilicon,broken-untranslated-msi
> + : Reserve ITS HW region to avoid translating msi.
> +
This should be determined from the compatible string. Continuing to add
properties for each errata doesn't scale.
> - cavium,cn9900-broken-page1-regspace
> : Replaces all page 1 offsets used for EVTQ_PROD/CONS,
> PRIQ_PROD/CONS register access with page 0 offsets.
> --
> 1.9.1
>
>
> --
> To unsubscribe from this list: send the line "unsubscribe devicetree" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 10+ messages in thread* [PATCH v7 1/5] Doc: iommu/arm-smmu-v3: Add workaround for HiSilicon erratum 161010801
2017-09-19 14:53 ` Rob Herring
@ 2017-09-19 16:09 ` Shameerali Kolothum Thodi
0 siblings, 0 replies; 10+ messages in thread
From: Shameerali Kolothum Thodi @ 2017-09-19 16:09 UTC (permalink / raw)
To: linux-arm-kernel
> -----Original Message-----
> From: Rob Herring [mailto:robh at kernel.org]
> Sent: Tuesday, September 19, 2017 3:53 PM
> To: Shameerali Kolothum Thodi <shameerali.kolothum.thodi@huawei.com>
> Cc: lorenzo.pieralisi at arm.com; marc.zyngier at arm.com;
> sudeep.holla at arm.com; will.deacon at arm.com; robin.murphy at arm.com;
> joro at 8bytes.org; mark.rutland at arm.com; hanjun.guo at linaro.org; Gabriele
> Paoloni <gabriele.paoloni@huawei.com>; John Garry
> <john.garry@huawei.com>; iommu at lists.linux-foundation.org; linux-arm-
> kernel at lists.infradead.org; linux-acpi at vger.kernel.org;
> devicetree at vger.kernel.org; devel at acpica.org; Linuxarm
> <linuxarm@huawei.com>; Wangzhou (B) <wangzhou1@hisilicon.com>;
> Guohanjun (Hanjun Guo) <guohanjun@huawei.com>
> Subject: Re: [PATCH v7 1/5] Doc: iommu/arm-smmu-v3: Add workaround for
> HiSilicon erratum 161010801
>
> On Thu, Sep 14, 2017 at 01:57:52PM +0100, Shameer Kolothum wrote:
> > From: John Garry <john.garry@huawei.com>
> >
> > The HiSilicon erratum 161010801 describes the limitation of HiSilicon
> platforms
> > hip06/hip07 to support the SMMU mappings for MSI transactions.
> >
> > On these platforms, GICv3 ITS translator is presented with the deviceID
> > by extending the MSI payload data to 64 bits to include the deviceID.
> > Hence, the PCIe controller on this platforms has to differentiate the MSI
> > payload against other DMA payload and has to modify the MSI payload.
> > This basically makes it difficult for this platforms to have a SMMU
> > translation for MSI.
> >
> > This patch adds a SMMUv3 binding to flag that the SMMU breaks msi
> > translation at ITS.
> >
> > Also, the arm64 silicon errata is updated with this same erratum.
> >
> > Signed-off-by: John Garry <john.garry@huawei.com>
> > Signed-off-by: Shameer Kolothum
> <shameerali.kolothum.thodi@huawei.com>
[...]
> > --- a/Documentation/devicetree/bindings/iommu/arm,smmu-v3.txt
> > +++ b/Documentation/devicetree/bindings/iommu/arm,smmu-v3.txt
> > @@ -55,6 +55,9 @@ the PCIe specification.
> > - hisilicon,broken-prefetch-cmd
> > : Avoid sending CMD_PREFETCH_* commands to the SMMU.
> >
> > +- hisilicon,broken-untranslated-msi
> > + : Reserve ITS HW region to avoid translating msi.
> > +
>
> This should be determined from the compatible string. Continuing to add
> properties for each errata doesn't scale.
Ok. I think the suggestion here is to follow the arm-smmu.c (SMMUv1/v2)
driver way of implementing the errata. As you might have noticed, the
SMMUv3 driver dt errata framework depends on properties and this will
change the way errata is implemented in the driver now.
Hi Will/Robin,
Could you please take a look and let us know your thoughts on changing
the SMMUv3 dt errata implementation to version/model/compatible string
framework for this quirk.
Thanks,
Shameer
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v7 2/5] ACPI/IORT: Add msi address regions reservation helper
2017-09-14 12:57 [PATCH v7 0/5] iommu/smmu-v3: Workaround for hisilicon 161010801 erratum(reserve HW MSI) Shameer Kolothum
2017-09-14 12:57 ` [PATCH v7 1/5] Doc: iommu/arm-smmu-v3: Add workaround for HiSilicon erratum 161010801 Shameer Kolothum
@ 2017-09-14 12:57 ` Shameer Kolothum
2017-09-14 12:57 ` [PATCH v7 3/5] iommu/of: " Shameer Kolothum
` (2 subsequent siblings)
4 siblings, 0 replies; 10+ messages in thread
From: Shameer Kolothum @ 2017-09-14 12:57 UTC (permalink / raw)
To: linux-arm-kernel
On some platforms msi parent address regions have to be excluded from
normal IOVA allocation in that they are detected and decoded in a HW
specific way by system components and so they cannot be considered normal
IOVA address space.
Add a helper function that retrieves ITS address regions - the msi
parent - through IORT device <-> ITS mappings and reserves it so that
these regions will not be translated by IOMMU and will be excluded from
IOVA allocations.
Signed-off-by: Shameer Kolothum <shameerali.kolothum.thodi@huawei.com>
[lorenzo.pieralisi at arm.com: updated commit log/added comments]
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
---
drivers/acpi/arm64/iort.c | 96 ++++++++++++++++++++++++++++++++++++++--
drivers/irqchip/irq-gic-v3-its.c | 3 +-
include/linux/acpi_iort.h | 7 ++-
3 files changed, 101 insertions(+), 5 deletions(-)
diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index a3215ee..b2e9150 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -39,6 +39,7 @@
struct iort_its_msi_chip {
struct list_head list;
struct fwnode_handle *fw_node;
+ phys_addr_t base_addr;
u32 translation_id;
};
@@ -136,14 +137,16 @@ typedef acpi_status (*iort_find_node_callback)
static DEFINE_SPINLOCK(iort_msi_chip_lock);
/**
- * iort_register_domain_token() - register domain token and related ITS ID
- * to the list from where we can get it back later on.
+ * iort_register_domain_token() - register domain token along with related
+ * ITS ID and base address to the list from where we can get it back later on.
* @trans_id: ITS ID.
+ * @base: ITS base address.
* @fw_node: Domain token.
*
* Returns: 0 on success, -ENOMEM if no memory when allocating list element
*/
-int iort_register_domain_token(int trans_id, struct fwnode_handle *fw_node)
+int iort_register_domain_token(int trans_id, phys_addr_t base,
+ struct fwnode_handle *fw_node)
{
struct iort_its_msi_chip *its_msi_chip;
@@ -153,6 +156,7 @@ int iort_register_domain_token(int trans_id, struct fwnode_handle *fw_node)
its_msi_chip->fw_node = fw_node;
its_msi_chip->translation_id = trans_id;
+ its_msi_chip->base_addr = base;
spin_lock(&iort_msi_chip_lock);
list_add(&its_msi_chip->list, &iort_msi_chip_list);
@@ -481,6 +485,24 @@ int iort_pmsi_get_dev_id(struct device *dev, u32 *dev_id)
return -ENODEV;
}
+static int __maybe_unused iort_find_its_base(u32 its_id, phys_addr_t *base)
+{
+ struct iort_its_msi_chip *its_msi_chip;
+ bool match = false;
+
+ spin_lock(&iort_msi_chip_lock);
+ list_for_each_entry(its_msi_chip, &iort_msi_chip_list, list) {
+ if (its_msi_chip->translation_id == its_id) {
+ *base = its_msi_chip->base_addr;
+ match = true;
+ break;
+ }
+ }
+ spin_unlock(&iort_msi_chip_lock);
+
+ return match ? 0 : -ENODEV;
+}
+
/**
* iort_dev_find_its_id() - Find the ITS identifier for a device
* @dev: The device.
@@ -639,6 +661,72 @@ int iort_add_device_replay(const struct iommu_ops *ops, struct device *dev)
return err;
}
+
+/**
+ * iort_iommu_msi_get_resv_regions - Reserved region driver helper
+ * @dev: Device from iommu_get_resv_regions()
+ * @list: Reserved region list from iommu_get_resv_regions()
+ *
+ * Returns: Number of reserved regions on success (0 if no associated msi
+ * regions), appropriate error value otherwise. The ITS regions
+ * associated with the device are the msi reserved regions.
+ */
+int iort_iommu_msi_get_resv_regions(struct device *dev, struct list_head *head)
+{
+ struct acpi_iort_its_group *its;
+ struct acpi_iort_node *node, *its_node = NULL;
+ int i, resv = 0;
+
+ node = iort_find_dev_node(dev);
+ if (!node)
+ return -ENODEV;
+
+ /*
+ * Current logic to reserve ITS regions relies on HW topologies
+ * where a given PCI or named component maps its IDs to only one
+ * ITS group; if a PCI or named component can map its IDs to
+ * different ITS groups through IORT mappings this function has
+ * to be reworked to ensure we reserve regions for all ITS groups
+ * a given PCI or named component may map IDs to.
+ */
+ if (dev_is_pci(dev)) {
+ u32 rid;
+
+ pci_for_each_dma_alias(to_pci_dev(dev), __get_pci_rid, &rid);
+ its_node = iort_node_map_id(node, rid, NULL, IORT_MSI_TYPE);
+ } else {
+ for (i = 0; i < node->mapping_count; i++) {
+ its_node = iort_node_map_platform_id(node, NULL,
+ IORT_MSI_TYPE, i);
+ if (its_node)
+ break;
+ }
+ }
+
+ if (!its_node)
+ return 0;
+
+ /* Move to ITS specific data */
+ its = (struct acpi_iort_its_group *)its_node->node_data;
+
+ for (i = 0; i < its->its_count; i++) {
+ phys_addr_t base;
+
+ if (!iort_find_its_base(its->identifiers[i], &base)) {
+ int prot = IOMMU_WRITE | IOMMU_NOEXEC | IOMMU_MMIO;
+ struct iommu_resv_region *region;
+
+ region = iommu_alloc_resv_region(base, SZ_128K, prot,
+ IOMMU_RESV_MSI);
+ if (region) {
+ list_add_tail(®ion->list, head);
+ resv++;
+ }
+ }
+ }
+
+ return (resv == its->its_count) ? resv : -ENODEV;
+}
#else
static inline
const struct iommu_ops *iort_fwspec_iommu_ops(struct iommu_fwspec *fwspec)
@@ -646,6 +734,8 @@ const struct iommu_ops *iort_fwspec_iommu_ops(struct iommu_fwspec *fwspec)
static inline
int iort_add_device_replay(const struct iommu_ops *ops, struct device *dev)
{ return 0; }
+int iort_iommu_msi_get_resv_regions(struct device *dev, struct list_head *head)
+{ return -ENODEV; }
#endif
static const struct iommu_ops *iort_iommu_xlate(struct device *dev,
diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
index 284738a..cd41780 100644
--- a/drivers/irqchip/irq-gic-v3-its.c
+++ b/drivers/irqchip/irq-gic-v3-its.c
@@ -1951,7 +1951,8 @@ static int __init gic_acpi_parse_madt_its(struct acpi_subtable_header *header,
return -ENOMEM;
}
- err = iort_register_domain_token(its_entry->translation_id, dom_handle);
+ err = iort_register_domain_token(its_entry->translation_id, res.start,
+ dom_handle);
if (err) {
pr_err("ITS@%pa: Unable to register GICv3 ITS domain token (ITS ID %d) to IORT\n",
&res.start, its_entry->translation_id);
diff --git a/include/linux/acpi_iort.h b/include/linux/acpi_iort.h
index 8379d40..586fb95 100644
--- a/include/linux/acpi_iort.h
+++ b/include/linux/acpi_iort.h
@@ -26,7 +26,8 @@
#define IORT_IRQ_MASK(irq) (irq & 0xffffffffULL)
#define IORT_IRQ_TRIGGER_MASK(irq) ((irq >> 32) & 0xffffffffULL)
-int iort_register_domain_token(int trans_id, struct fwnode_handle *fw_node);
+int iort_register_domain_token(int trans_id, phys_addr_t base,
+ struct fwnode_handle *fw_node);
void iort_deregister_domain_token(int trans_id);
struct fwnode_handle *iort_find_domain_token(int trans_id);
#ifdef CONFIG_ACPI_IORT
@@ -38,6 +39,7 @@
/* IOMMU interface */
void iort_set_dma_mask(struct device *dev);
const struct iommu_ops *iort_iommu_configure(struct device *dev);
+int iort_iommu_msi_get_resv_regions(struct device *dev, struct list_head *head);
#else
static inline void acpi_iort_init(void) { }
static inline u32 iort_msi_map_rid(struct device *dev, u32 req_id)
@@ -51,6 +53,9 @@ static inline void iort_set_dma_mask(struct device *dev) { }
static inline
const struct iommu_ops *iort_iommu_configure(struct device *dev)
{ return NULL; }
+static inline
+int iort_iommu_msi_get_resv_regions(struct device *dev, struct list_head *head)
+{ return -ENODEV; }
#endif
#endif /* __ACPI_IORT_H__ */
--
1.9.1
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH v7 3/5] iommu/of: Add msi address regions reservation helper
2017-09-14 12:57 [PATCH v7 0/5] iommu/smmu-v3: Workaround for hisilicon 161010801 erratum(reserve HW MSI) Shameer Kolothum
2017-09-14 12:57 ` [PATCH v7 1/5] Doc: iommu/arm-smmu-v3: Add workaround for HiSilicon erratum 161010801 Shameer Kolothum
2017-09-14 12:57 ` [PATCH v7 2/5] ACPI/IORT: Add msi address regions reservation helper Shameer Kolothum
@ 2017-09-14 12:57 ` Shameer Kolothum
2017-09-22 14:27 ` Lorenzo Pieralisi
2017-09-14 12:57 ` [PATCH v7 4/5] iommu/dma: Add a helper function to reserve HW MSI address regions for IOMMU drivers Shameer Kolothum
2017-09-14 12:57 ` [PATCH v7 5/5] iommu/arm-smmu-v3:Enable ACPI based HiSilicon erratum 161010801 Shameer Kolothum
4 siblings, 1 reply; 10+ messages in thread
From: Shameer Kolothum @ 2017-09-14 12:57 UTC (permalink / raw)
To: linux-arm-kernel
From: John Garry <john.garry@huawei.com>
On some platforms msi-controller address regions have to be excluded
from normal IOVA allocation in that they are detected and decoded in
a HW specific way by system components and so they cannot be considered
normal IOVA address space.
Add a helper function that retrieves msi address regions through device
tree msi mapping, so that these regions will not be translated by IOMMU
and will be excluded from IOVA allocations.
Signed-off-by: John Garry <john.garry@huawei.com>
Signed-off-by: Shameer Kolothum <shameerali.kolothum.thodi@huawei.com>
---
drivers/iommu/of_iommu.c | 117 +++++++++++++++++++++++++++++++++++++++++++++++
include/linux/of_iommu.h | 10 ++++
2 files changed, 127 insertions(+)
diff --git a/drivers/iommu/of_iommu.c b/drivers/iommu/of_iommu.c
index 8cb6082..f2d1a76 100644
--- a/drivers/iommu/of_iommu.c
+++ b/drivers/iommu/of_iommu.c
@@ -21,6 +21,7 @@
#include <linux/iommu.h>
#include <linux/limits.h>
#include <linux/of.h>
+#include <linux/of_address.h>
#include <linux/of_iommu.h>
#include <linux/of_pci.h>
#include <linux/slab.h>
@@ -246,6 +247,122 @@ const struct iommu_ops *of_iommu_configure(struct device *dev,
return ops;
}
+/**
+ * of_iommu_msi_get_resv_regions - Reserved region driver helper
+ * @dev: Device from iommu_get_resv_regions()
+ * @list: Reserved region list from iommu_get_resv_regions()
+ *
+ * Returns: Number of reserved regions on success (0 if no associated
+ * msi parent), appropriate error value otherwise.
+ */
+int of_iommu_msi_get_resv_regions(struct device *dev, struct list_head *head)
+{
+ int prot = IOMMU_WRITE | IOMMU_NOEXEC | IOMMU_MMIO;
+ struct iommu_resv_region *region;
+ struct device_node *np;
+ struct resource res;
+ int i, resv = 0, mappings = 0;
+
+ if (dev_is_pci(dev)) {
+ struct device *dma_dev, *bridge;
+ struct of_phandle_args iommu_spec;
+ struct pci_dev *pdev = to_pci_dev(dev);
+ int err, count;
+ u32 rid, map_mask;
+ const __be32 *msi_map;
+
+ bridge = pci_get_host_bridge_device(pdev);
+ dma_dev = bridge->parent;
+ pci_put_host_bridge_device(bridge);
+
+ if (!dma_dev->of_node)
+ return -ENODEV;
+
+ iommu_spec.args_count = 1;
+ np = iommu_spec.np = dma_dev->of_node;
+ pci_for_each_dma_alias(pdev, __get_pci_rid, &iommu_spec);
+
+ rid = iommu_spec.args[0];
+ if (!of_property_read_u32(np, "msi-map-mask", &map_mask))
+ rid &= map_mask;
+
+ msi_map = of_get_property(np, "msi-map", NULL);
+ if (!msi_map)
+ return -ENODEV;
+
+ mappings = of_count_phandle_with_args(np, "msi-map", NULL) / 4;
+
+ for (i = 0, count = mappings; i < count; i++, msi_map += 4) {
+ struct device_node *msi_node;
+ u32 rid_base, rid_len, phandle;
+
+ rid_base = be32_to_cpup(msi_map + 0);
+ phandle = be32_to_cpup(msi_map + 1);
+ rid_len = be32_to_cpup(msi_map + 3);
+
+ /* check rid is within range */
+ if (rid < rid_base || rid >= rid_base + rid_len) {
+ mappings--;
+ continue;
+ }
+
+ msi_node = of_find_node_by_phandle(phandle);
+ if (!msi_node)
+ return -ENODEV;
+
+ err = of_address_to_resource(msi_node, 0, &res);
+ of_node_put(msi_node);
+ if (err)
+ return err;
+
+ region = iommu_alloc_resv_region(res.start,
+ resource_size(&res),
+ prot, IOMMU_RESV_MSI);
+ if (region) {
+ list_add_tail(®ion->list, head);
+ resv++;
+ }
+ }
+ } else if (dev->of_node) {
+ struct device_node *msi_np;
+ int index = 0;
+ int tuples;
+
+ np = dev->of_node;
+
+ tuples = of_count_phandle_with_args(np, "msi-parent", NULL);
+
+ while (index < tuples) {
+ int msi_cells = 0;
+ int err;
+
+ msi_np = of_parse_phandle(np, "msi-parent", index);
+ if (!msi_np)
+ return -ENODEV;
+
+ of_property_read_u32(msi_np, "#msi-cells", &msi_cells);
+
+ err = of_address_to_resource(msi_np, 0, &res);
+ of_node_put(msi_np);
+ if (err)
+ return err;
+
+ mappings++;
+
+ region = iommu_alloc_resv_region(res.start,
+ resource_size(&res),
+ prot, IOMMU_RESV_MSI);
+ if (region) {
+ list_add_tail(®ion->list, head);
+ resv++;
+ }
+ index += 1 + msi_cells;
+ }
+ }
+
+ return (resv == mappings) ? resv : -ENODEV;
+}
+
static int __init of_iommu_init(void)
{
struct device_node *np;
diff --git a/include/linux/of_iommu.h b/include/linux/of_iommu.h
index 13394ac..9267772 100644
--- a/include/linux/of_iommu.h
+++ b/include/linux/of_iommu.h
@@ -14,6 +14,9 @@ extern int of_get_dma_window(struct device_node *dn, const char *prefix,
extern const struct iommu_ops *of_iommu_configure(struct device *dev,
struct device_node *master_np);
+extern int of_iommu_msi_get_resv_regions(struct device *dev,
+ struct list_head *head);
+
#else
static inline int of_get_dma_window(struct device_node *dn, const char *prefix,
@@ -29,6 +32,13 @@ static inline const struct iommu_ops *of_iommu_configure(struct device *dev,
return NULL;
}
+static int of_iommu_msi_get_resv_regions(struct device *dev,
+ struct list_head *head)
+{
+ return -ENODEV;
+}
+
+
#endif /* CONFIG_OF_IOMMU */
extern struct of_device_id __iommu_of_table;
--
1.9.1
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH v7 3/5] iommu/of: Add msi address regions reservation helper
2017-09-14 12:57 ` [PATCH v7 3/5] iommu/of: " Shameer Kolothum
@ 2017-09-22 14:27 ` Lorenzo Pieralisi
2017-09-22 15:37 ` Shameerali Kolothum Thodi
0 siblings, 1 reply; 10+ messages in thread
From: Lorenzo Pieralisi @ 2017-09-22 14:27 UTC (permalink / raw)
To: linux-arm-kernel
John, Shameer,
On Thu, Sep 14, 2017 at 01:57:54PM +0100, Shameer Kolothum wrote:
> From: John Garry <john.garry@huawei.com>
>
> On some platforms msi-controller address regions have to be excluded
> from normal IOVA allocation in that they are detected and decoded in
> a HW specific way by system components and so they cannot be considered
> normal IOVA address space.
>
> Add a helper function that retrieves msi address regions through device
> tree msi mapping, so that these regions will not be translated by IOMMU
> and will be excluded from IOVA allocations.
>
> Signed-off-by: John Garry <john.garry@huawei.com>
> Signed-off-by: Shameer Kolothum <shameerali.kolothum.thodi@huawei.com>
> ---
> drivers/iommu/of_iommu.c | 117 +++++++++++++++++++++++++++++++++++++++++++++++
> include/linux/of_iommu.h | 10 ++++
> 2 files changed, 127 insertions(+)
>
> diff --git a/drivers/iommu/of_iommu.c b/drivers/iommu/of_iommu.c
> index 8cb6082..f2d1a76 100644
> --- a/drivers/iommu/of_iommu.c
> +++ b/drivers/iommu/of_iommu.c
> @@ -21,6 +21,7 @@
> #include <linux/iommu.h>
> #include <linux/limits.h>
> #include <linux/of.h>
> +#include <linux/of_address.h>
> #include <linux/of_iommu.h>
> #include <linux/of_pci.h>
> #include <linux/slab.h>
> @@ -246,6 +247,122 @@ const struct iommu_ops *of_iommu_configure(struct device *dev,
> return ops;
> }
>
> +/**
> + * of_iommu_msi_get_resv_regions - Reserved region driver helper
> + * @dev: Device from iommu_get_resv_regions()
> + * @list: Reserved region list from iommu_get_resv_regions()
> + *
> + * Returns: Number of reserved regions on success (0 if no associated
> + * msi parent), appropriate error value otherwise.
> + */
> +int of_iommu_msi_get_resv_regions(struct device *dev, struct list_head *head)
> +{
> + int prot = IOMMU_WRITE | IOMMU_NOEXEC | IOMMU_MMIO;
> + struct iommu_resv_region *region;
> + struct device_node *np;
> + struct resource res;
> + int i, resv = 0, mappings = 0;
> +
> + if (dev_is_pci(dev)) {
> + struct device *dma_dev, *bridge;
> + struct of_phandle_args iommu_spec;
> + struct pci_dev *pdev = to_pci_dev(dev);
> + int err, count;
> + u32 rid, map_mask;
> + const __be32 *msi_map;
> +
> + bridge = pci_get_host_bridge_device(pdev);
> + dma_dev = bridge->parent;
> + pci_put_host_bridge_device(bridge);
> +
> + if (!dma_dev->of_node)
> + return -ENODEV;
> +
> + iommu_spec.args_count = 1;
> + np = iommu_spec.np = dma_dev->of_node;
> + pci_for_each_dma_alias(pdev, __get_pci_rid, &iommu_spec);
> +
> + rid = iommu_spec.args[0];
> + if (!of_property_read_u32(np, "msi-map-mask", &map_mask))
> + rid &= map_mask;
> +
> + msi_map = of_get_property(np, "msi-map", NULL);
> + if (!msi_map)
> + return -ENODEV;
> +
> + mappings = of_count_phandle_with_args(np, "msi-map", NULL) / 4;
> +
> + for (i = 0, count = mappings; i < count; i++, msi_map += 4) {
> + struct device_node *msi_node;
> + u32 rid_base, rid_len, phandle;
> +
> + rid_base = be32_to_cpup(msi_map + 0);
> + phandle = be32_to_cpup(msi_map + 1);
> + rid_len = be32_to_cpup(msi_map + 3);
> +
> + /* check rid is within range */
> + if (rid < rid_base || rid >= rid_base + rid_len) {
> + mappings--;
> + continue;
> + }
> +
> + msi_node = of_find_node_by_phandle(phandle);
> + if (!msi_node)
> + return -ENODEV;
This is basically of_pci_map_rid(), I wonder whether there is not
a way to consolidate some code here - duplicating certainly does not
help. To make MSI reservations generic this is probably the only way
to do it but it would be nice to reuse some OF MSI code.
With the current kernel API there is a way but it is a bit whacky.
Just loop over "msi-controller" nodes and try to map the device to
them through of_pci_map_rid, if mapping succeeds reserve region for
the target node.
Not a big fan of what I am proposing but it certainly helps reuse
some existing code that makes no sense to duplicate.
> + err = of_address_to_resource(msi_node, 0, &res);
> + of_node_put(msi_node);
> + if (err)
> + return err;
> +
> + region = iommu_alloc_resv_region(res.start,
> + resource_size(&res),
> + prot, IOMMU_RESV_MSI);
> + if (region) {
> + list_add_tail(®ion->list, head);
> + resv++;
> + }
> + }
> + } else if (dev->of_node) {
> + struct device_node *msi_np;
> + int index = 0;
> + int tuples;
> +
> + np = dev->of_node;
> +
> + tuples = of_count_phandle_with_args(np, "msi-parent", NULL);
> +
> + while (index < tuples) {
Would not be easier to have an of_parse_phandle_with_args() loop here ?
Lorenzo
> + int msi_cells = 0;
> + int err;
> +
> + msi_np = of_parse_phandle(np, "msi-parent", index);
> + if (!msi_np)
> + return -ENODEV;
> +
> + of_property_read_u32(msi_np, "#msi-cells", &msi_cells);
> +
> + err = of_address_to_resource(msi_np, 0, &res);
> + of_node_put(msi_np);
> + if (err)
> + return err;
> +
> + mappings++;
> +
> + region = iommu_alloc_resv_region(res.start,
> + resource_size(&res),
> + prot, IOMMU_RESV_MSI);
> + if (region) {
> + list_add_tail(®ion->list, head);
> + resv++;
> + }
> + index += 1 + msi_cells;
> + }
> + }
> +
> + return (resv == mappings) ? resv : -ENODEV;
> +}
> +
> static int __init of_iommu_init(void)
> {
> struct device_node *np;
> diff --git a/include/linux/of_iommu.h b/include/linux/of_iommu.h
> index 13394ac..9267772 100644
> --- a/include/linux/of_iommu.h
> +++ b/include/linux/of_iommu.h
> @@ -14,6 +14,9 @@ extern int of_get_dma_window(struct device_node *dn, const char *prefix,
> extern const struct iommu_ops *of_iommu_configure(struct device *dev,
> struct device_node *master_np);
>
> +extern int of_iommu_msi_get_resv_regions(struct device *dev,
> + struct list_head *head);
> +
> #else
>
> static inline int of_get_dma_window(struct device_node *dn, const char *prefix,
> @@ -29,6 +32,13 @@ static inline const struct iommu_ops *of_iommu_configure(struct device *dev,
> return NULL;
> }
>
> +static int of_iommu_msi_get_resv_regions(struct device *dev,
> + struct list_head *head)
> +{
> + return -ENODEV;
> +}
> +
> +
> #endif /* CONFIG_OF_IOMMU */
>
> extern struct of_device_id __iommu_of_table;
> --
> 1.9.1
>
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 10+ messages in thread* [PATCH v7 3/5] iommu/of: Add msi address regions reservation helper
2017-09-22 14:27 ` Lorenzo Pieralisi
@ 2017-09-22 15:37 ` Shameerali Kolothum Thodi
0 siblings, 0 replies; 10+ messages in thread
From: Shameerali Kolothum Thodi @ 2017-09-22 15:37 UTC (permalink / raw)
To: linux-arm-kernel
> -----Original Message-----
> From: Lorenzo Pieralisi [mailto:lorenzo.pieralisi at arm.com]
> Sent: Friday, September 22, 2017 3:28 PM
> To: Shameerali Kolothum Thodi <shameerali.kolothum.thodi@huawei.com>
> Cc: marc.zyngier at arm.com; sudeep.holla at arm.com; will.deacon at arm.com;
> robin.murphy at arm.com; joro at 8bytes.org; mark.rutland at arm.com;
> hanjun.guo at linaro.org; Gabriele Paoloni <gabriele.paoloni@huawei.com>;
> John Garry <john.garry@huawei.com>; iommu at lists.linux-foundation.org;
> linux-arm-kernel at lists.infradead.org; linux-acpi at vger.kernel.org;
> devicetree at vger.kernel.org; devel at acpica.org; Linuxarm
> <linuxarm@huawei.com>; Wangzhou (B) <wangzhou1@hisilicon.com>;
> Guohanjun (Hanjun Guo) <guohanjun@huawei.com>
> Subject: Re: [PATCH v7 3/5] iommu/of: Add msi address regions reservation
> helper
>
> John, Shameer,
>
> On Thu, Sep 14, 2017 at 01:57:54PM +0100, Shameer Kolothum wrote:
> > From: John Garry <john.garry@huawei.com>
> >
> > On some platforms msi-controller address regions have to be excluded
> > from normal IOVA allocation in that they are detected and decoded in
> > a HW specific way by system components and so they cannot be
> considered
> > normal IOVA address space.
> >
> > Add a helper function that retrieves msi address regions through device
> > tree msi mapping, so that these regions will not be translated by IOMMU
> > and will be excluded from IOVA allocations.
> >
> > Signed-off-by: John Garry <john.garry@huawei.com>
> > Signed-off-by: Shameer Kolothum
> <shameerali.kolothum.thodi@huawei.com>
> > ---
> > drivers/iommu/of_iommu.c | 117
> +++++++++++++++++++++++++++++++++++++++++++++++
> > include/linux/of_iommu.h | 10 ++++
> > 2 files changed, 127 insertions(+)
> >
> > diff --git a/drivers/iommu/of_iommu.c b/drivers/iommu/of_iommu.c
> > index 8cb6082..f2d1a76 100644
> > --- a/drivers/iommu/of_iommu.c
> > +++ b/drivers/iommu/of_iommu.c
> > @@ -21,6 +21,7 @@
> > #include <linux/iommu.h>
> > #include <linux/limits.h>
> > #include <linux/of.h>
> > +#include <linux/of_address.h>
> > #include <linux/of_iommu.h>
> > #include <linux/of_pci.h>
> > #include <linux/slab.h>
> > @@ -246,6 +247,122 @@ const struct iommu_ops
> *of_iommu_configure(struct device *dev,
> > return ops;
> > }
> >
> > +/**
> > + * of_iommu_msi_get_resv_regions - Reserved region driver helper
> > + * @dev: Device from iommu_get_resv_regions()
> > + * @list: Reserved region list from iommu_get_resv_regions()
> > + *
> > + * Returns: Number of reserved regions on success (0 if no associated
> > + * msi parent), appropriate error value otherwise.
> > + */
> > +int of_iommu_msi_get_resv_regions(struct device *dev, struct list_head
> *head)
> > +{
> > + int prot = IOMMU_WRITE | IOMMU_NOEXEC | IOMMU_MMIO;
> > + struct iommu_resv_region *region;
> > + struct device_node *np;
> > + struct resource res;
> > + int i, resv = 0, mappings = 0;
> > +
> > + if (dev_is_pci(dev)) {
> > + struct device *dma_dev, *bridge;
> > + struct of_phandle_args iommu_spec;
> > + struct pci_dev *pdev = to_pci_dev(dev);
> > + int err, count;
> > + u32 rid, map_mask;
> > + const __be32 *msi_map;
> > +
> > + bridge = pci_get_host_bridge_device(pdev);
> > + dma_dev = bridge->parent;
> > + pci_put_host_bridge_device(bridge);
> > +
> > + if (!dma_dev->of_node)
> > + return -ENODEV;
> > +
> > + iommu_spec.args_count = 1;
> > + np = iommu_spec.np = dma_dev->of_node;
> > + pci_for_each_dma_alias(pdev, __get_pci_rid,
> &iommu_spec);
> > +
> > + rid = iommu_spec.args[0];
> > + if (!of_property_read_u32(np, "msi-map-mask",
> &map_mask))
> > + rid &= map_mask;
> > +
> > + msi_map = of_get_property(np, "msi-map", NULL);
> > + if (!msi_map)
> > + return -ENODEV;
> > +
> > + mappings = of_count_phandle_with_args(np, "msi-map",
> NULL) / 4;
> > +
> > + for (i = 0, count = mappings; i < count; i++, msi_map += 4) {
> > + struct device_node *msi_node;
> > + u32 rid_base, rid_len, phandle;
> > +
> > + rid_base = be32_to_cpup(msi_map + 0);
> > + phandle = be32_to_cpup(msi_map + 1);
> > + rid_len = be32_to_cpup(msi_map + 3);
> > +
> > + /* check rid is within range */
> > + if (rid < rid_base || rid >= rid_base + rid_len) {
> > + mappings--;
> > + continue;
> > + }
> > +
> > + msi_node = of_find_node_by_phandle(phandle);
> > + if (!msi_node)
> > + return -ENODEV;
>
> This is basically of_pci_map_rid(), I wonder whether there is not
> a way to consolidate some code here - duplicating certainly does not
> help. To make MSI reservations generic this is probably the only way
> to do it but it would be nice to reuse some OF MSI code.
>
> With the current kernel API there is a way but it is a bit whacky.
>
> Just loop over "msi-controller" nodes and try to map the device to
> them through of_pci_map_rid, if mapping succeeds reserve region for
> the target node.
>
> Not a big fan of what I am proposing but it certainly helps reuse
> some existing code that makes no sense to duplicate.
Right, lot of this is of_pci_map_rid() code. And just to confirm,
I think the proposal is to make use of the @target node param in
of_pci_map_rid() for a matching "msi-controller".
> > + err = of_address_to_resource(msi_node, 0, &res);
> > + of_node_put(msi_node);
> > + if (err)
> > + return err;
> > +
> > + region = iommu_alloc_resv_region(res.start,
> > + resource_size(&res),
> > + prot,
> IOMMU_RESV_MSI);
> > + if (region) {
> > + list_add_tail(®ion->list, head);
> > + resv++;
> > + }
> > + }
> > + } else if (dev->of_node) {
> > + struct device_node *msi_np;
> > + int index = 0;
> > + int tuples;
> > +
> > + np = dev->of_node;
> > +
> > + tuples = of_count_phandle_with_args(np, "msi-parent",
> NULL);
> > +
> > + while (index < tuples) {
>
> Would not be easier to have an of_parse_phandle_with_args() loop here ?
Ok. Many thanks for going through this. We will rework this based on your
suggestions and send out the next revision (rebased on -rc1).
Thanks,
Shameer
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v7 4/5] iommu/dma: Add a helper function to reserve HW MSI address regions for IOMMU drivers
2017-09-14 12:57 [PATCH v7 0/5] iommu/smmu-v3: Workaround for hisilicon 161010801 erratum(reserve HW MSI) Shameer Kolothum
` (2 preceding siblings ...)
2017-09-14 12:57 ` [PATCH v7 3/5] iommu/of: " Shameer Kolothum
@ 2017-09-14 12:57 ` Shameer Kolothum
2017-09-14 12:57 ` [PATCH v7 5/5] iommu/arm-smmu-v3:Enable ACPI based HiSilicon erratum 161010801 Shameer Kolothum
4 siblings, 0 replies; 10+ messages in thread
From: Shameer Kolothum @ 2017-09-14 12:57 UTC (permalink / raw)
To: linux-arm-kernel
IOMMU drivers can use this to implement their .get_resv_regions callback
for HW MSI specific reservations(e.g. ARM GICv3 ITS MSI region).
Signed-off-by: Shameer Kolothum <shameerali.kolothum.thodi@huawei.com>
[John: added DT support]
Signed-off-by: John Garry <john.garry@huawei.com>
---
drivers/iommu/dma-iommu.c | 19 +++++++++++++++++++
include/linux/dma-iommu.h | 7 +++++++
2 files changed, 26 insertions(+)
diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c
index 9d1cebe..f8709a2 100644
--- a/drivers/iommu/dma-iommu.c
+++ b/drivers/iommu/dma-iommu.c
@@ -19,6 +19,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <linux/acpi_iort.h>
#include <linux/device.h>
#include <linux/dma-iommu.h>
#include <linux/gfp.h>
@@ -27,6 +28,7 @@
#include <linux/iova.h>
#include <linux/irq.h>
#include <linux/mm.h>
+#include <linux/of_iommu.h>
#include <linux/pci.h>
#include <linux/scatterlist.h>
#include <linux/vmalloc.h>
@@ -198,6 +200,23 @@ void iommu_dma_get_resv_regions(struct device *dev, struct list_head *list)
}
EXPORT_SYMBOL(iommu_dma_get_resv_regions);
+/**
+ * iommu_dma_get_msi_resv_regions - Reserved region driver helper
+ * @dev: Device from iommu_get_resv_regions()
+ * @list: Reserved region list from iommu_get_resv_regions()
+ *
+ * IOMMU drivers can use this to implement their .get_resv_regions
+ * callback for HW MSI specific reservations.
+ */
+int iommu_dma_get_msi_resv_regions(struct device *dev, struct list_head *list)
+{
+ if (is_of_node(dev->iommu_fwspec->iommu_fwnode))
+ return of_iommu_msi_get_resv_regions(dev, list);
+
+ return iort_iommu_msi_get_resv_regions(dev, list);
+}
+EXPORT_SYMBOL(iommu_dma_get_msi_resv_regions);
+
static int cookie_init_hw_msi_region(struct iommu_dma_cookie *cookie,
phys_addr_t start, phys_addr_t end)
{
diff --git a/include/linux/dma-iommu.h b/include/linux/dma-iommu.h
index 92f2083..6062ef0 100644
--- a/include/linux/dma-iommu.h
+++ b/include/linux/dma-iommu.h
@@ -74,6 +74,8 @@ void iommu_dma_unmap_resource(struct device *dev, dma_addr_t handle,
void iommu_dma_map_msi_msg(int irq, struct msi_msg *msg);
void iommu_dma_get_resv_regions(struct device *dev, struct list_head *list);
+int iommu_dma_get_msi_resv_regions(struct device *dev, struct list_head *list);
+
#else
struct iommu_domain;
@@ -107,6 +109,11 @@ static inline void iommu_dma_get_resv_regions(struct device *dev, struct list_he
{
}
+static inline int iommu_dma_get_msi_resv_regions(struct device *dev, struct list_head *list)
+{
+ return -ENODEV;
+}
+
#endif /* CONFIG_IOMMU_DMA */
#endif /* __KERNEL__ */
#endif /* __DMA_IOMMU_H */
--
1.9.1
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH v7 5/5] iommu/arm-smmu-v3:Enable ACPI based HiSilicon erratum 161010801
2017-09-14 12:57 [PATCH v7 0/5] iommu/smmu-v3: Workaround for hisilicon 161010801 erratum(reserve HW MSI) Shameer Kolothum
` (3 preceding siblings ...)
2017-09-14 12:57 ` [PATCH v7 4/5] iommu/dma: Add a helper function to reserve HW MSI address regions for IOMMU drivers Shameer Kolothum
@ 2017-09-14 12:57 ` Shameer Kolothum
4 siblings, 0 replies; 10+ messages in thread
From: Shameer Kolothum @ 2017-09-14 12:57 UTC (permalink / raw)
To: linux-arm-kernel
The HiSilicon erratum 161010801 describes the limitation of HiSilicon
platforms Hip06/Hip07 to support the SMMU mappings for MSI transactions.
On these platforms GICv3 ITS translator is presented with the deviceID
by extending the MSI payload data to 64 bits to include the deviceID.
Hence, the PCIe controller on this platforms has to differentiate the
MSI payload against other DMA payload and has to modify the MSI payload.
This basically makes it difficult for this platforms to have a SMMU
translation for MSI.
This patch implements a quirk to reserve the hw msi regions in the
smmu-v3 driver which means these address regions will not be
translated and will be excluded from iova allocations.
Signed-off-by: Shameer Kolothum <shameerali.kolothum.thodi@huawei.com>
[John: add DT support]
Signed-off-by: John Garry <john.garry@huawei.com>
---
drivers/iommu/arm-smmu-v3.c | 28 +++++++++++++++++++++++-----
1 file changed, 23 insertions(+), 5 deletions(-)
diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c
index 568c400..8503f4d 100644
--- a/drivers/iommu/arm-smmu-v3.c
+++ b/drivers/iommu/arm-smmu-v3.c
@@ -608,6 +608,7 @@ struct arm_smmu_device {
#define ARM_SMMU_OPT_SKIP_PREFETCH (1 << 0)
#define ARM_SMMU_OPT_PAGE0_REGS_ONLY (1 << 1)
+#define ARM_SMMU_OPT_RESV_HW_MSI (1 << 2)
u32 options;
struct arm_smmu_cmdq cmdq;
@@ -674,6 +675,7 @@ struct arm_smmu_option_prop {
static struct arm_smmu_option_prop arm_smmu_options[] = {
{ ARM_SMMU_OPT_SKIP_PREFETCH, "hisilicon,broken-prefetch-cmd" },
+ { ARM_SMMU_OPT_RESV_HW_MSI, "hisilicon,broken-untranslated-msi" },
{ ARM_SMMU_OPT_PAGE0_REGS_ONLY, "cavium,cn9900-broken-page1-regspace"},
{ 0, NULL},
};
@@ -1934,14 +1936,29 @@ static void arm_smmu_get_resv_regions(struct device *dev,
struct list_head *head)
{
struct iommu_resv_region *region;
+ struct arm_smmu_master_data *master = dev->iommu_fwspec->iommu_priv;
+ struct arm_smmu_device *smmu = master->smmu;
int prot = IOMMU_WRITE | IOMMU_NOEXEC | IOMMU_MMIO;
+ int resv = 0;
- region = iommu_alloc_resv_region(MSI_IOVA_BASE, MSI_IOVA_LENGTH,
- prot, IOMMU_RESV_SW_MSI);
- if (!region)
- return;
+ if ((smmu->options & ARM_SMMU_OPT_RESV_HW_MSI)) {
- list_add_tail(®ion->list, head);
+ resv = iommu_dma_get_msi_resv_regions(dev, head);
+
+ if (resv < 0) {
+ dev_warn(dev, "HW MSI region resv failed: %d\n", resv);
+ return;
+ }
+ }
+
+ if (!resv) {
+ region = iommu_alloc_resv_region(MSI_IOVA_BASE, MSI_IOVA_LENGTH,
+ prot, IOMMU_RESV_SW_MSI);
+ if (!region)
+ return;
+
+ list_add_tail(®ion->list, head);
+ }
iommu_dma_get_resv_regions(dev, head);
}
@@ -2667,6 +2684,7 @@ static void acpi_smmu_get_options(u32 model, struct arm_smmu_device *smmu)
break;
case ACPI_IORT_SMMU_HISILICON_HI161X:
smmu->options |= ARM_SMMU_OPT_SKIP_PREFETCH;
+ smmu->options |= ARM_SMMU_OPT_RESV_HW_MSI;
break;
}
--
1.9.1
^ permalink raw reply related [flat|nested] 10+ messages in thread