Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 87e956e9 authored by Stephane Viau's avatar Stephane Viau Committed by Rob Clark
Browse files

drm/msm: fix IOMMU cleanup for -EPROBE_DEFER



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: default avatarStephane Viau <sviau@codeaurora.org>
Signed-off-by: default avatarRob Clark <robdclark@gmail.com>
parent cf3198c2
Loading
Loading
Loading
Loading
+17 −5
Original line number Diff line number Diff line
@@ -20,6 +20,10 @@
#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) {
+1 −0
Original line number Diff line number Diff line
@@ -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;
+6 −0
Original line number Diff line number Diff line
@@ -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);

+19 −2
Original line number Diff line number Diff line
@@ -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,
+1 −0
Original line number Diff line number Diff line
@@ -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,