SMMU register regions are located into 3 blocks discontiguously. Get them and reserve each region respectively. This allows other module to use/reserve other register regions between SMMU register blocks. Signed-off-by: Hiroshi DOYU <hdoyu@xxxxxxxxxx> --- drivers/iommu/tegra-smmu.c | 44 ++++++++++++++++++++++++++++++++++++-------- 1 files changed, 36 insertions(+), 8 deletions(-) diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c index de9fafe..90bbf07 100644 --- a/drivers/iommu/tegra-smmu.c +++ b/drivers/iommu/tegra-smmu.c @@ -173,6 +173,8 @@ #define SMMU_ASID_DISABLE 0 #define SMMU_ASID_ASID(n) ((n) & ~SMMU_ASID_ENABLE(0)) +#define NUM_SMMU_REG_BLOCKS 3 + #define smmu_client_enable_hwgrp(c, m) smmu_client_set_hwgrp(c, m, 1) #define smmu_client_disable_hwgrp(c) smmu_client_set_hwgrp(c, 0, 0) #define __smmu_client_enable_hwgrp(c, m) __smmu_client_set_hwgrp(c, m, 1) @@ -866,7 +868,7 @@ static int tegra_smmu_resume(struct device *dev) static int tegra_smmu_probe(struct platform_device *pdev) { struct smmu_device *smmu; - struct resource *regs, *window; + struct resource *res[NUM_SMMU_REG_BLOCKS], *window; struct device *dev = &pdev->dev; int i, err = 0; @@ -875,9 +877,25 @@ static int tegra_smmu_probe(struct platform_device *pdev) BUILD_BUG_ON(PAGE_SHIFT != SMMU_PAGE_SHIFT); - regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); - window = platform_get_resource(pdev, IORESOURCE_MEM, 1); - if (!regs || !window) { + for (i = 0; i < ARRAY_SIZE(res); i++) { + res[i] = platform_get_resource(pdev, IORESOURCE_MEM, i); + if (!res[i]) + return -ENODEV; + + res[i] = devm_request_mem_region(&pdev->dev, res[i]->start, + resource_size(res[i]), + dev_name(&pdev->dev)); + if (res[i]) + continue; + + while (--i >= 0) + devm_release_mem_region(&pdev->dev, res[i]->start, + resource_size(res[i])); + return -EIO; + } + + window = platform_get_resource(pdev, IORESOURCE_MEM, 3); + if (!window) { dev_err(dev, "No SMMU resources\n"); return -ENODEV; } @@ -892,7 +910,8 @@ static int tegra_smmu_probe(struct platform_device *pdev) smmu->num_as = SMMU_NUM_ASIDS; smmu->iovmm_base = (unsigned long)window->start; smmu->page_count = resource_size(window) >> SMMU_PAGE_SHIFT; - smmu->regs = devm_ioremap(dev, regs->start, resource_size(regs)); + smmu->regs = devm_ioremap(dev, res[0]->start, + res[2]->end - res[0]->start + 1); if (!smmu->regs) { dev_err(dev, "failed to remap SMMU registers\n"); err = -ENXIO; @@ -905,7 +924,7 @@ static int tegra_smmu_probe(struct platform_device *pdev) smmu->asid_security = 0; smmu->as = devm_kzalloc(dev, - sizeof(smmu->as[0]) * smmu->num_as, GFP_KERNEL); + sizeof(smmu->as[0]) * smmu->num_as, GFP_KERNEL); if (!smmu->as) { dev_err(dev, "failed to allocate smmu_as\n"); err = -ENOMEM; @@ -950,6 +969,9 @@ fail: devm_kfree(dev, smmu->as); } devm_kfree(dev, smmu); + for (i = 0; i < ARRAY_SIZE(res); i++) + devm_release_mem_region(&pdev->dev, res[i]->start, + resource_size(res[i])); return err; } @@ -957,12 +979,11 @@ static int tegra_smmu_remove(struct platform_device *pdev) { struct smmu_device *smmu = platform_get_drvdata(pdev); struct device *dev = smmu->dev; + int i; smmu_write(smmu, SMMU_CONFIG_DISABLE, SMMU_CONFIG); platform_set_drvdata(pdev, NULL); if (smmu->as) { - int i; - for (i = 0; i < smmu->num_as; i++) free_pdir(&smmu->as[i]); devm_kfree(dev, smmu->as); @@ -973,6 +994,13 @@ static int tegra_smmu_remove(struct platform_device *pdev) devm_iounmap(dev, smmu->regs); devm_kfree(dev, smmu); smmu_handle = NULL; + for (i = 0; i < NUM_SMMU_REG_BLOCKS; i++) { + struct resource *res; + + res = platform_get_resource(pdev, IORESOURCE_MEM, i); + devm_release_mem_region(&pdev->dev, res->start, + resource_size(res)); + } return 0; } -- 1.7.5.4 -- To unsubscribe from this list: send the line "unsubscribe linux-tegra" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html