coresight: change ETM locking scheme from mutex to spinlock

Switch to using spinlocks instead of mutexes to make apis
callable from atomic context.

Change-Id: I6c249b66c7f9db3d6028f1ab92bacfbcf43b150e
Signed-off-by: Pratik Patel <pratikp@codeaurora.org>
This commit is contained in:
Pratik Patel 2012-10-23 21:12:07 -07:00 committed by Iliyan Malchev
parent 05ec10729f
commit 79e8303e69

View file

@ -25,7 +25,7 @@
#include <linux/wakelock.h>
#include <linux/sysfs.h>
#include <linux/stat.h>
#include <linux/mutex.h>
#include <linux/spinlock.h>
#include <linux/clk.h>
#include <linux/cpu.h>
#include <linux/of_coresight.h>
@ -192,7 +192,7 @@ struct etm_drvdata {
struct device *dev;
struct coresight_device *csdev;
struct clk *clk;
struct mutex mutex;
spinlock_t spinlock;
struct wake_lock wake_lock;
int cpu;
uint8_t arch;
@ -445,14 +445,16 @@ static int etm_enable(struct coresight_device *csdev)
if (ret)
goto err_clk;
mutex_lock(&drvdata->mutex);
spin_lock(&drvdata->spinlock);
/*
* Executing __etm_enable on the cpu whose ETM is being enabled
* ensures that register writes occur when cpu is powered.
*/
smp_call_function_single(drvdata->cpu, __etm_enable, drvdata, 1);
drvdata->enable = true;
mutex_unlock(&drvdata->mutex);
spin_unlock(&drvdata->spinlock);
wake_unlock(&drvdata->wake_lock);
@ -488,14 +490,16 @@ static void etm_disable(struct coresight_device *csdev)
wake_lock(&drvdata->wake_lock);
mutex_lock(&drvdata->mutex);
spin_lock(&drvdata->spinlock);
/*
* Executing __etm_disable on the cpu whose ETM is being disabled
* ensures that register writes occur when cpu is powered.
*/
smp_call_function_single(drvdata->cpu, __etm_disable, drvdata, 1);
drvdata->enable = false;
mutex_unlock(&drvdata->mutex);
spin_unlock(&drvdata->spinlock);
clk_disable_unprepare(drvdata->clk);
@ -564,7 +568,7 @@ static ssize_t etm_store_reset(struct device *dev,
if (sscanf(buf, "%lx", &val) != 1)
return -EINVAL;
mutex_lock(&drvdata->mutex);
spin_lock(&drvdata->spinlock);
if (val) {
drvdata->mode = ETM_MODE_EXCLUDE;
drvdata->ctrl = 0x0;
@ -608,7 +612,7 @@ static ssize_t etm_store_reset(struct device *dev,
drvdata->sync_freq = 0x80;
drvdata->timestamp_event = 0x406F;
}
mutex_unlock(&drvdata->mutex);
spin_unlock(&drvdata->spinlock);
return size;
}
static DEVICE_ATTR(reset, S_IRUGO | S_IWUSR, etm_show_reset, etm_store_reset);
@ -631,7 +635,7 @@ static ssize_t etm_store_mode(struct device *dev, struct device_attribute *attr,
if (sscanf(buf, "%lx", &val) != 1)
return -EINVAL;
mutex_lock(&drvdata->mutex);
spin_lock(&drvdata->spinlock);
drvdata->mode = val & ETM_MODE_ALL;
if (drvdata->mode & ETM_MODE_EXCLUDE)
@ -658,7 +662,7 @@ static ssize_t etm_store_mode(struct device *dev, struct device_attribute *attr,
drvdata->ctrl |= (BIT(14) | BIT(15));
else
drvdata->ctrl &= ~(BIT(14) | BIT(15));
mutex_unlock(&drvdata->mutex);
spin_unlock(&drvdata->spinlock);
return size;
}
@ -760,12 +764,13 @@ static ssize_t etm_store_addr_idx(struct device *dev,
if (val >= drvdata->nr_addr_cmp)
return -EINVAL;
/* Use mutex to ensure index doesn't change while it gets dereferenced
* multiple times within a mutex block elsewhere.
/*
* Use spinlock to ensure index doesn't change while it gets
* dereferenced multiple times within a spinlock block elsewhere.
*/
mutex_lock(&drvdata->mutex);
spin_lock(&drvdata->spinlock);
drvdata->addr_idx = val;
mutex_unlock(&drvdata->mutex);
spin_unlock(&drvdata->spinlock);
return size;
}
static DEVICE_ATTR(addr_idx, S_IRUGO | S_IWUSR, etm_show_addr_idx,
@ -778,16 +783,16 @@ static ssize_t etm_show_addr_single(struct device *dev,
unsigned long val;
uint8_t idx;
mutex_lock(&drvdata->mutex);
spin_lock(&drvdata->spinlock);
idx = drvdata->addr_idx;
if (!(drvdata->addr_type[idx] == ETM_ADDR_TYPE_NONE ||
drvdata->addr_type[idx] == ETM_ADDR_TYPE_SINGLE)) {
mutex_unlock(&drvdata->mutex);
spin_unlock(&drvdata->spinlock);
return -EPERM;
}
val = drvdata->addr_val[idx];
mutex_unlock(&drvdata->mutex);
spin_unlock(&drvdata->spinlock);
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
}
@ -802,17 +807,17 @@ static ssize_t etm_store_addr_single(struct device *dev,
if (sscanf(buf, "%lx", &val) != 1)
return -EINVAL;
mutex_lock(&drvdata->mutex);
spin_lock(&drvdata->spinlock);
idx = drvdata->addr_idx;
if (!(drvdata->addr_type[idx] == ETM_ADDR_TYPE_NONE ||
drvdata->addr_type[idx] == ETM_ADDR_TYPE_SINGLE)) {
mutex_unlock(&drvdata->mutex);
spin_unlock(&drvdata->spinlock);
return -EPERM;
}
drvdata->addr_val[idx] = val;
drvdata->addr_type[idx] = ETM_ADDR_TYPE_SINGLE;
mutex_unlock(&drvdata->mutex);
spin_unlock(&drvdata->spinlock);
return size;
}
static DEVICE_ATTR(addr_single, S_IRUGO | S_IWUSR, etm_show_addr_single,
@ -825,23 +830,23 @@ static ssize_t etm_show_addr_range(struct device *dev,
unsigned long val1, val2;
uint8_t idx;
mutex_lock(&drvdata->mutex);
spin_lock(&drvdata->spinlock);
idx = drvdata->addr_idx;
if (idx % 2 != 0) {
mutex_unlock(&drvdata->mutex);
spin_unlock(&drvdata->spinlock);
return -EPERM;
}
if (!((drvdata->addr_type[idx] == ETM_ADDR_TYPE_NONE &&
drvdata->addr_type[idx + 1] == ETM_ADDR_TYPE_NONE) ||
(drvdata->addr_type[idx] == ETM_ADDR_TYPE_RANGE &&
drvdata->addr_type[idx + 1] == ETM_ADDR_TYPE_RANGE))) {
mutex_unlock(&drvdata->mutex);
spin_unlock(&drvdata->spinlock);
return -EPERM;
}
val1 = drvdata->addr_val[idx];
val2 = drvdata->addr_val[idx + 1];
mutex_unlock(&drvdata->mutex);
spin_unlock(&drvdata->spinlock);
return scnprintf(buf, PAGE_SIZE, "%#lx %#lx\n", val1, val2);
}
@ -859,17 +864,17 @@ static ssize_t etm_store_addr_range(struct device *dev,
if (val1 > val2)
return -EINVAL;
mutex_lock(&drvdata->mutex);
spin_lock(&drvdata->spinlock);
idx = drvdata->addr_idx;
if (idx % 2 != 0) {
mutex_unlock(&drvdata->mutex);
spin_unlock(&drvdata->spinlock);
return -EPERM;
}
if (!((drvdata->addr_type[idx] == ETM_ADDR_TYPE_NONE &&
drvdata->addr_type[idx + 1] == ETM_ADDR_TYPE_NONE) ||
(drvdata->addr_type[idx] == ETM_ADDR_TYPE_RANGE &&
drvdata->addr_type[idx + 1] == ETM_ADDR_TYPE_RANGE))) {
mutex_unlock(&drvdata->mutex);
spin_unlock(&drvdata->spinlock);
return -EPERM;
}
@ -878,7 +883,7 @@ static ssize_t etm_store_addr_range(struct device *dev,
drvdata->addr_val[idx + 1] = val2;
drvdata->addr_type[idx + 1] = ETM_ADDR_TYPE_RANGE;
drvdata->enable_ctrl1 |= (1 << (idx/2));
mutex_unlock(&drvdata->mutex);
spin_unlock(&drvdata->spinlock);
return size;
}
static DEVICE_ATTR(addr_range, S_IRUGO | S_IWUSR, etm_show_addr_range,
@ -891,16 +896,16 @@ static ssize_t etm_show_addr_start(struct device *dev,
unsigned long val;
uint8_t idx;
mutex_lock(&drvdata->mutex);
spin_lock(&drvdata->spinlock);
idx = drvdata->addr_idx;
if (!(drvdata->addr_type[idx] == ETM_ADDR_TYPE_NONE ||
drvdata->addr_type[idx] == ETM_ADDR_TYPE_START)) {
mutex_unlock(&drvdata->mutex);
spin_unlock(&drvdata->spinlock);
return -EPERM;
}
val = drvdata->addr_val[idx];
mutex_unlock(&drvdata->mutex);
spin_unlock(&drvdata->spinlock);
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
}
@ -915,11 +920,11 @@ static ssize_t etm_store_addr_start(struct device *dev,
if (sscanf(buf, "%lx", &val) != 1)
return -EINVAL;
mutex_lock(&drvdata->mutex);
spin_lock(&drvdata->spinlock);
idx = drvdata->addr_idx;
if (!(drvdata->addr_type[idx] == ETM_ADDR_TYPE_NONE ||
drvdata->addr_type[idx] == ETM_ADDR_TYPE_START)) {
mutex_unlock(&drvdata->mutex);
spin_unlock(&drvdata->spinlock);
return -EPERM;
}
@ -927,7 +932,7 @@ static ssize_t etm_store_addr_start(struct device *dev,
drvdata->addr_type[idx] = ETM_ADDR_TYPE_START;
drvdata->startstop_ctrl |= (1 << idx);
drvdata->enable_ctrl1 |= BIT(25);
mutex_unlock(&drvdata->mutex);
spin_unlock(&drvdata->spinlock);
return size;
}
static DEVICE_ATTR(addr_start, S_IRUGO | S_IWUSR, etm_show_addr_start,
@ -940,16 +945,16 @@ static ssize_t etm_show_addr_stop(struct device *dev,
unsigned long val;
uint8_t idx;
mutex_lock(&drvdata->mutex);
spin_lock(&drvdata->spinlock);
idx = drvdata->addr_idx;
if (!(drvdata->addr_type[idx] == ETM_ADDR_TYPE_NONE ||
drvdata->addr_type[idx] == ETM_ADDR_TYPE_STOP)) {
mutex_unlock(&drvdata->mutex);
spin_unlock(&drvdata->spinlock);
return -EPERM;
}
val = drvdata->addr_val[idx];
mutex_unlock(&drvdata->mutex);
spin_unlock(&drvdata->spinlock);
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
}
@ -964,11 +969,11 @@ static ssize_t etm_store_addr_stop(struct device *dev,
if (sscanf(buf, "%lx", &val) != 1)
return -EINVAL;
mutex_lock(&drvdata->mutex);
spin_lock(&drvdata->spinlock);
idx = drvdata->addr_idx;
if (!(drvdata->addr_type[idx] == ETM_ADDR_TYPE_NONE ||
drvdata->addr_type[idx] == ETM_ADDR_TYPE_STOP)) {
mutex_unlock(&drvdata->mutex);
spin_unlock(&drvdata->spinlock);
return -EPERM;
}
@ -976,7 +981,7 @@ static ssize_t etm_store_addr_stop(struct device *dev,
drvdata->addr_type[idx] = ETM_ADDR_TYPE_STOP;
drvdata->startstop_ctrl |= (1 << (idx + 16));
drvdata->enable_ctrl1 |= BIT(25);
mutex_unlock(&drvdata->mutex);
spin_unlock(&drvdata->spinlock);
return size;
}
static DEVICE_ATTR(addr_stop, S_IRUGO | S_IWUSR, etm_show_addr_stop,
@ -988,9 +993,9 @@ static ssize_t etm_show_addr_acctype(struct device *dev,
struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
unsigned long val;
mutex_lock(&drvdata->mutex);
spin_lock(&drvdata->spinlock);
val = drvdata->addr_acctype[drvdata->addr_idx];
mutex_unlock(&drvdata->mutex);
spin_unlock(&drvdata->spinlock);
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
}
@ -1004,9 +1009,9 @@ static ssize_t etm_store_addr_acctype(struct device *dev,
if (sscanf(buf, "%lx", &val) != 1)
return -EINVAL;
mutex_lock(&drvdata->mutex);
spin_lock(&drvdata->spinlock);
drvdata->addr_acctype[drvdata->addr_idx] = val;
mutex_unlock(&drvdata->mutex);
spin_unlock(&drvdata->spinlock);
return size;
}
static DEVICE_ATTR(addr_acctype, S_IRUGO | S_IWUSR, etm_show_addr_acctype,
@ -1033,12 +1038,13 @@ static ssize_t etm_store_cntr_idx(struct device *dev,
if (val >= drvdata->nr_cntr)
return -EINVAL;
/* Use mutex to ensure index doesn't change while it gets dereferenced
* multiple times within a mutex block elsewhere.
/*
* Use spinlock to ensure index doesn't change while it gets
* dereferenced multiple times within a spinlock block elsewhere.
*/
mutex_lock(&drvdata->mutex);
spin_lock(&drvdata->spinlock);
drvdata->cntr_idx = val;
mutex_unlock(&drvdata->mutex);
spin_unlock(&drvdata->spinlock);
return size;
}
static DEVICE_ATTR(cntr_idx, S_IRUGO | S_IWUSR, etm_show_cntr_idx,
@ -1050,9 +1056,9 @@ static ssize_t etm_show_cntr_rld_val(struct device *dev,
struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
unsigned long val;
mutex_lock(&drvdata->mutex);
spin_lock(&drvdata->spinlock);
val = drvdata->cntr_rld_val[drvdata->cntr_idx];
mutex_unlock(&drvdata->mutex);
spin_unlock(&drvdata->spinlock);
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
}
@ -1066,9 +1072,9 @@ static ssize_t etm_store_cntr_rld_val(struct device *dev,
if (sscanf(buf, "%lx", &val) != 1)
return -EINVAL;
mutex_lock(&drvdata->mutex);
spin_lock(&drvdata->spinlock);
drvdata->cntr_rld_val[drvdata->cntr_idx] = val;
mutex_unlock(&drvdata->mutex);
spin_unlock(&drvdata->spinlock);
return size;
}
static DEVICE_ATTR(cntr_rld_val, S_IRUGO | S_IWUSR, etm_show_cntr_rld_val,
@ -1080,9 +1086,9 @@ static ssize_t etm_show_cntr_event(struct device *dev,
struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
unsigned long val;
mutex_lock(&drvdata->mutex);
spin_lock(&drvdata->spinlock);
val = drvdata->cntr_event[drvdata->cntr_idx];
mutex_unlock(&drvdata->mutex);
spin_unlock(&drvdata->spinlock);
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
}
@ -1096,9 +1102,9 @@ static ssize_t etm_store_cntr_event(struct device *dev,
if (sscanf(buf, "%lx", &val) != 1)
return -EINVAL;
mutex_lock(&drvdata->mutex);
spin_lock(&drvdata->spinlock);
drvdata->cntr_event[drvdata->cntr_idx] = val & ETM_EVENT_MASK;
mutex_unlock(&drvdata->mutex);
spin_unlock(&drvdata->spinlock);
return size;
}
static DEVICE_ATTR(cntr_event, S_IRUGO | S_IWUSR, etm_show_cntr_event,
@ -1110,9 +1116,9 @@ static ssize_t etm_show_cntr_rld_event(struct device *dev,
struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
unsigned long val;
mutex_lock(&drvdata->mutex);
spin_lock(&drvdata->spinlock);
val = drvdata->cntr_rld_event[drvdata->cntr_idx];
mutex_unlock(&drvdata->mutex);
spin_unlock(&drvdata->spinlock);
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
}
@ -1126,9 +1132,9 @@ static ssize_t etm_store_cntr_rld_event(struct device *dev,
if (sscanf(buf, "%lx", &val) != 1)
return -EINVAL;
mutex_lock(&drvdata->mutex);
spin_lock(&drvdata->spinlock);
drvdata->cntr_rld_event[drvdata->cntr_idx] = val & ETM_EVENT_MASK;
mutex_unlock(&drvdata->mutex);
spin_unlock(&drvdata->spinlock);
return size;
}
static DEVICE_ATTR(cntr_rld_event, S_IRUGO | S_IWUSR, etm_show_cntr_rld_event,
@ -1140,9 +1146,9 @@ static ssize_t etm_show_cntr_val(struct device *dev,
struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
unsigned long val;
mutex_lock(&drvdata->mutex);
spin_lock(&drvdata->spinlock);
val = drvdata->cntr_val[drvdata->cntr_idx];
mutex_unlock(&drvdata->mutex);
spin_unlock(&drvdata->spinlock);
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
}
@ -1156,9 +1162,9 @@ static ssize_t etm_store_cntr_val(struct device *dev,
if (sscanf(buf, "%lx", &val) != 1)
return -EINVAL;
mutex_lock(&drvdata->mutex);
spin_lock(&drvdata->spinlock);
drvdata->cntr_val[drvdata->cntr_idx] = val;
mutex_unlock(&drvdata->mutex);
spin_unlock(&drvdata->spinlock);
return size;
}
static DEVICE_ATTR(cntr_val, S_IRUGO | S_IWUSR, etm_show_cntr_val,
@ -1362,12 +1368,13 @@ static ssize_t etm_store_ctxid_idx(struct device *dev,
if (val >= drvdata->nr_ctxid_cmp)
return -EINVAL;
/* Use mutex to ensure index doesn't change while it gets dereferenced
* multiple times within a mutex block elsewhere.
/*
* Use spinlock to ensure index doesn't change while it gets
* dereferenced multiple times within a spinlock block elsewhere.
*/
mutex_lock(&drvdata->mutex);
spin_lock(&drvdata->spinlock);
drvdata->ctxid_idx = val;
mutex_unlock(&drvdata->mutex);
spin_unlock(&drvdata->spinlock);
return size;
}
static DEVICE_ATTR(ctxid_idx, S_IRUGO | S_IWUSR, etm_show_ctxid_idx,
@ -1379,9 +1386,9 @@ static ssize_t etm_show_ctxid_val(struct device *dev,
struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
unsigned long val;
mutex_lock(&drvdata->mutex);
spin_lock(&drvdata->spinlock);
val = drvdata->ctxid_val[drvdata->ctxid_idx];
mutex_unlock(&drvdata->mutex);
spin_unlock(&drvdata->spinlock);
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
}
@ -1395,9 +1402,9 @@ static ssize_t etm_store_ctxid_val(struct device *dev,
if (sscanf(buf, "%lx", &val) != 1)
return -EINVAL;
mutex_lock(&drvdata->mutex);
spin_lock(&drvdata->spinlock);
drvdata->ctxid_val[drvdata->ctxid_idx] = val;
mutex_unlock(&drvdata->mutex);
spin_unlock(&drvdata->spinlock);
return size;
}
static DEVICE_ATTR(ctxid_val, S_IRUGO | S_IWUSR, etm_show_ctxid_val,
@ -1497,8 +1504,8 @@ static int __etm_store_pcsave(struct etm_drvdata *drvdata, unsigned long val)
if (ret)
return ret;
mutex_lock(&drvdata->mutex);
get_online_cpus();
spin_lock(&drvdata->spinlock);
if (val) {
if (drvdata->pcsave_enable)
goto out;
@ -1523,8 +1530,8 @@ static int __etm_store_pcsave(struct etm_drvdata *drvdata, unsigned long val)
dev_info(drvdata->dev, "PC save disabled\n");
}
out:
spin_unlock(&drvdata->spinlock);
put_online_cpus();
mutex_unlock(&drvdata->mutex);
clk_disable_unprepare(drvdata->clk);
return ret;
@ -1754,7 +1761,7 @@ static int __devinit etm_probe(struct platform_device *pdev)
if (!drvdata->base)
return -ENOMEM;
mutex_init(&drvdata->mutex);
spin_lock_init(&drvdata->spinlock);
wake_lock_init(&drvdata->wake_lock, WAKE_LOCK_SUSPEND, "coresight-etm");
drvdata->clk = devm_clk_get(dev, "core_clk");
@ -1848,7 +1855,6 @@ err1:
clk_disable_unprepare(drvdata->clk);
err0:
wake_lock_destroy(&drvdata->wake_lock);
mutex_destroy(&drvdata->mutex);
return ret;
}
@ -1859,7 +1865,6 @@ static int __devexit etm_remove(struct platform_device *pdev)
device_remove_file(&drvdata->csdev->dev, &dev_attr_pcsave);
coresight_unregister(drvdata->csdev);
wake_lock_destroy(&drvdata->wake_lock);
mutex_destroy(&drvdata->mutex);
return 0;
}