summaryrefslogtreecommitdiff
path: root/drivers/iommu
diff options
context:
space:
mode:
authorHiroshi DOYU <hdoyu@nvidia.com>2012-01-23 12:40:32 +0200
committerSimone Willett <swillett@nvidia.com>2012-02-09 18:19:53 -0800
commita1dbd7aee49af8805bd5325f6977f57df3106501 (patch)
tree2476a8dba021be5260093a5db98a5281ef8e9e46 /drivers/iommu
parent4d41b03d13b02221d0084b64fd55f66fdbdc0896 (diff)
iommu: tegra/gart: Fix with mainline IOMMU API change
The mainline IOMMU API v3.3-rc1 has been changed so that bytes are used in mapping size instead of page order and page-by-page iteration is taken care of by iommu core. The rest are mostly for maintainability: $ git co iommu/next drivers/iommu/tegra-gart.c Change-Id: Id88ae8d23d11f4e003d11ec1e4223a72215ad142 Signed-off-by: Hiroshi DOYU <hdoyu@nvidia.com> Reviewed-on: http://git-master/r/78138 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Krishna Reddy <vdumpa@nvidia.com>
Diffstat (limited to 'drivers/iommu')
-rw-r--r--drivers/iommu/tegra-gart.c119
1 files changed, 55 insertions, 64 deletions
diff --git a/drivers/iommu/tegra-gart.c b/drivers/iommu/tegra-gart.c
index c5d118f5c859..e8d50a268f3f 100644
--- a/drivers/iommu/tegra-gart.c
+++ b/drivers/iommu/tegra-gart.c
@@ -53,14 +53,16 @@ struct gart_client {
struct gart_device {
void __iomem *regs;
u32 *savedata;
- u32 page_count; /* total remappable size */
- dma_addr_t iovmm_base; /* offset to apply to vmm_area */
- spinlock_t pte_lock; /* for pagetable */
+ u32 page_count; /* total remappable size */
+ dma_addr_t iovmm_base; /* offset to vmm_area */
+ spinlock_t pte_lock; /* for pagetable */
struct list_head client;
- spinlock_t client_lock; /* for client list */
+ spinlock_t client_lock; /* for client list */
struct device *dev;
};
+static struct gart_device *gart_handle; /* unique for a system */
+
#define GART_PTE(_pfn) \
(GART_ENTRY_PHYS_ADDR_VALID | ((_pfn) << PAGE_SHIFT))
@@ -149,27 +151,6 @@ static inline bool gart_iova_range_valid(struct gart_device *gart,
return true;
}
-static int gart_iommu_domain_init(struct iommu_domain *domain)
-{
- return 0;
-}
-
-static void gart_iommu_domain_destroy(struct iommu_domain *domain)
-{
- struct gart_device *gart = domain->priv;
-
- spin_lock(&gart->client_lock);
- if (!list_empty(&gart->client)) {
- struct gart_client *c;
-
- list_for_each_entry(c, &gart->client, list)
- dev_err(gart->dev,
- "%s is still attached\n", dev_name(c->dev));
- }
- spin_unlock(&gart->client_lock);
- domain->priv = NULL;
-}
-
static int gart_iommu_attach_dev(struct iommu_domain *domain,
struct device *dev)
{
@@ -181,7 +162,8 @@ static int gart_iommu_attach_dev(struct iommu_domain *domain,
if (!gart)
return -EINVAL;
domain->priv = gart;
- client = devm_kzalloc(dev, sizeof(*c), GFP_KERNEL);
+
+ client = devm_kzalloc(gart->dev, sizeof(*c), GFP_KERNEL);
if (!client)
return -ENOMEM;
client->dev = dev;
@@ -201,7 +183,7 @@ static int gart_iommu_attach_dev(struct iommu_domain *domain,
return 0;
fail:
- devm_kfree(dev, client);
+ devm_kfree(gart->dev, client);
spin_unlock(&gart->client_lock);
return err;
}
@@ -217,7 +199,7 @@ static void gart_iommu_detach_dev(struct iommu_domain *domain,
list_for_each_entry(c, &gart->client, list) {
if (c->dev == dev) {
list_del(&c->list);
- devm_kfree(dev, c);
+ devm_kfree(gart->dev, c);
dev_dbg(gart->dev, "Detached %s\n", dev_name(dev));
goto out;
}
@@ -227,61 +209,63 @@ out:
spin_unlock(&gart->client_lock);
}
+static int gart_iommu_domain_init(struct iommu_domain *domain)
+{
+ return 0;
+}
+
+static void gart_iommu_domain_destroy(struct iommu_domain *domain)
+{
+ struct gart_device *gart = domain->priv;
+
+ if (!gart)
+ return;
+
+ spin_lock(&gart->client_lock);
+ if (!list_empty(&gart->client)) {
+ struct gart_client *c;
+
+ list_for_each_entry(c, &gart->client, list)
+ gart_iommu_detach_dev(domain, c->dev);
+ }
+ spin_unlock(&gart->client_lock);
+ domain->priv = NULL;
+}
+
static int gart_iommu_map(struct iommu_domain *domain, unsigned long iova,
- phys_addr_t pa, int gfp_order, int prot)
+ phys_addr_t pa, size_t bytes, int prot)
{
struct gart_device *gart = domain->priv;
unsigned long flags;
- unsigned long count = (PAGE_SIZE << gfp_order) >> GART_PAGE_SHIFT;
- int i;
+ unsigned long pfn;
- if (!gart_iova_range_valid(gart, iova, count * GART_PAGE_SIZE))
+ if (!gart_iova_range_valid(gart, iova, bytes))
return -EINVAL;
spin_lock_irqsave(&gart->pte_lock, flags);
-
- for (i = 0; i < count; i++) {
- unsigned long pfn;
-
- pfn = __phys_to_pfn(pa);
- if (!pfn_valid(pfn)) {
- dev_err(gart->dev, "Invalid page: %08x\n", pa);
- goto fail;
- }
-
- gart_set_pte(gart, iova, GART_PTE(pfn));
- iova += GART_PAGE_SIZE;
+ pfn = __phys_to_pfn(pa);
+ if (!pfn_valid(pfn)) {
+ dev_err(gart->dev, "Invalid page: %08x\n", pa);
+ spin_lock_irqsave(&gart->pte_lock, flags);
+ return -EINVAL;
}
+ gart_set_pte(gart, iova, GART_PTE(pfn));
FLUSH_GART_REGS(gart);
spin_unlock_irqrestore(&gart->pte_lock, flags);
return 0;
-
-fail:
- while (--i >= 0) {
- iova -= GART_PAGE_SIZE;
- gart_set_pte(gart, iova, 0);
- }
- FLUSH_GART_REGS(gart);
- spin_unlock_irqrestore(&gart->pte_lock, flags);
- return -EINVAL;
}
-static int gart_iommu_unmap(struct iommu_domain *domain, unsigned long iova,
- int gfp_order)
+static size_t gart_iommu_unmap(struct iommu_domain *domain, unsigned long iova,
+ size_t bytes)
{
- int i;
struct gart_device *gart = domain->priv;
unsigned long flags;
- unsigned long count = (PAGE_SIZE << gfp_order) >> GART_PAGE_SHIFT;
- if (!gart_iova_range_valid(gart, iova, count * GART_PAGE_SIZE))
- return -EINVAL;
+ if (!gart_iova_range_valid(gart, iova, bytes))
+ return 0;
spin_lock_irqsave(&gart->pte_lock, flags);
- for (i = 0; i < count; i++) {
- gart_set_pte(gart, iova, 0);
- iova += GART_PAGE_SIZE;
- }
+ gart_set_pte(gart, iova, 0);
FLUSH_GART_REGS(gart);
spin_unlock_irqrestore(&gart->pte_lock, flags);
return 0;
@@ -326,6 +310,7 @@ static struct iommu_ops gart_iommu_ops = {
.unmap = gart_iommu_unmap,
.iova_to_phys = gart_iommu_iova_to_phys,
.domain_has_cap = gart_iommu_domain_has_cap,
+ .pgsize_bitmap = GART_IOMMU_PGSIZES,
};
static int tegra_gart_suspend(struct device *dev)
@@ -361,6 +346,9 @@ static int tegra_gart_probe(struct platform_device *pdev)
int err;
struct device *dev = &pdev->dev;
+ if (gart_handle)
+ return -EIO;
+
BUILD_BUG_ON(PAGE_SHIFT != GART_PAGE_SHIFT);
/* the GART memory aperture is required */
@@ -401,6 +389,8 @@ static int tegra_gart_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, gart);
do_gart_setup(gart, NULL);
+
+ gart_handle = gart;
return 0;
fail:
@@ -423,6 +413,7 @@ static int tegra_gart_remove(struct platform_device *pdev)
if (gart->regs)
devm_iounmap(dev, gart->regs);
devm_kfree(dev, gart);
+ gart_handle = NULL;
return 0;
}
@@ -443,7 +434,7 @@ static struct platform_driver tegra_gart_driver = {
static int __devinit tegra_gart_init(void)
{
- register_iommu(&gart_iommu_ops);
+ bus_set_iommu(&platform_bus_type, &gart_iommu_ops);
return platform_driver_register(&tegra_gart_driver);
}