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: Stephane Viau <sviau@codeaurora.org>
Signed-off-by: Rob Clark <robdclark@gmail.com>
This commit is contained in:
Stephane Viau 2014-06-17 10:32:37 -04:00 committed by Rob Clark
parent cf3198c205
commit 87e956e9be
5 changed files with 44 additions and 7 deletions

View File

@ -20,6 +20,10 @@
#include "msm_mmu.h" #include "msm_mmu.h"
#include "mdp5_kms.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 struct mdp5_platform_config *mdp5_get_config(struct platform_device *dev);
static int mdp5_hw_init(struct msm_kms *kms) 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) static void mdp5_destroy(struct msm_kms *kms)
{ {
struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_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); kfree(mdp5_kms);
} }
@ -216,10 +226,6 @@ fail:
return ret; return ret;
} }
static const char *iommu_ports[] = {
"mdp_0",
};
static int get_clk(struct platform_device *pdev, struct clk **clkp, static int get_clk(struct platform_device *pdev, struct clk **clkp,
const char *name) const char *name)
{ {
@ -317,17 +323,23 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev)
mmu = msm_iommu_new(dev, config->iommu); mmu = msm_iommu_new(dev, config->iommu);
if (IS_ERR(mmu)) { if (IS_ERR(mmu)) {
ret = PTR_ERR(mmu); ret = PTR_ERR(mmu);
dev_err(dev->dev, "failed to init iommu: %d\n", ret);
goto fail; goto fail;
} }
ret = mmu->funcs->attach(mmu, iommu_ports, ret = mmu->funcs->attach(mmu, iommu_ports,
ARRAY_SIZE(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; goto fail;
}
} else { } else {
dev_info(dev->dev, "no iommu, fallback to phys " dev_info(dev->dev, "no iommu, fallback to phys "
"contig buffers for scanout\n"); "contig buffers for scanout\n");
mmu = NULL; mmu = NULL;
} }
mdp5_kms->mmu = mmu;
mdp5_kms->id = msm_register_mmu(dev, mmu); mdp5_kms->id = msm_register_mmu(dev, mmu);
if (mdp5_kms->id < 0) { if (mdp5_kms->id < 0) {

View File

@ -33,6 +33,7 @@ struct mdp5_kms {
/* mapper-id used to request GEM buffer mapped for scanout: */ /* mapper-id used to request GEM buffer mapped for scanout: */
int id; int id;
struct msm_mmu *mmu;
/* for tracking smp allocation amongst pipes: */ /* for tracking smp allocation amongst pipes: */
mdp5_smp_state_t smp_state; mdp5_smp_state_t smp_state;

View File

@ -278,6 +278,7 @@ int msm_gem_get_iova_locked(struct drm_gem_object *obj, int id,
uint32_t *iova) uint32_t *iova)
{ {
struct msm_gem_object *msm_obj = to_msm_bo(obj); struct msm_gem_object *msm_obj = to_msm_bo(obj);
struct drm_device *dev = obj->dev;
int ret = 0; int ret = 0;
if (!msm_obj->domain[id].iova) { 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 msm_mmu *mmu = priv->mmus[id];
struct page **pages = get_pages(obj); struct page **pages = get_pages(obj);
if (!mmu) {
dev_err(dev->dev, "null MMU pointer\n");
return -EINVAL;
}
if (IS_ERR(pages)) if (IS_ERR(pages))
return PTR_ERR(pages); return PTR_ERR(pages);

View File

@ -28,7 +28,7 @@ static int msm_fault_handler(struct iommu_domain *iommu, struct device *dev,
unsigned long iova, int flags, void *arg) unsigned long iova, int flags, void *arg)
{ {
DBG("*** fault: iova=%08lx, flags=%d", iova, flags); 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) 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++) { for (i = 0; i < cnt; i++) {
struct device *msm_iommu_get_ctx(const char *ctx_name); struct device *msm_iommu_get_ctx(const char *ctx_name);
struct device *ctx = msm_iommu_get_ctx(names[i]); 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; continue;
}
ret = iommu_attach_device(iommu->domain, ctx); ret = iommu_attach_device(iommu->domain, ctx);
if (ret) { if (ret) {
dev_warn(dev->dev, "could not attach iommu to %s", names[i]); 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; 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, static int msm_iommu_map(struct msm_mmu *mmu, uint32_t iova,
struct sg_table *sgt, unsigned len, int prot) 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 = { static const struct msm_mmu_funcs funcs = {
.attach = msm_iommu_attach, .attach = msm_iommu_attach,
.detach = msm_iommu_detach,
.map = msm_iommu_map, .map = msm_iommu_map,
.unmap = msm_iommu_unmap, .unmap = msm_iommu_unmap,
.destroy = msm_iommu_destroy, .destroy = msm_iommu_destroy,

View File

@ -22,6 +22,7 @@
struct msm_mmu_funcs { struct msm_mmu_funcs {
int (*attach)(struct msm_mmu *mmu, const char **names, int cnt); 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, int (*map)(struct msm_mmu *mmu, uint32_t iova, struct sg_table *sgt,
unsigned len, int prot); unsigned len, int prot);
int (*unmap)(struct msm_mmu *mmu, uint32_t iova, struct sg_table *sgt, int (*unmap)(struct msm_mmu *mmu, uint32_t iova, struct sg_table *sgt,