Skip to content

Commit

Permalink
drm/msm: fix IOMMU cleanup for -EPROBE_DEFER
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Stephane Viau authored and Rob Clark committed Jun 22, 2014
1 parent cf3198c commit 87e956e
Show file tree
Hide file tree
Showing 5 changed files with 44 additions and 7 deletions.
22 changes: 17 additions & 5 deletions drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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);
}

Expand Down Expand Up @@ -216,10 +226,6 @@ static int modeset_init(struct mdp5_kms *mdp5_kms)
return ret;
}

static const char *iommu_ports[] = {
"mdp_0",
};

static int get_clk(struct platform_device *pdev, struct clk **clkp,
const char *name)
{
Expand Down Expand Up @@ -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) {
Expand Down
1 change: 1 addition & 0 deletions drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
6 changes: 6 additions & 0 deletions drivers/gpu/drm/msm/msm_gem.c
Original file line number Diff line number Diff line change
Expand Up @@ -278,13 +278,19 @@ 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) {
struct msm_drm_private *priv = obj->dev->dev_private;
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);

Expand Down
21 changes: 19 additions & 2 deletions drivers/gpu/drm/msm/msm_iommu.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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]);
Expand All @@ -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)
{
Expand Down Expand Up @@ -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,
Expand Down
1 change: 1 addition & 0 deletions drivers/gpu/drm/msm/msm_mmu.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down

0 comments on commit 87e956e

Please sign in to comment.