From 38667f18900afe172a4fe44279b132b4140f920f Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Mon, 29 Jun 2015 10:16:08 +0200 Subject: iommu: Ignore -ENODEV errors from add_device call-back The -ENODEV error just means that the device is not translated by an IOMMU. We shouldn't bail out of iommu driver initialization when that happens, as this is a common scenario on ARM. Not returning -ENODEV in the drivers would be a bad idea, as the IOMMU core would have no indication whether a device is translated or not. This indication is not used at the moment, but will probably be in the future. Fixes: 19762d7 ("iommu: Propagate error in add_iommu_group") Tested-by: Marek Szyprowski Tested-by: Eric Auger Tested-by: Heiko Stuebner Signed-off-by: Joerg Roedel --- drivers/iommu/iommu.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'drivers/iommu') diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 49e7542510d1..f286090931cc 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -847,13 +847,24 @@ static int add_iommu_group(struct device *dev, void *data) { struct iommu_callback_data *cb = data; const struct iommu_ops *ops = cb->ops; + int ret; if (!ops->add_device) return 0; WARN_ON(dev->iommu_group); - return ops->add_device(dev); + ret = ops->add_device(dev); + + /* + * We ignore -ENODEV errors for now, as they just mean that the + * device is not translated by an IOMMU. We still care about + * other errors and fail to initialize when they happen. + */ + if (ret == -ENODEV) + ret = 0; + + return ret; } static int remove_iommu_group(struct device *dev, void *data) -- cgit v1.2.3 From d38f0ff9ab35414644995bae187d015c31aae19c Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Mon, 29 Jun 2015 17:47:42 +0100 Subject: iommu/arm-smmu: Fix broken ATOS check Commit 83a60ed8f0b5 ("iommu/arm-smmu: fix ARM_SMMU_FEAT_TRANS_OPS condition") accidentally negated the ID0_ATOSNS predicate in the ATOS feature check, causing the driver to attempt ATOS requests on SMMUv2 hardware without the ATOS feature implemented. This patch restores the predicate to the correct value. Cc: # 4.0+ Reported-by: Varun Sethi Signed-off-by: Will Deacon Signed-off-by: Joerg Roedel --- drivers/iommu/arm-smmu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/iommu') diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index dce041b1c139..4cd0c29cb585 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -1566,7 +1566,7 @@ static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu) return -ENODEV; } - if ((id & ID0_S1TS) && ((smmu->version == 1) || (id & ID0_ATOSNS))) { + if ((id & ID0_S1TS) && ((smmu->version == 1) || !(id & ID0_ATOSNS))) { smmu->features |= ARM_SMMU_FEAT_TRANS_OPS; dev_notice(smmu->dev, "\taddress translation ops\n"); } -- cgit v1.2.3 From a6e08fb2d2f9eb38f52e6f2425a38f1cb9794742 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Mon, 29 Jun 2015 17:47:43 +0100 Subject: iommu/arm-smmu: Delete an unnecessary check before the function call "free_io_pgtable_ops" The free_io_pgtable_ops() function tests whether its argument is NULL and then returns immediately. Thus the test around the call is not needed. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Will Deacon Signed-off-by: Joerg Roedel --- drivers/iommu/arm-smmu-v3.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/iommu') diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c index f14130121298..8e9ec81ce4bb 100644 --- a/drivers/iommu/arm-smmu-v3.c +++ b/drivers/iommu/arm-smmu-v3.c @@ -1389,8 +1389,7 @@ static void arm_smmu_domain_free(struct iommu_domain *domain) struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain); struct arm_smmu_device *smmu = smmu_domain->smmu; - if (smmu_domain->pgtbl_ops) - free_io_pgtable_ops(smmu_domain->pgtbl_ops); + free_io_pgtable_ops(smmu_domain->pgtbl_ops); /* Free the CD and ASID, if we allocated them */ if (smmu_domain->stage == ARM_SMMU_DOMAIN_S1) { -- cgit v1.2.3 From 7a5a566eab48da7522f601f96aef3af102178046 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Tue, 30 Jun 2015 08:56:11 +0200 Subject: iommu/amd: Introduce protection_domain_init() function This function contains the common parts between the initialization of dma_ops_domains and usual protection domains. This also fixes a long-standing bug which was uncovered by recent changes, in which the api_lock was not initialized for dma_ops_domains. Reported-by: George Wang Tested-by: George Wang Signed-off-by: Joerg Roedel --- drivers/iommu/amd_iommu.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) (limited to 'drivers/iommu') diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c index c5677ed2cd89..cedbf004c8ef 100644 --- a/drivers/iommu/amd_iommu.c +++ b/drivers/iommu/amd_iommu.c @@ -116,6 +116,7 @@ struct kmem_cache *amd_iommu_irq_cache; static void update_domain(struct protection_domain *domain); static int alloc_passthrough_domain(void); +static int protection_domain_init(struct protection_domain *domain); /**************************************************************************** * @@ -1880,12 +1881,9 @@ static struct dma_ops_domain *dma_ops_domain_alloc(void) if (!dma_dom) return NULL; - spin_lock_init(&dma_dom->domain.lock); - - dma_dom->domain.id = domain_id_alloc(); - if (dma_dom->domain.id == 0) + if (protection_domain_init(&dma_dom->domain)) goto free_dma_dom; - INIT_LIST_HEAD(&dma_dom->domain.dev_list); + dma_dom->domain.mode = PAGE_MODE_2_LEVEL; dma_dom->domain.pt_root = (void *)get_zeroed_page(GFP_KERNEL); dma_dom->domain.flags = PD_DMA_OPS_MASK; @@ -2915,6 +2913,18 @@ static void protection_domain_free(struct protection_domain *domain) kfree(domain); } +static int protection_domain_init(struct protection_domain *domain) +{ + spin_lock_init(&domain->lock); + mutex_init(&domain->api_lock); + domain->id = domain_id_alloc(); + if (!domain->id) + return -ENOMEM; + INIT_LIST_HEAD(&domain->dev_list); + + return 0; +} + static struct protection_domain *protection_domain_alloc(void) { struct protection_domain *domain; @@ -2923,12 +2933,8 @@ static struct protection_domain *protection_domain_alloc(void) if (!domain) return NULL; - spin_lock_init(&domain->lock); - mutex_init(&domain->api_lock); - domain->id = domain_id_alloc(); - if (!domain->id) + if (protection_domain_init(domain)) goto out_err; - INIT_LIST_HEAD(&domain->dev_list); add_domain_to_list(domain); -- cgit v1.2.3