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:
Yuanfang Zhang
2019-11-05 18:50:57 +08:00
committed by Tingwei Zhang
parent f37e82faf4
commit 0726d3a73c
4 changed files with 167 additions and 10 deletions

View File

@@ -614,9 +614,12 @@ int tmc_read_prepare_etb(struct tmc_drvdata *drvdata)
} }
/* Disable the TMC if need be */ /* 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); __tmc_etb_disable_hw(drvdata);
}
drvdata->reading = true; drvdata->reading = true;
out: out:
spin_unlock_irqrestore(&drvdata->spinlock, flags); 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 */ /* Re-enable the TMC if need be */
if (drvdata->mode == CS_MODE_SYSFS) { 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); memset(drvdata->buf, 0, drvdata->size);
__tmc_etb_enable_hw(drvdata); __tmc_etb_enable_hw(drvdata);
spin_unlock_irqrestore(&drvdata->spinlock, flags);
coresight_enable_all_source_link();
spin_lock_irqsave(&drvdata->spinlock, flags);
} else { } else {
/* /*
* The ETB/ETF is not tracing and the buffer was just read. * 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->buf = NULL;
} }
drvdata->reading = false;
spin_unlock_irqrestore(&drvdata->spinlock, flags); spin_unlock_irqrestore(&drvdata->spinlock, flags);
/* /*

View File

@@ -2015,12 +2015,14 @@ int tmc_etr_switch_mode(struct tmc_drvdata *drvdata, const char *out_mode)
return 0; return 0;
} }
coresight_disable_all_source_link();
tmc_disable_etr_sink(drvdata->csdev); tmc_disable_etr_sink(drvdata->csdev);
old_mode = drvdata->out_mode; old_mode = drvdata->out_mode;
drvdata->out_mode = new_mode; drvdata->out_mode = new_mode;
if (tmc_enable_etr_sink_sysfs(drvdata->csdev)) { if (tmc_enable_etr_sink_sysfs(drvdata->csdev)) {
drvdata->out_mode = old_mode; drvdata->out_mode = old_mode;
tmc_enable_etr_sink_sysfs(drvdata->csdev); tmc_enable_etr_sink_sysfs(drvdata->csdev);
coresight_enable_all_source_link();
dev_err(&drvdata->csdev->dev, dev_err(&drvdata->csdev->dev,
"Switch to %s failed. Fall back to %s.\n", "Switch to %s failed. Fall back to %s.\n",
str_tmc_etr_out_mode[new_mode], 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); mutex_unlock(&drvdata->mem_lock);
return -EINVAL; return -EINVAL;
} }
coresight_enable_all_source_link();
mutex_unlock(&drvdata->mem_lock); mutex_unlock(&drvdata->mem_lock);
return 0; 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. */ /* 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); __tmc_etr_disable_hw(drvdata);
}
drvdata->reading = true; drvdata->reading = true;
out: out:
spin_unlock_irqrestore(&drvdata->spinlock, flags); spin_unlock_irqrestore(&drvdata->spinlock, flags);
@@ -2103,6 +2108,7 @@ int tmc_read_unprepare_etr(struct tmc_drvdata *drvdata)
mutex_lock(&drvdata->mem_lock); mutex_lock(&drvdata->mem_lock);
spin_lock_irqsave(&drvdata->spinlock, flags); spin_lock_irqsave(&drvdata->spinlock, flags);
drvdata->reading = false;
/* RE-enable the TMC if need be */ /* RE-enable the TMC if need be */
if (drvdata->mode == CS_MODE_SYSFS) { if (drvdata->mode == CS_MODE_SYSFS) {
/* /*
@@ -2111,6 +2117,10 @@ int tmc_read_unprepare_etr(struct tmc_drvdata *drvdata)
* be NULL. * be NULL.
*/ */
__tmc_etr_enable_hw(drvdata); __tmc_etr_enable_hw(drvdata);
spin_unlock_irqrestore(&drvdata->spinlock, flags);
coresight_enable_all_source_link();
spin_lock_irqsave(&drvdata->spinlock, flags);
} else { } else {
/* /*
* The ETR is not tracing and the buffer was just read. * 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->sysfs_buf = NULL;
} }
drvdata->reading = false;
spin_unlock_irqrestore(&drvdata->spinlock, flags); spin_unlock_irqrestore(&drvdata->spinlock, flags);
/* Free allocated memory out side of the spinlock */ /* Free allocated memory out side of the spinlock */
if (sysfs_buf) if (sysfs_buf)
tmc_etr_free_sysfs_buf(sysfs_buf); tmc_etr_free_sysfs_buf(sysfs_buf);
mutex_unlock(&drvdata->mem_lock); mutex_unlock(&drvdata->mem_lock);
return 0; return 0;
} }

View File

@@ -48,6 +48,8 @@ struct coresight_path {
static LIST_HEAD(cs_active_paths); 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 * 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 * 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; 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 coresight_enable(struct coresight_device *csdev)
{ {
int ret = 0; int ret = 0;
@@ -1041,18 +1166,32 @@ static ssize_t enable_sink_store(struct device *dev,
int ret; int ret;
unsigned long val; unsigned long val;
struct coresight_device *csdev = to_coresight_device(dev); struct coresight_device *csdev = to_coresight_device(dev);
struct coresight_device *sink = NULL;
ret = kstrtoul(buf, 10, &val); ret = kstrtoul(buf, 10, &val);
if (ret) if (ret)
return 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; csdev->activated = true;
else } else {
if (csdev->enable)
goto err;
csdev->activated = false; csdev->activated = false;
}
mutex_unlock(&coresight_mutex);
return size; return size;
err:
mutex_unlock(&coresight_mutex);
return -EINVAL;
} }
static DEVICE_ATTR_RW(enable_sink); static DEVICE_ATTR_RW(enable_sink);

View File

@@ -313,6 +313,8 @@ extern const char *coresight_alloc_device_name(struct coresight_dev_list *devs,
struct device *dev); struct device *dev);
extern void coresight_disable_reg_clk(struct coresight_device *csdev); extern void coresight_disable_reg_clk(struct coresight_device *csdev);
extern int coresight_enable_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 #else
static inline struct coresight_device * static inline struct coresight_device *
coresight_register(struct coresight_desc *desc) { return NULL; } 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; return -EINVAL;
} }
static void coresight_disable_all_source_link(void) {};
static void coresight_enable_all_source_link(void) {};
#endif #endif
extern int coresight_get_cpu(struct device *dev); extern int coresight_get_cpu(struct device *dev);