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

Commit f0eb0ed5 authored by Jordan Crouse's avatar Jordan Crouse
Browse files

drm/msm: Add enable/disable hooks for mmu



5XX targets that are using per-process pagetables will need to
keep the IOMMU clocks on the entire time because we don't know
exactly when the GPU might touch it.  That said there are
occassional depencency issues if the clocks are enabled out
of order.  To be certain we should enable the MMU clocks last
and disable them first.  Add enable/disable hooks to the MMU
struct to do this cleanly from the GPU pm_resume / pm_suspend
paths.

Change-Id: Ic0dedbad8e2298e55c90b29eed657baa0933ddcf
Signed-off-by: default avatarJordan Crouse <jcrouse@codeaurora.org>
parent 4e061d8b
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -183,6 +183,9 @@ int msm_gpu_pm_resume(struct msm_gpu *gpu)
	if (ret)
		return ret;

	if (gpu->aspace && gpu->aspace->mmu)
		msm_mmu_enable(gpu->aspace->mmu);

	return 0;
}

@@ -203,6 +206,9 @@ int msm_gpu_pm_suspend(struct msm_gpu *gpu)
	if (WARN_ON(gpu->active_cnt < 0))
		return -EINVAL;

	if (gpu->aspace && gpu->aspace->mmu)
		msm_mmu_disable(gpu->aspace->mmu);

	ret = disable_axi(gpu);
	if (ret)
		return ret;
+31 −44
Original line number Diff line number Diff line
@@ -27,49 +27,17 @@ static int msm_fault_handler(struct iommu_domain *iommu, struct device *dev,
	return 0;
}

static void enable_iommu_clocks(struct msm_iommu *iommu)
{
	int i;

	for (i = 0; i < iommu->nr_clocks; i++) {
		if (iommu->clocks[i])
			clk_prepare_enable(iommu->clocks[i]);
	}
}

static void disable_iommu_clocks(struct msm_iommu *iommu)
{
	int i;

	for (i = 0; i < iommu->nr_clocks; i++) {
		if (iommu->clocks[i])
			clk_disable_unprepare(iommu->clocks[i]);
	}
}

/*
 * Get and enable the IOMMU clocks so that we can make
 * sure they stay on the entire duration so that we can
 * safely change the pagetable from the GPU
 */
static void get_iommu_clocks(struct msm_iommu *iommu, struct device *dev)
static void iommu_get_clocks(struct msm_iommu *iommu, struct device *dev)
{
	struct property *prop;
	const char *name;
	int i = 0;

	if (iommu->nr_clocks) {
		enable_iommu_clocks(iommu);
		return;
	}

	iommu->nr_clocks =
		of_property_count_strings(dev->of_node, "clock-names");

	if (iommu->nr_clocks < 0) {
		iommu->nr_clocks = 0;
	if (iommu->nr_clocks < 0)
		return;
	}

	if (WARN_ON(iommu->nr_clocks > ARRAY_SIZE(iommu->clocks)))
		iommu->nr_clocks = ARRAY_SIZE(iommu->clocks);
@@ -78,11 +46,34 @@ static void get_iommu_clocks(struct msm_iommu *iommu, struct device *dev)
		if (i == iommu->nr_clocks)
			break;

		iommu->clocks[i] =  clk_get(dev, name);
		i++;
		iommu->clocks[i++] =  clk_get(dev, name);
	}
}


static void msm_iommu_clocks_enable(struct msm_mmu *mmu)
{
	struct msm_iommu *iommu = to_msm_iommu(mmu);
	int i;

	if (!iommu->nr_clocks)
		iommu_get_clocks(iommu, mmu->dev->parent);

	for (i = 0; i < iommu->nr_clocks; i++) {
		if (iommu->clocks[i])
			clk_prepare_enable(iommu->clocks[i]);
	}
}

	enable_iommu_clocks(iommu);
static void msm_iommu_clocks_disable(struct msm_mmu *mmu)
{
	struct msm_iommu *iommu = to_msm_iommu(mmu);
	int i;

	for (i = 0; i < iommu->nr_clocks; i++) {
		if (iommu->clocks[i])
			clk_disable_unprepare(iommu->clocks[i]);
	}
}

static int msm_iommu_attach(struct msm_mmu *mmu, const char **names,
@@ -103,16 +94,12 @@ static int msm_iommu_attach_user(struct msm_mmu *mmu, const char **names,
	iommu->allow_dynamic = !iommu_domain_set_attr(iommu->domain,
		DOMAIN_ATTR_ENABLE_TTBR1, &val) ? true : false;

	get_iommu_clocks(iommu, mmu->dev->parent);

	/* Mark the GPU as I/O coherent if it is supported */
	iommu->is_coherent = of_dma_is_coherent(mmu->dev->of_node);

	ret = iommu_attach_device(iommu->domain, mmu->dev);
	if (ret) {
		disable_iommu_clocks(iommu);
	if (ret)
		return ret;
	}

	/*
	 * Get the context bank for the base domain; this will be shared with
@@ -160,8 +147,6 @@ static void msm_iommu_detach(struct msm_mmu *mmu)
	struct msm_iommu *iommu = to_msm_iommu(mmu);

	iommu_detach_device(iommu->domain, mmu->dev);

	disable_iommu_clocks(iommu);
}

static void msm_iommu_detach_dynamic(struct msm_mmu *mmu)
@@ -261,6 +246,8 @@ static const struct msm_mmu_funcs user_funcs = {
		.map = msm_iommu_map,
		.unmap = msm_iommu_unmap,
		.destroy = msm_iommu_destroy,
		.enable = msm_iommu_clocks_enable,
		.disable = msm_iommu_clocks_disable,
};

static const struct msm_mmu_funcs dynamic_funcs = {
+14 −0
Original line number Diff line number Diff line
@@ -43,6 +43,8 @@ struct msm_mmu_funcs {
	void (*unmap)(struct msm_mmu *mmu, uint64_t iova, struct sg_table *sgt,
			void *priv);
	void (*destroy)(struct msm_mmu *mmu);
	void (*enable)(struct msm_mmu *mmu);
	void (*disable)(struct msm_mmu *mmu);
};

struct msm_mmu {
@@ -68,4 +70,16 @@ struct msm_mmu *msm_iommu_new(struct device *parent,
/* Create a new dynamic domain for GPU */
struct msm_mmu *msm_iommu_new_dynamic(struct msm_mmu *orig);

static inline void msm_mmu_enable(struct msm_mmu *mmu)
{
	if (mmu->funcs->enable)
		mmu->funcs->enable(mmu);
}

static inline void msm_mmu_disable(struct msm_mmu *mmu)
{
	if (mmu->funcs->disable)
		mmu->funcs->disable(mmu);
}

#endif /* __MSM_MMU_H__ */