iommu: arm-smmu: Vote for power in add_device and remove_device
These functions access iommu registers, so ensure the device is in
the proper state first.
Change-Id: I66df2c25a0eb072dc9c69604fbe32d0af2828303
Signed-off-by: Patrick Daly <pdaly@codeaurora.org>
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index d714e27..4d6ee1b 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -2374,6 +2374,10 @@
return -ENODEV;
}
+ ret = arm_smmu_power_on(smmu->pwr);
+ if (ret)
+ goto out_free;
+
ret = -EINVAL;
for (i = 0; i < fwspec->num_ids; i++) {
u16 sid = fwspec->ids[i];
@@ -2382,12 +2386,12 @@
if (sid & ~smmu->streamid_mask) {
dev_err(dev, "stream ID 0x%x out of range for SMMU (0x%x)\n",
sid, smmu->streamid_mask);
- goto out_free;
+ goto out_pwr_off;
}
if (mask & ~smmu->smr_mask_mask) {
dev_err(dev, "SMR mask 0x%x out of range for SMMU (0x%x)\n",
sid, smmu->smr_mask_mask);
- goto out_free;
+ goto out_pwr_off;
}
}
@@ -2395,7 +2399,7 @@
cfg = kzalloc(offsetof(struct arm_smmu_master_cfg, smendx[i]),
GFP_KERNEL);
if (!cfg)
- goto out_free;
+ goto out_pwr_off;
cfg->smmu = smmu;
fwspec->iommu_priv = cfg;
@@ -2404,10 +2408,13 @@
ret = arm_smmu_master_alloc_smes(dev);
if (ret)
- goto out_free;
+ goto out_pwr_off;
+ arm_smmu_power_off(smmu->pwr);
return 0;
+out_pwr_off:
+ arm_smmu_power_off(smmu->pwr);
out_free:
if (fwspec)
kfree(fwspec->iommu_priv);
@@ -2418,14 +2425,22 @@
static void arm_smmu_remove_device(struct device *dev)
{
struct iommu_fwspec *fwspec = dev->iommu_fwspec;
+ struct arm_smmu_device *smmu;
if (!fwspec || fwspec->ops != &arm_smmu_ops)
return;
+ smmu = fwspec_smmu(fwspec);
+ if (arm_smmu_power_on(smmu->pwr)) {
+ WARN_ON(1);
+ return;
+ }
+
arm_smmu_master_free_smes(fwspec);
iommu_group_remove_device(dev);
kfree(fwspec->iommu_priv);
iommu_fwspec_free(dev);
+ arm_smmu_power_off(smmu->pwr);
}
static struct iommu_group *arm_smmu_device_group(struct device *dev)