Skip to content

Commit

Permalink
staging: omapdrm: Fix error paths during dmm init
Browse files Browse the repository at this point in the history
Failures during the dmm probe can cause the kernel to crash.  Moved
the spinlock to a global and moved list initializations immediately
after the allocation of the dmm private structure.

Signed-off-by: Andy Gross <andy.gross@ti.com>
Reviewed-by: Rob Clark <rob.clark@linaro.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
Andy Gross authored and Greg Kroah-Hartman committed Jun 11, 2012
1 parent 3953503 commit ef44593
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 21 deletions.
1 change: 0 additions & 1 deletion drivers/staging/omapdrm/omap_dmm_priv.h
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,6 @@ struct dmm {

/* allocation list and lock */
struct list_head alloc_head;
spinlock_t list_lock;
};

#endif
44 changes: 24 additions & 20 deletions drivers/staging/omapdrm/omap_dmm_tiler.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@
static struct tcm *containers[TILFMT_NFORMATS];
static struct dmm *omap_dmm;

/* global spinlock for protecting lists */
static DEFINE_SPINLOCK(list_lock);

/* Geometry table */
#define GEOM(xshift, yshift, bytes_per_pixel) { \
.x_shft = (xshift), \
Expand Down Expand Up @@ -147,13 +150,13 @@ static struct dmm_txn *dmm_txn_init(struct dmm *dmm, struct tcm *tcm)
down(&dmm->engine_sem);

/* grab an idle engine */
spin_lock(&dmm->list_lock);
spin_lock(&list_lock);
if (!list_empty(&dmm->idle_head)) {
engine = list_entry(dmm->idle_head.next, struct refill_engine,
idle_node);
list_del(&engine->idle_node);
}
spin_unlock(&dmm->list_lock);
spin_unlock(&list_lock);

BUG_ON(!engine);

Expand Down Expand Up @@ -256,9 +259,9 @@ static int dmm_txn_commit(struct dmm_txn *txn, bool wait)
}

cleanup:
spin_lock(&dmm->list_lock);
spin_lock(&list_lock);
list_add(&engine->idle_node, &dmm->idle_head);
spin_unlock(&dmm->list_lock);
spin_unlock(&list_lock);

up(&omap_dmm->engine_sem);
return ret;
Expand Down Expand Up @@ -351,9 +354,9 @@ struct tiler_block *tiler_reserve_2d(enum tiler_fmt fmt, uint16_t w,
}

/* add to allocation list */
spin_lock(&omap_dmm->list_lock);
spin_lock(&list_lock);
list_add(&block->alloc_node, &omap_dmm->alloc_head);
spin_unlock(&omap_dmm->list_lock);
spin_unlock(&list_lock);

return block;
}
Expand All @@ -374,9 +377,9 @@ struct tiler_block *tiler_reserve_1d(size_t size)
return ERR_PTR(-ENOMEM);
}

spin_lock(&omap_dmm->list_lock);
spin_lock(&list_lock);
list_add(&block->alloc_node, &omap_dmm->alloc_head);
spin_unlock(&omap_dmm->list_lock);
spin_unlock(&list_lock);

return block;
}
Expand All @@ -389,9 +392,9 @@ int tiler_release(struct tiler_block *block)
if (block->area.tcm)
dev_err(omap_dmm->dev, "failed to release block\n");

spin_lock(&omap_dmm->list_lock);
spin_lock(&list_lock);
list_del(&block->alloc_node);
spin_unlock(&omap_dmm->list_lock);
spin_unlock(&list_lock);

kfree(block);
return ret;
Expand Down Expand Up @@ -479,13 +482,13 @@ static int omap_dmm_remove(struct platform_device *dev)

if (omap_dmm) {
/* free all area regions */
spin_lock(&omap_dmm->list_lock);
spin_lock(&list_lock);
list_for_each_entry_safe(block, _block, &omap_dmm->alloc_head,
alloc_node) {
list_del(&block->alloc_node);
kfree(block);
}
spin_unlock(&omap_dmm->list_lock);
spin_unlock(&list_lock);

for (i = 0; i < omap_dmm->num_lut; i++)
if (omap_dmm->tcm && omap_dmm->tcm[i])
Expand All @@ -503,7 +506,7 @@ static int omap_dmm_remove(struct platform_device *dev)

vfree(omap_dmm->lut);

if (omap_dmm->irq != -1)
if (omap_dmm->irq > 0)
free_irq(omap_dmm->irq, omap_dmm);

iounmap(omap_dmm->base);
Expand All @@ -527,6 +530,10 @@ static int omap_dmm_probe(struct platform_device *dev)
goto fail;
}

/* initialize lists */
INIT_LIST_HEAD(&omap_dmm->alloc_head);
INIT_LIST_HEAD(&omap_dmm->idle_head);

/* lookup hwmod data - base address and irq */
mem = platform_get_resource(dev, IORESOURCE_MEM, 0);
if (!mem) {
Expand Down Expand Up @@ -629,7 +636,6 @@ static int omap_dmm_probe(struct platform_device *dev)
}

sema_init(&omap_dmm->engine_sem, omap_dmm->num_engines);
INIT_LIST_HEAD(&omap_dmm->idle_head);
for (i = 0; i < omap_dmm->num_engines; i++) {
omap_dmm->engines[i].id = i;
omap_dmm->engines[i].dmm = omap_dmm;
Expand Down Expand Up @@ -672,9 +678,6 @@ static int omap_dmm_probe(struct platform_device *dev)
containers[TILFMT_32BIT] = omap_dmm->tcm[0];
containers[TILFMT_PAGE] = omap_dmm->tcm[0];

INIT_LIST_HEAD(&omap_dmm->alloc_head);
spin_lock_init(&omap_dmm->list_lock);

area = (struct tcm_area) {
.is2d = true,
.tcm = NULL,
Expand All @@ -697,7 +700,8 @@ static int omap_dmm_probe(struct platform_device *dev)
return 0;

fail:
omap_dmm_remove(dev);
if (omap_dmm_remove(dev))
dev_err(&dev->dev, "cleanup failed\n");
return ret;
}

Expand Down Expand Up @@ -810,7 +814,7 @@ int tiler_map_show(struct seq_file *s, void *arg)
map[i] = global_map + i * (w_adj + 1);
map[i][w_adj] = 0;
}
spin_lock_irqsave(&omap_dmm->list_lock, flags);
spin_lock_irqsave(&list_lock, flags);

list_for_each_entry(block, &omap_dmm->alloc_head, alloc_node) {
if (block->fmt != TILFMT_PAGE) {
Expand All @@ -836,7 +840,7 @@ int tiler_map_show(struct seq_file *s, void *arg)
}
}

spin_unlock_irqrestore(&omap_dmm->list_lock, flags);
spin_unlock_irqrestore(&list_lock, flags);

if (s) {
seq_printf(s, "BEGIN DMM TILER MAP\n");
Expand Down

0 comments on commit ef44593

Please sign in to comment.