|
@@ -649,22 +649,15 @@ static int ipmmu_find_utlbs(struct ipmmu_vmsa_device *mmu, struct device *dev,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static int ipmmu_add_device(struct device *dev)
|
|
|
+static int ipmmu_init_platform_device(struct device *dev)
|
|
|
{
|
|
|
struct ipmmu_vmsa_archdata *archdata;
|
|
|
struct ipmmu_vmsa_device *mmu;
|
|
|
- struct iommu_group *group = NULL;
|
|
|
unsigned int *utlbs;
|
|
|
unsigned int i;
|
|
|
int num_utlbs;
|
|
|
int ret = -ENODEV;
|
|
|
|
|
|
- if (dev->archdata.iommu) {
|
|
|
- dev_warn(dev, "IOMMU driver already assigned to device %s\n",
|
|
|
- dev_name(dev));
|
|
|
- return -EINVAL;
|
|
|
- }
|
|
|
-
|
|
|
/* Find the master corresponding to the device. */
|
|
|
|
|
|
num_utlbs = of_count_phandle_with_args(dev->of_node, "iommus",
|
|
@@ -701,6 +694,36 @@ static int ipmmu_add_device(struct device *dev)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ archdata = kzalloc(sizeof(*archdata), GFP_KERNEL);
|
|
|
+ if (!archdata) {
|
|
|
+ ret = -ENOMEM;
|
|
|
+ goto error;
|
|
|
+ }
|
|
|
+
|
|
|
+ archdata->mmu = mmu;
|
|
|
+ archdata->utlbs = utlbs;
|
|
|
+ archdata->num_utlbs = num_utlbs;
|
|
|
+ dev->archdata.iommu = archdata;
|
|
|
+ return 0;
|
|
|
+
|
|
|
+error:
|
|
|
+ kfree(utlbs);
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+static int ipmmu_add_device(struct device *dev)
|
|
|
+{
|
|
|
+ struct ipmmu_vmsa_archdata *archdata;
|
|
|
+ struct ipmmu_vmsa_device *mmu = NULL;
|
|
|
+ struct iommu_group *group;
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ if (dev->archdata.iommu) {
|
|
|
+ dev_warn(dev, "IOMMU driver already assigned to device %s\n",
|
|
|
+ dev_name(dev));
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
/* Create a device group and add the device to it. */
|
|
|
group = iommu_group_alloc();
|
|
|
if (IS_ERR(group)) {
|
|
@@ -718,16 +741,9 @@ static int ipmmu_add_device(struct device *dev)
|
|
|
goto error;
|
|
|
}
|
|
|
|
|
|
- archdata = kzalloc(sizeof(*archdata), GFP_KERNEL);
|
|
|
- if (!archdata) {
|
|
|
- ret = -ENOMEM;
|
|
|
+ ret = ipmmu_init_platform_device(dev);
|
|
|
+ if (ret < 0)
|
|
|
goto error;
|
|
|
- }
|
|
|
-
|
|
|
- archdata->mmu = mmu;
|
|
|
- archdata->utlbs = utlbs;
|
|
|
- archdata->num_utlbs = num_utlbs;
|
|
|
- dev->archdata.iommu = archdata;
|
|
|
|
|
|
/*
|
|
|
* Create the ARM mapping, used by the ARM DMA mapping core to allocate
|
|
@@ -738,6 +754,8 @@ static int ipmmu_add_device(struct device *dev)
|
|
|
* - Make the mapping size configurable ? We currently use a 2GB mapping
|
|
|
* at a 1GB offset to ensure that NULL VAs will fault.
|
|
|
*/
|
|
|
+ archdata = dev->archdata.iommu;
|
|
|
+ mmu = archdata->mmu;
|
|
|
if (!mmu->mapping) {
|
|
|
struct dma_iommu_mapping *mapping;
|
|
|
|
|
@@ -762,16 +780,16 @@ static int ipmmu_add_device(struct device *dev)
|
|
|
return 0;
|
|
|
|
|
|
error:
|
|
|
- arm_iommu_release_mapping(mmu->mapping);
|
|
|
-
|
|
|
- kfree(dev->archdata.iommu);
|
|
|
- kfree(utlbs);
|
|
|
-
|
|
|
- dev->archdata.iommu = NULL;
|
|
|
+ if (mmu)
|
|
|
+ arm_iommu_release_mapping(mmu->mapping);
|
|
|
|
|
|
if (!IS_ERR_OR_NULL(group))
|
|
|
iommu_group_remove_device(dev);
|
|
|
|
|
|
+ kfree(archdata->utlbs);
|
|
|
+ kfree(archdata);
|
|
|
+ dev->archdata.iommu = NULL;
|
|
|
+
|
|
|
return ret;
|
|
|
}
|
|
|
|