ARM: etm: Add some missing locks and error checks

It is not safe to call etm_lock or etb_lock without holding the
mutex since another thread may also have unlocked the registers.

Also add some missing checks for valid etb_regs in the etm sysfs
entries.

Change-Id: I939f76a6ea7546a8fc0d4ddafa2fd2b6f38103bb
Signed-off-by: Arve Hjønnevåg <arve@android.com>
This commit is contained in:
Arve Hjønnevåg
2011-02-14 21:09:51 -08:00
parent f717d8b087
commit 848bc34c41

View File

@@ -264,8 +264,13 @@ static void etm_dump(void)
static void sysrq_etm_dump(int key)
{
if (!mutex_trylock(&tracer.mutex)) {
printk(KERN_INFO "Tracing hardware busy\n");
return;
}
dev_dbg(tracer.dev, "Dumping ETB buffer\n");
etm_dump();
mutex_unlock(&tracer.mutex);
}
static struct sysrq_key_op sysrq_etm_op = {
@@ -374,6 +379,7 @@ static int etb_probe(struct amba_device *dev, const struct amba_id *id)
if (ret)
goto out;
mutex_lock(&t->mutex);
t->etb_regs = ioremap_nocache(dev->res.start, resource_size(&dev->res));
if (!t->etb_regs) {
ret = -ENOMEM;
@@ -382,6 +388,16 @@ static int etb_probe(struct amba_device *dev, const struct amba_id *id)
amba_set_drvdata(dev, t);
etb_unlock(t);
t->etb_bufsz = etb_readl(t, ETBR_DEPTH);
dev_dbg(&dev->dev, "Size: %x\n", t->etb_bufsz);
/* make sure trace capture is disabled */
etb_writel(t, 0, ETBR_CTRL);
etb_writel(t, 0x1000, ETBR_FORMATTERCTRL);
etb_lock(t);
mutex_unlock(&t->mutex);
etb_miscdev.parent = &dev->dev;
ret = misc_register(&etb_miscdev);
@@ -395,25 +411,19 @@ static int etb_probe(struct amba_device *dev, const struct amba_id *id)
else
clk_enable(t->emu_clk);
etb_unlock(t);
t->etb_bufsz = etb_readl(t, ETBR_DEPTH);
dev_dbg(&dev->dev, "Size: %x\n", t->etb_bufsz);
/* make sure trace capture is disabled */
etb_writel(t, 0, ETBR_CTRL);
etb_writel(t, 0x1000, ETBR_FORMATTERCTRL);
etb_lock(t);
dev_dbg(&dev->dev, "ETB AMBA driver initialized.\n");
out:
return ret;
out_unmap:
mutex_lock(&t->mutex);
amba_set_drvdata(dev, NULL);
iounmap(t->etb_regs);
t->etb_regs = NULL;
out_release:
mutex_unlock(&t->mutex);
amba_release_regions(dev);
return ret;
@@ -475,7 +485,10 @@ static ssize_t trace_running_store(struct kobject *kobj,
return -EINVAL;
mutex_lock(&tracer.mutex);
ret = value ? trace_start(&tracer) : trace_stop(&tracer);
if (!tracer.etb_regs)
ret = -ENODEV;
else
ret = value ? trace_start(&tracer) : trace_stop(&tracer);
mutex_unlock(&tracer.mutex);
return ret ? : n;
@@ -491,18 +504,25 @@ static ssize_t trace_info_show(struct kobject *kobj,
u32 etb_wa, etb_ra, etb_st, etb_fc, etm_ctrl, etm_st;
int datalen;
etb_unlock(&tracer);
datalen = etb_getdatalen(&tracer);
etb_wa = etb_readl(&tracer, ETBR_WRITEADDR);
etb_ra = etb_readl(&tracer, ETBR_READADDR);
etb_st = etb_readl(&tracer, ETBR_STATUS);
etb_fc = etb_readl(&tracer, ETBR_FORMATTERCTRL);
etb_lock(&tracer);
mutex_lock(&tracer.mutex);
if (tracer.etb_regs) {
etb_unlock(&tracer);
datalen = etb_getdatalen(&tracer);
etb_wa = etb_readl(&tracer, ETBR_WRITEADDR);
etb_ra = etb_readl(&tracer, ETBR_READADDR);
etb_st = etb_readl(&tracer, ETBR_STATUS);
etb_fc = etb_readl(&tracer, ETBR_FORMATTERCTRL);
etb_lock(&tracer);
} else {
etb_wa = etb_ra = etb_st = etb_fc = ~0;
datalen = -1;
}
etm_unlock(&tracer);
etm_ctrl = etm_readl(&tracer, ETMR_CTRL);
etm_st = etm_readl(&tracer, ETMR_STATUS);
etm_lock(&tracer);
mutex_unlock(&tracer.mutex);
return sprintf(buf, "Trace buffer len: %d\nComparator pairs: %d\n"
"ETBR_WRITEADDR:\t%08x\n"
@@ -652,7 +672,6 @@ static int etm_probe(struct amba_device *dev, const struct amba_id *id)
amba_set_drvdata(dev, t);
mutex_init(&t->mutex);
t->dev = &dev->dev;
t->flags = TRACER_CYCLE_ACC | TRACER_TRACE_DATA;
t->etm_portsz = 1;
@@ -746,6 +765,8 @@ static int __init etm_init(void)
{
int retval;
mutex_init(&tracer.mutex);
retval = amba_driver_register(&etb_driver);
if (retval) {
printk(KERN_ERR "Failed to register etb\n");