iommu/exynos: Add support for binding more than one sysmmu to master device
authorMarek Szyprowski <m.szyprowski@samsung.com>
Tue, 19 May 2015 13:20:33 +0000 (15:20 +0200)
committerJoerg Roedel <jroedel@suse.de>
Fri, 29 May 2015 08:49:47 +0000 (10:49 +0200)
This patch adds support for assigning more than one SYSMMU controller to
the master device. This has been achieved simply by chaning the struct
device pointer in struct exynos_iommu_owner into the list of struct
sysmmu_drvdata of all controllers assigned to the given master device.

Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
Tested-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
Signed-off-by: Joerg Roedel <jroedel@suse.de>
drivers/iommu/exynos-iommu.c

index 99ed39c89e0b5be59d6bfd672dbc7df7a3f218dd..b7f679c4659ccbafedb68e9a9bef67f4b757d7de 100644 (file)
@@ -187,7 +187,7 @@ static char *sysmmu_fault_name[SYSMMU_FAULTS_NUM] = {
  * pointer.
 */
 struct exynos_iommu_owner {
-       struct device *sysmmu;          /* sysmmu controller for given master */
+       struct list_head controllers;   /* list of sysmmu_drvdata.owner_node */
 };
 
 /*
@@ -221,6 +221,7 @@ struct sysmmu_drvdata {
        spinlock_t lock;                /* lock for modyfying state */
        struct exynos_iommu_domain *domain; /* domain we belong to */
        struct list_head domain_node;   /* node for domain clients list */
+       struct list_head owner_node;    /* node for owner controllers list */
        phys_addr_t pgtable;            /* assigned page table structure */
        unsigned int version;           /* our version */
 };
@@ -713,8 +714,7 @@ static int exynos_iommu_attach_device(struct iommu_domain *iommu_domain,
        if (!has_sysmmu(dev))
                return -ENODEV;
 
-       data = dev_get_drvdata(owner->sysmmu);
-       if (data) {
+       list_for_each_entry(data, &owner->controllers, owner_node) {
                ret = __sysmmu_enable(data, pagetable, domain);
                if (ret >= 0) {
                        data->master = dev;
@@ -742,7 +742,7 @@ static void exynos_iommu_detach_device(struct iommu_domain *iommu_domain,
 {
        struct exynos_iommu_domain *domain = to_exynos_domain(iommu_domain);
        phys_addr_t pagetable = virt_to_phys(domain->pgtable);
-       struct sysmmu_drvdata *data;
+       struct sysmmu_drvdata *data, *next;
        unsigned long flags;
        bool found = false;
 
@@ -750,14 +750,13 @@ static void exynos_iommu_detach_device(struct iommu_domain *iommu_domain,
                return;
 
        spin_lock_irqsave(&domain->lock, flags);
-       list_for_each_entry(data, &domain->clients, domain_node) {
+       list_for_each_entry_safe(data, next, &domain->clients, domain_node) {
                if (data->master == dev) {
                        if (__sysmmu_disable(data)) {
                                data->master = NULL;
                                list_del_init(&data->domain_node);
                        }
                        found = true;
-                       break;
                }
        }
        spin_unlock_irqrestore(&domain->lock, flags);