drm/msm: fix IOMMU cleanup for -EPROBE_DEFER
authorStephane Viau <sviau@codeaurora.org>
Tue, 17 Jun 2014 14:32:37 +0000 (10:32 -0400)
committerRob Clark <robdclark@gmail.com>
Sun, 22 Jun 2014 12:32:10 +0000 (08:32 -0400)
If probe fails after IOMMU is attached, we need to detach in order to
clean up properly.  Before this change, IOMMU faults would occur if the
probe failed (-EPROBE_DEFER).

Signed-off-by: Stephane Viau <sviau@codeaurora.org>
Signed-off-by: Rob Clark <robdclark@gmail.com>
drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c
drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h
drivers/gpu/drm/msm/msm_gem.c
drivers/gpu/drm/msm/msm_iommu.c
drivers/gpu/drm/msm/msm_mmu.h

index 42caf7f..71510ee 100644 (file)
 #include "msm_mmu.h"
 #include "mdp5_kms.h"
 
+static const char *iommu_ports[] = {
+               "mdp_0",
+};
+
 static struct mdp5_platform_config *mdp5_get_config(struct platform_device *dev);
 
 static int mdp5_hw_init(struct msm_kms *kms)
@@ -104,6 +108,12 @@ static void mdp5_preclose(struct msm_kms *kms, struct drm_file *file)
 static void mdp5_destroy(struct msm_kms *kms)
 {
        struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
+       struct msm_mmu *mmu = mdp5_kms->mmu;
+
+       if (mmu) {
+               mmu->funcs->detach(mmu, iommu_ports, ARRAY_SIZE(iommu_ports));
+               mmu->funcs->destroy(mmu);
+       }
        kfree(mdp5_kms);
 }
 
@@ -216,10 +226,6 @@ fail:
        return ret;
 }
 
-static const char *iommu_ports[] = {
-               "mdp_0",
-};
-
 static int get_clk(struct platform_device *pdev, struct clk **clkp,
                const char *name)
 {
@@ -317,17 +323,23 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev)
                mmu = msm_iommu_new(dev, config->iommu);
                if (IS_ERR(mmu)) {
                        ret = PTR_ERR(mmu);
+                       dev_err(dev->dev, "failed to init iommu: %d\n", ret);
                        goto fail;
                }
+
                ret = mmu->funcs->attach(mmu, iommu_ports,
                                ARRAY_SIZE(iommu_ports));
-               if (ret)
+               if (ret) {
+                       dev_err(dev->dev, "failed to attach iommu: %d\n", ret);
+                       mmu->funcs->destroy(mmu);
                        goto fail;
+               }
        } else {
                dev_info(dev->dev, "no iommu, fallback to phys "
                                "contig buffers for scanout\n");
                mmu = NULL;
        }
+       mdp5_kms->mmu = mmu;
 
        mdp5_kms->id = msm_register_mmu(dev, mmu);
        if (mdp5_kms->id < 0) {
index c8b1a25..6e981b6 100644 (file)
@@ -33,6 +33,7 @@ struct mdp5_kms {
 
        /* mapper-id used to request GEM buffer mapped for scanout: */
        int id;
+       struct msm_mmu *mmu;
 
        /* for tracking smp allocation amongst pipes: */
        mdp5_smp_state_t smp_state;
index bb8026d..690d7e7 100644 (file)
@@ -278,6 +278,7 @@ int msm_gem_get_iova_locked(struct drm_gem_object *obj, int id,
                uint32_t *iova)
 {
        struct msm_gem_object *msm_obj = to_msm_bo(obj);
+       struct drm_device *dev = obj->dev;
        int ret = 0;
 
        if (!msm_obj->domain[id].iova) {
@@ -285,6 +286,11 @@ int msm_gem_get_iova_locked(struct drm_gem_object *obj, int id,
                struct msm_mmu *mmu = priv->mmus[id];
                struct page **pages = get_pages(obj);
 
+               if (!mmu) {
+                       dev_err(dev->dev, "null MMU pointer\n");
+                       return -EINVAL;
+               }
+
                if (IS_ERR(pages))
                        return PTR_ERR(pages);
 
index 198ed84..4b2ad91 100644 (file)
@@ -28,7 +28,7 @@ static int msm_fault_handler(struct iommu_domain *iommu, struct device *dev,
                unsigned long iova, int flags, void *arg)
 {
        DBG("*** fault: iova=%08lx, flags=%d", iova, flags);
-       return 0;
+       return -ENOSYS;
 }
 
 static int msm_iommu_attach(struct msm_mmu *mmu, const char **names, int cnt)
@@ -40,8 +40,10 @@ static int msm_iommu_attach(struct msm_mmu *mmu, const char **names, int cnt)
        for (i = 0; i < cnt; i++) {
                struct device *msm_iommu_get_ctx(const char *ctx_name);
                struct device *ctx = msm_iommu_get_ctx(names[i]);
-               if (IS_ERR_OR_NULL(ctx))
+               if (IS_ERR_OR_NULL(ctx)) {
+                       dev_warn(dev->dev, "couldn't get %s context", names[i]);
                        continue;
+               }
                ret = iommu_attach_device(iommu->domain, ctx);
                if (ret) {
                        dev_warn(dev->dev, "could not attach iommu to %s", names[i]);
@@ -52,6 +54,20 @@ static int msm_iommu_attach(struct msm_mmu *mmu, const char **names, int cnt)
        return 0;
 }
 
+static void msm_iommu_detach(struct msm_mmu *mmu, const char **names, int cnt)
+{
+       struct msm_iommu *iommu = to_msm_iommu(mmu);
+       int i;
+
+       for (i = 0; i < cnt; i++) {
+               struct device *msm_iommu_get_ctx(const char *ctx_name);
+               struct device *ctx = msm_iommu_get_ctx(names[i]);
+               if (IS_ERR_OR_NULL(ctx))
+                       continue;
+               iommu_detach_device(iommu->domain, ctx);
+       }
+}
+
 static int msm_iommu_map(struct msm_mmu *mmu, uint32_t iova,
                struct sg_table *sgt, unsigned len, int prot)
 {
@@ -127,6 +143,7 @@ static void msm_iommu_destroy(struct msm_mmu *mmu)
 
 static const struct msm_mmu_funcs funcs = {
                .attach = msm_iommu_attach,
+               .detach = msm_iommu_detach,
                .map = msm_iommu_map,
                .unmap = msm_iommu_unmap,
                .destroy = msm_iommu_destroy,
index 0303244..21da6d1 100644 (file)
@@ -22,6 +22,7 @@
 
 struct msm_mmu_funcs {
        int (*attach)(struct msm_mmu *mmu, const char **names, int cnt);
+       void (*detach)(struct msm_mmu *mmu, const char **names, int cnt);
        int (*map)(struct msm_mmu *mmu, uint32_t iova, struct sg_table *sgt,
                        unsigned len, int prot);
        int (*unmap)(struct msm_mmu *mmu, uint32_t iova, struct sg_table *sgt,