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: Jordan Crouse <jcrouse@codeaurora.org>
This commit is contained in:
Jordan Crouse 2017-04-07 15:01:42 -06:00
parent 4e061d8b60
commit f0eb0ed585
3 changed files with 51 additions and 44 deletions

View file

@ -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;

View file

@ -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);
}
}
enable_iommu_clocks(iommu);
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]);
}
}
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 = {

View file

@ -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__ */