coresight: fix tmc flush timeout issue
cpu will hang when FlushMan bit, StopOnFl bit don't be reset to 0 and etm0 was enabled. This change disable source and link for all activated path to workaround this issue when read tmc from dev interface and switch etr out_mode. Change-Id: Idf6d8cffcef0bedaeed91f28366f9c33e22bc0cb Signed-off-by: Yuanfang Zhang <zhangyuanfang@codeaurora.org> Signed-off-by: Tingwei Zhang <tingwei@codeaurora.org>
This commit is contained in:

committed by
Tingwei Zhang

parent
f37e82faf4
commit
0726d3a73c
@@ -614,9 +614,12 @@ int tmc_read_prepare_etb(struct tmc_drvdata *drvdata)
|
||||
}
|
||||
|
||||
/* Disable the TMC if need be */
|
||||
if (drvdata->mode == CS_MODE_SYSFS)
|
||||
if (drvdata->mode == CS_MODE_SYSFS) {
|
||||
spin_unlock_irqrestore(&drvdata->spinlock, flags);
|
||||
coresight_disable_all_source_link();
|
||||
spin_lock_irqsave(&drvdata->spinlock, flags);
|
||||
__tmc_etb_disable_hw(drvdata);
|
||||
|
||||
}
|
||||
drvdata->reading = true;
|
||||
out:
|
||||
spin_unlock_irqrestore(&drvdata->spinlock, flags);
|
||||
@@ -646,6 +649,7 @@ int tmc_read_unprepare_etb(struct tmc_drvdata *drvdata)
|
||||
}
|
||||
}
|
||||
|
||||
drvdata->reading = false;
|
||||
/* Re-enable the TMC if need be */
|
||||
if (drvdata->mode == CS_MODE_SYSFS) {
|
||||
/*
|
||||
@@ -658,6 +662,9 @@ int tmc_read_unprepare_etb(struct tmc_drvdata *drvdata)
|
||||
*/
|
||||
memset(drvdata->buf, 0, drvdata->size);
|
||||
__tmc_etb_enable_hw(drvdata);
|
||||
spin_unlock_irqrestore(&drvdata->spinlock, flags);
|
||||
coresight_enable_all_source_link();
|
||||
spin_lock_irqsave(&drvdata->spinlock, flags);
|
||||
} else {
|
||||
/*
|
||||
* The ETB/ETF is not tracing and the buffer was just read.
|
||||
@@ -667,7 +674,6 @@ int tmc_read_unprepare_etb(struct tmc_drvdata *drvdata)
|
||||
drvdata->buf = NULL;
|
||||
}
|
||||
|
||||
drvdata->reading = false;
|
||||
spin_unlock_irqrestore(&drvdata->spinlock, flags);
|
||||
|
||||
/*
|
||||
|
@@ -2015,12 +2015,14 @@ int tmc_etr_switch_mode(struct tmc_drvdata *drvdata, const char *out_mode)
|
||||
return 0;
|
||||
}
|
||||
|
||||
coresight_disable_all_source_link();
|
||||
tmc_disable_etr_sink(drvdata->csdev);
|
||||
old_mode = drvdata->out_mode;
|
||||
drvdata->out_mode = new_mode;
|
||||
if (tmc_enable_etr_sink_sysfs(drvdata->csdev)) {
|
||||
drvdata->out_mode = old_mode;
|
||||
tmc_enable_etr_sink_sysfs(drvdata->csdev);
|
||||
coresight_enable_all_source_link();
|
||||
dev_err(&drvdata->csdev->dev,
|
||||
"Switch to %s failed. Fall back to %s.\n",
|
||||
str_tmc_etr_out_mode[new_mode],
|
||||
@@ -2028,7 +2030,7 @@ int tmc_etr_switch_mode(struct tmc_drvdata *drvdata, const char *out_mode)
|
||||
mutex_unlock(&drvdata->mem_lock);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
coresight_enable_all_source_link();
|
||||
mutex_unlock(&drvdata->mem_lock);
|
||||
return 0;
|
||||
}
|
||||
@@ -2081,9 +2083,12 @@ int tmc_read_prepare_etr(struct tmc_drvdata *drvdata)
|
||||
}
|
||||
|
||||
/* Disable the TMC if we are trying to read from a running session. */
|
||||
if (drvdata->mode == CS_MODE_SYSFS)
|
||||
if (drvdata->mode == CS_MODE_SYSFS) {
|
||||
spin_unlock_irqrestore(&drvdata->spinlock, flags);
|
||||
coresight_disable_all_source_link();
|
||||
spin_lock_irqsave(&drvdata->spinlock, flags);
|
||||
__tmc_etr_disable_hw(drvdata);
|
||||
|
||||
}
|
||||
drvdata->reading = true;
|
||||
out:
|
||||
spin_unlock_irqrestore(&drvdata->spinlock, flags);
|
||||
@@ -2103,6 +2108,7 @@ int tmc_read_unprepare_etr(struct tmc_drvdata *drvdata)
|
||||
mutex_lock(&drvdata->mem_lock);
|
||||
spin_lock_irqsave(&drvdata->spinlock, flags);
|
||||
|
||||
drvdata->reading = false;
|
||||
/* RE-enable the TMC if need be */
|
||||
if (drvdata->mode == CS_MODE_SYSFS) {
|
||||
/*
|
||||
@@ -2111,6 +2117,10 @@ int tmc_read_unprepare_etr(struct tmc_drvdata *drvdata)
|
||||
* be NULL.
|
||||
*/
|
||||
__tmc_etr_enable_hw(drvdata);
|
||||
|
||||
spin_unlock_irqrestore(&drvdata->spinlock, flags);
|
||||
coresight_enable_all_source_link();
|
||||
spin_lock_irqsave(&drvdata->spinlock, flags);
|
||||
} else {
|
||||
/*
|
||||
* The ETR is not tracing and the buffer was just read.
|
||||
@@ -2120,14 +2130,12 @@ int tmc_read_unprepare_etr(struct tmc_drvdata *drvdata)
|
||||
drvdata->sysfs_buf = NULL;
|
||||
}
|
||||
|
||||
drvdata->reading = false;
|
||||
spin_unlock_irqrestore(&drvdata->spinlock, flags);
|
||||
|
||||
/* Free allocated memory out side of the spinlock */
|
||||
if (sysfs_buf)
|
||||
tmc_etr_free_sysfs_buf(sysfs_buf);
|
||||
|
||||
|
||||
mutex_unlock(&drvdata->mem_lock);
|
||||
return 0;
|
||||
}
|
||||
|
@@ -48,6 +48,8 @@ struct coresight_path {
|
||||
|
||||
static LIST_HEAD(cs_active_paths);
|
||||
|
||||
static struct coresight_device *activated_sink;
|
||||
|
||||
/*
|
||||
* When losing synchronisation a new barrier packet needs to be inserted at the
|
||||
* beginning of the data collected in a buffer. That way the decoder knows that
|
||||
@@ -918,6 +920,129 @@ static int coresight_store_path(struct list_head *path)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void coresight_enable_source_link(struct list_head *path)
|
||||
{
|
||||
u32 type;
|
||||
int ret;
|
||||
struct coresight_node *nd;
|
||||
struct coresight_device *csdev, *parent, *child;
|
||||
|
||||
list_for_each_entry_reverse(nd, path, link) {
|
||||
csdev = nd->csdev;
|
||||
type = csdev->type;
|
||||
|
||||
if (type == CORESIGHT_DEV_TYPE_LINKSINK)
|
||||
type = (csdev == coresight_get_sink(path)) ?
|
||||
CORESIGHT_DEV_TYPE_SINK :
|
||||
CORESIGHT_DEV_TYPE_LINK;
|
||||
|
||||
switch (type) {
|
||||
case CORESIGHT_DEV_TYPE_SINK:
|
||||
break;
|
||||
case CORESIGHT_DEV_TYPE_SOURCE:
|
||||
if (source_ops(csdev)->enable) {
|
||||
ret = coresight_enable_reg_clk(csdev);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
ret = source_ops(csdev)->enable(csdev,
|
||||
NULL, CS_MODE_SYSFS);
|
||||
if (ret) {
|
||||
coresight_disable_reg_clk(csdev);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
csdev->enable = true;
|
||||
break;
|
||||
case CORESIGHT_DEV_TYPE_LINK:
|
||||
parent = list_prev_entry(nd, link)->csdev;
|
||||
child = list_next_entry(nd, link)->csdev;
|
||||
ret = coresight_enable_link(csdev, parent, child, path);
|
||||
if (ret)
|
||||
goto err;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
err:
|
||||
coresight_disable_path_from(path, nd);
|
||||
coresight_release_path(path);
|
||||
}
|
||||
|
||||
static void coresight_disable_source_link(struct list_head *path)
|
||||
{
|
||||
u32 type;
|
||||
struct coresight_node *nd;
|
||||
struct coresight_device *csdev, *parent, *child;
|
||||
|
||||
list_for_each_entry(nd, path, link) {
|
||||
csdev = nd->csdev;
|
||||
type = csdev->type;
|
||||
|
||||
if (type == CORESIGHT_DEV_TYPE_LINKSINK)
|
||||
type = (csdev == coresight_get_sink(path)) ?
|
||||
CORESIGHT_DEV_TYPE_SINK :
|
||||
CORESIGHT_DEV_TYPE_LINK;
|
||||
|
||||
switch (type) {
|
||||
case CORESIGHT_DEV_TYPE_SINK:
|
||||
break;
|
||||
case CORESIGHT_DEV_TYPE_SOURCE:
|
||||
if (source_ops(csdev)->disable) {
|
||||
source_ops(csdev)->disable(csdev, NULL);
|
||||
coresight_disable_reg_clk(csdev);
|
||||
}
|
||||
csdev->enable = false;
|
||||
break;
|
||||
case CORESIGHT_DEV_TYPE_LINK:
|
||||
parent = list_prev_entry(nd, link)->csdev;
|
||||
child = list_next_entry(nd, link)->csdev;
|
||||
coresight_disable_link(csdev, parent, child, path);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
void coresight_disable_all_source_link(void)
|
||||
{
|
||||
struct coresight_path *cspath = NULL;
|
||||
struct coresight_path *cspath_next = NULL;
|
||||
|
||||
mutex_lock(&coresight_mutex);
|
||||
|
||||
list_for_each_entry_safe(cspath, cspath_next, &cs_active_paths, link) {
|
||||
coresight_disable_source_link(cspath->path);
|
||||
}
|
||||
|
||||
activated_sink = coresight_get_enabled_sink(false);
|
||||
if (activated_sink)
|
||||
activated_sink->activated = false;
|
||||
|
||||
mutex_unlock(&coresight_mutex);
|
||||
}
|
||||
|
||||
void coresight_enable_all_source_link(void)
|
||||
{
|
||||
struct coresight_path *cspath = NULL;
|
||||
struct coresight_path *cspath_next = NULL;
|
||||
|
||||
mutex_lock(&coresight_mutex);
|
||||
|
||||
list_for_each_entry_safe(cspath, cspath_next, &cs_active_paths, link) {
|
||||
coresight_enable_source_link(cspath->path);
|
||||
}
|
||||
|
||||
if (activated_sink && activated_sink->enable)
|
||||
activated_sink->activated = true;
|
||||
|
||||
activated_sink = NULL;
|
||||
mutex_unlock(&coresight_mutex);
|
||||
}
|
||||
|
||||
int coresight_enable(struct coresight_device *csdev)
|
||||
{
|
||||
int ret = 0;
|
||||
@@ -1041,18 +1166,32 @@ static ssize_t enable_sink_store(struct device *dev,
|
||||
int ret;
|
||||
unsigned long val;
|
||||
struct coresight_device *csdev = to_coresight_device(dev);
|
||||
struct coresight_device *sink = NULL;
|
||||
|
||||
ret = kstrtoul(buf, 10, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
mutex_lock(&coresight_mutex);
|
||||
|
||||
if (val)
|
||||
if (val) {
|
||||
sink = activated_sink ? activated_sink :
|
||||
coresight_get_enabled_sink(false);
|
||||
if (sink && strcmp(dev_name(&sink->dev),
|
||||
dev_name(&csdev->dev)))
|
||||
goto err;
|
||||
csdev->activated = true;
|
||||
else
|
||||
} else {
|
||||
if (csdev->enable)
|
||||
goto err;
|
||||
csdev->activated = false;
|
||||
}
|
||||
mutex_unlock(&coresight_mutex);
|
||||
|
||||
return size;
|
||||
|
||||
err:
|
||||
mutex_unlock(&coresight_mutex);
|
||||
return -EINVAL;
|
||||
}
|
||||
static DEVICE_ATTR_RW(enable_sink);
|
||||
|
||||
|
@@ -313,6 +313,8 @@ extern const char *coresight_alloc_device_name(struct coresight_dev_list *devs,
|
||||
struct device *dev);
|
||||
extern void coresight_disable_reg_clk(struct coresight_device *csdev);
|
||||
extern int coresight_enable_reg_clk(struct coresight_device *csdev);
|
||||
extern void coresight_disable_all_source_link(void);
|
||||
extern void coresight_enable_all_source_link(void);
|
||||
#else
|
||||
static inline struct coresight_device *
|
||||
coresight_register(struct coresight_desc *desc) { return NULL; }
|
||||
@@ -339,6 +341,8 @@ static inline int coresight_enable_reg_clk(struct coresight_device *csdev)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
static void coresight_disable_all_source_link(void) {};
|
||||
static void coresight_enable_all_source_link(void) {};
|
||||
#endif
|
||||
|
||||
extern int coresight_get_cpu(struct device *dev);
|
||||
|
Reference in New Issue
Block a user