Commit c38a9ec2 authored by Mathieu Poirier's avatar Mathieu Poirier Committed by Greg Kroah-Hartman

coresight: etm4x: moving etm_drvdata::enable to atomic field

Similarly to ETMv3, moving etmv4_drvdata::enable to an atomic
type that gives the 'mode' of a tracer and prevents multiple,
simultanious access by different subsystems.
Signed-off-by: default avatarMathieu Poirier <mathieu.poirier@linaro.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 66bbbb77
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/perf_event.h> #include <linux/perf_event.h>
#include <asm/sections.h> #include <asm/sections.h>
#include <asm/local.h>
#include "coresight-etm4x.h" #include "coresight-etm4x.h"
...@@ -76,7 +77,7 @@ static int etm4_trace_id(struct coresight_device *csdev) ...@@ -76,7 +77,7 @@ static int etm4_trace_id(struct coresight_device *csdev)
unsigned long flags; unsigned long flags;
int trace_id = -1; int trace_id = -1;
if (!drvdata->enable) if (!local_read(&drvdata->mode))
return drvdata->trcid; return drvdata->trcid;
spin_lock_irqsave(&drvdata->spinlock, flags); spin_lock_irqsave(&drvdata->spinlock, flags);
...@@ -188,8 +189,7 @@ static void etm4_enable_hw(void *info) ...@@ -188,8 +189,7 @@ static void etm4_enable_hw(void *info)
dev_dbg(drvdata->dev, "cpu: %d enable smp call done\n", drvdata->cpu); dev_dbg(drvdata->dev, "cpu: %d enable smp call done\n", drvdata->cpu);
} }
static int etm4_enable(struct coresight_device *csdev, static int etm4_enable_sysfs(struct coresight_device *csdev)
struct perf_event_attr *attr, u32 mode)
{ {
struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
int ret; int ret;
...@@ -204,18 +204,46 @@ static int etm4_enable(struct coresight_device *csdev, ...@@ -204,18 +204,46 @@ static int etm4_enable(struct coresight_device *csdev,
etm4_enable_hw, drvdata, 1); etm4_enable_hw, drvdata, 1);
if (ret) if (ret)
goto err; goto err;
drvdata->enable = true;
drvdata->sticky_enable = true;
drvdata->sticky_enable = true;
spin_unlock(&drvdata->spinlock); spin_unlock(&drvdata->spinlock);
dev_info(drvdata->dev, "ETM tracing enabled\n"); dev_info(drvdata->dev, "ETM tracing enabled\n");
return 0; return 0;
err: err:
spin_unlock(&drvdata->spinlock); spin_unlock(&drvdata->spinlock);
return ret; return ret;
} }
static int etm4_enable(struct coresight_device *csdev,
struct perf_event_attr *attr, u32 mode)
{
int ret;
u32 val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
val = local_cmpxchg(&drvdata->mode, CS_MODE_DISABLED, mode);
/* Someone is already using the tracer */
if (val)
return -EBUSY;
switch (mode) {
case CS_MODE_SYSFS:
ret = etm4_enable_sysfs(csdev);
break;
default:
ret = -EINVAL;
}
/* The tracer didn't start */
if (ret)
local_set(&drvdata->mode, CS_MODE_DISABLED);
return ret;
}
static void etm4_disable_hw(void *info) static void etm4_disable_hw(void *info)
{ {
u32 control; u32 control;
...@@ -238,7 +266,7 @@ static void etm4_disable_hw(void *info) ...@@ -238,7 +266,7 @@ static void etm4_disable_hw(void *info)
dev_dbg(drvdata->dev, "cpu: %d disable smp call done\n", drvdata->cpu); dev_dbg(drvdata->dev, "cpu: %d disable smp call done\n", drvdata->cpu);
} }
static void etm4_disable(struct coresight_device *csdev) static void etm4_disable_sysfs(struct coresight_device *csdev)
{ {
struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
...@@ -256,7 +284,6 @@ static void etm4_disable(struct coresight_device *csdev) ...@@ -256,7 +284,6 @@ static void etm4_disable(struct coresight_device *csdev)
* ensures that register writes occur when cpu is powered. * ensures that register writes occur when cpu is powered.
*/ */
smp_call_function_single(drvdata->cpu, etm4_disable_hw, drvdata, 1); smp_call_function_single(drvdata->cpu, etm4_disable_hw, drvdata, 1);
drvdata->enable = false;
spin_unlock(&drvdata->spinlock); spin_unlock(&drvdata->spinlock);
put_online_cpus(); put_online_cpus();
...@@ -264,6 +291,30 @@ static void etm4_disable(struct coresight_device *csdev) ...@@ -264,6 +291,30 @@ static void etm4_disable(struct coresight_device *csdev)
dev_info(drvdata->dev, "ETM tracing disabled\n"); dev_info(drvdata->dev, "ETM tracing disabled\n");
} }
static void etm4_disable(struct coresight_device *csdev)
{
u32 mode;
struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
/*
* For as long as the tracer isn't disabled another entity can't
* change its status. As such we can read the status here without
* fearing it will change under us.
*/
mode = local_read(&drvdata->mode);
switch (mode) {
case CS_MODE_DISABLED:
break;
case CS_MODE_SYSFS:
etm4_disable_sysfs(csdev);
break;
}
if (mode)
local_set(&drvdata->mode, CS_MODE_DISABLED);
}
static const struct coresight_ops_source etm4_source_ops = { static const struct coresight_ops_source etm4_source_ops = {
.cpu_id = etm4_cpu_id, .cpu_id = etm4_cpu_id,
.trace_id = etm4_trace_id, .trace_id = etm4_trace_id,
...@@ -531,7 +582,7 @@ static int etm4_cpu_callback(struct notifier_block *nfb, unsigned long action, ...@@ -531,7 +582,7 @@ static int etm4_cpu_callback(struct notifier_block *nfb, unsigned long action,
etmdrvdata[cpu]->os_unlock = true; etmdrvdata[cpu]->os_unlock = true;
} }
if (etmdrvdata[cpu]->enable) if (local_read(&etmdrvdata[cpu]->mode))
etm4_enable_hw(etmdrvdata[cpu]); etm4_enable_hw(etmdrvdata[cpu]);
spin_unlock(&etmdrvdata[cpu]->spinlock); spin_unlock(&etmdrvdata[cpu]->spinlock);
break; break;
...@@ -544,7 +595,7 @@ static int etm4_cpu_callback(struct notifier_block *nfb, unsigned long action, ...@@ -544,7 +595,7 @@ static int etm4_cpu_callback(struct notifier_block *nfb, unsigned long action,
case CPU_DYING: case CPU_DYING:
spin_lock(&etmdrvdata[cpu]->spinlock); spin_lock(&etmdrvdata[cpu]->spinlock);
if (etmdrvdata[cpu]->enable) if (local_read(&etmdrvdata[cpu]->mode))
etm4_disable_hw(etmdrvdata[cpu]); etm4_disable_hw(etmdrvdata[cpu]);
spin_unlock(&etmdrvdata[cpu]->spinlock); spin_unlock(&etmdrvdata[cpu]->spinlock);
break; break;
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#ifndef _CORESIGHT_CORESIGHT_ETM_H #ifndef _CORESIGHT_CORESIGHT_ETM_H
#define _CORESIGHT_CORESIGHT_ETM_H #define _CORESIGHT_CORESIGHT_ETM_H
#include <asm/local.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include "coresight-priv.h" #include "coresight-priv.h"
...@@ -290,6 +291,7 @@ struct etmv4_config { ...@@ -290,6 +291,7 @@ struct etmv4_config {
* @dev: The device entity associated to this component. * @dev: The device entity associated to this component.
* @csdev: Component vitals needed by the framework. * @csdev: Component vitals needed by the framework.
* @spinlock: Only one at a time pls. * @spinlock: Only one at a time pls.
* @mode: This tracer's mode, i.e sysFS, Perf or disabled.
* @cpu: The cpu this component is affined to. * @cpu: The cpu this component is affined to.
* @arch: ETM version number. * @arch: ETM version number.
* @nr_pe: The number of processing entity available for tracing. * @nr_pe: The number of processing entity available for tracing.
...@@ -316,7 +318,6 @@ struct etmv4_config { ...@@ -316,7 +318,6 @@ struct etmv4_config {
* supported for the corresponding Exception level. * supported for the corresponding Exception level.
* @ns_ex_level:In non-secure state, indicates whether instruction tracing is * @ns_ex_level:In non-secure state, indicates whether instruction tracing is
* supported for the corresponding Exception level. * supported for the corresponding Exception level.
* @enable: Is this ETM currently tracing.
* @sticky_enable: true if ETM base configuration has been done. * @sticky_enable: true if ETM base configuration has been done.
* @boot_enable:True if we should start tracing at boot time. * @boot_enable:True if we should start tracing at boot time.
* @os_unlock: True if access to management registers is allowed. * @os_unlock: True if access to management registers is allowed.
...@@ -346,6 +347,7 @@ struct etmv4_drvdata { ...@@ -346,6 +347,7 @@ struct etmv4_drvdata {
struct device *dev; struct device *dev;
struct coresight_device *csdev; struct coresight_device *csdev;
spinlock_t spinlock; spinlock_t spinlock;
local_t mode;
int cpu; int cpu;
u8 arch; u8 arch;
u8 nr_pe; u8 nr_pe;
...@@ -368,7 +370,6 @@ struct etmv4_drvdata { ...@@ -368,7 +370,6 @@ struct etmv4_drvdata {
u8 ccitmin; u8 ccitmin;
u8 s_ex_level; u8 s_ex_level;
u8 ns_ex_level; u8 ns_ex_level;
bool enable;
bool sticky_enable; bool sticky_enable;
bool boot_enable; bool boot_enable;
bool os_unlock; bool os_unlock;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment