Commit 4545b38e authored by James Clark's avatar James Clark Committed by Suzuki K Poulose

coresight: Remove atomic type from refcnt

Refcnt is only ever accessed from either inside the coresight_mutex, or
the device's spinlock, making the atomic type and atomic_dec_return()
calls confusing and unnecessary. The only point of synchronisation
outside of these two types of locks is already done with a compare and
swap on 'mode', which a comment has been added for.

There was one instance of refcnt being used outside of a lock in TPIU,
but that can easily be fixed by making it the same as all the other
devices and adding a spinlock. Potentially in the future all the
refcounting and locking can be moved up into the core code, and all the
mostly duplicate code from the individual devices can be removed.
Signed-off-by: default avatarJames Clark <james.clark@arm.com>
Link: https://lore.kernel.org/r/20240129154050.569566-8-james.clark@arm.comSigned-off-by: default avatarSuzuki K Poulose <suzuki.poulose@arm.com>
parent 1f5149c7
...@@ -161,7 +161,7 @@ static int etb_enable_sysfs(struct coresight_device *csdev) ...@@ -161,7 +161,7 @@ static int etb_enable_sysfs(struct coresight_device *csdev)
local_set(&csdev->mode, CS_MODE_SYSFS); local_set(&csdev->mode, CS_MODE_SYSFS);
} }
atomic_inc(&csdev->refcnt); csdev->refcnt++;
out: out:
spin_unlock_irqrestore(&drvdata->spinlock, flags); spin_unlock_irqrestore(&drvdata->spinlock, flags);
return ret; return ret;
...@@ -197,7 +197,7 @@ static int etb_enable_perf(struct coresight_device *csdev, void *data) ...@@ -197,7 +197,7 @@ static int etb_enable_perf(struct coresight_device *csdev, void *data)
* use for this session. * use for this session.
*/ */
if (drvdata->pid == pid) { if (drvdata->pid == pid) {
atomic_inc(&csdev->refcnt); csdev->refcnt++;
goto out; goto out;
} }
...@@ -215,7 +215,7 @@ static int etb_enable_perf(struct coresight_device *csdev, void *data) ...@@ -215,7 +215,7 @@ static int etb_enable_perf(struct coresight_device *csdev, void *data)
/* Associate with monitored process. */ /* Associate with monitored process. */
drvdata->pid = pid; drvdata->pid = pid;
local_set(&drvdata->csdev->mode, CS_MODE_PERF); local_set(&drvdata->csdev->mode, CS_MODE_PERF);
atomic_inc(&csdev->refcnt); csdev->refcnt++;
} }
out: out:
...@@ -354,7 +354,8 @@ static int etb_disable(struct coresight_device *csdev) ...@@ -354,7 +354,8 @@ static int etb_disable(struct coresight_device *csdev)
spin_lock_irqsave(&drvdata->spinlock, flags); spin_lock_irqsave(&drvdata->spinlock, flags);
if (atomic_dec_return(&csdev->refcnt)) { csdev->refcnt--;
if (csdev->refcnt) {
spin_unlock_irqrestore(&drvdata->spinlock, flags); spin_unlock_irqrestore(&drvdata->spinlock, flags);
return -EBUSY; return -EBUSY;
} }
...@@ -445,7 +446,7 @@ static unsigned long etb_update_buffer(struct coresight_device *csdev, ...@@ -445,7 +446,7 @@ static unsigned long etb_update_buffer(struct coresight_device *csdev,
spin_lock_irqsave(&drvdata->spinlock, flags); spin_lock_irqsave(&drvdata->spinlock, flags);
/* Don't do anything if another tracer is using this sink */ /* Don't do anything if another tracer is using this sink */
if (atomic_read(&csdev->refcnt) != 1) if (csdev->refcnt != 1)
goto out; goto out;
__etb_disable_hw(drvdata); __etb_disable_hw(drvdata);
......
...@@ -68,7 +68,7 @@ static int coresight_enable_source_sysfs(struct coresight_device *csdev, ...@@ -68,7 +68,7 @@ static int coresight_enable_source_sysfs(struct coresight_device *csdev,
return ret; return ret;
} }
atomic_inc(&csdev->refcnt); csdev->refcnt++;
return 0; return 0;
} }
...@@ -90,7 +90,8 @@ static bool coresight_disable_source_sysfs(struct coresight_device *csdev, ...@@ -90,7 +90,8 @@ static bool coresight_disable_source_sysfs(struct coresight_device *csdev,
if (local_read(&csdev->mode) != CS_MODE_SYSFS) if (local_read(&csdev->mode) != CS_MODE_SYSFS)
return false; return false;
if (atomic_dec_return(&csdev->refcnt) == 0) { csdev->refcnt--;
if (csdev->refcnt == 0) {
coresight_disable_source(csdev, data); coresight_disable_source(csdev, data);
return true; return true;
} }
...@@ -190,7 +191,7 @@ int coresight_enable_sysfs(struct coresight_device *csdev) ...@@ -190,7 +191,7 @@ int coresight_enable_sysfs(struct coresight_device *csdev)
* source is already enabled. * source is already enabled.
*/ */
if (subtype == CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE) if (subtype == CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE)
atomic_inc(&csdev->refcnt); csdev->refcnt++;
goto out; goto out;
} }
......
...@@ -206,7 +206,7 @@ static int tmc_enable_etf_sink_sysfs(struct coresight_device *csdev) ...@@ -206,7 +206,7 @@ static int tmc_enable_etf_sink_sysfs(struct coresight_device *csdev)
* touched. * touched.
*/ */
if (local_read(&csdev->mode) == CS_MODE_SYSFS) { if (local_read(&csdev->mode) == CS_MODE_SYSFS) {
atomic_inc(&csdev->refcnt); csdev->refcnt++;
goto out; goto out;
} }
...@@ -229,7 +229,7 @@ static int tmc_enable_etf_sink_sysfs(struct coresight_device *csdev) ...@@ -229,7 +229,7 @@ static int tmc_enable_etf_sink_sysfs(struct coresight_device *csdev)
ret = tmc_etb_enable_hw(drvdata); ret = tmc_etb_enable_hw(drvdata);
if (!ret) { if (!ret) {
local_set(&csdev->mode, CS_MODE_SYSFS); local_set(&csdev->mode, CS_MODE_SYSFS);
atomic_inc(&csdev->refcnt); csdev->refcnt++;
} else { } else {
/* Free up the buffer if we failed to enable */ /* Free up the buffer if we failed to enable */
used = false; used = false;
...@@ -284,7 +284,7 @@ static int tmc_enable_etf_sink_perf(struct coresight_device *csdev, void *data) ...@@ -284,7 +284,7 @@ static int tmc_enable_etf_sink_perf(struct coresight_device *csdev, void *data)
* use for this session. * use for this session.
*/ */
if (drvdata->pid == pid) { if (drvdata->pid == pid) {
atomic_inc(&csdev->refcnt); csdev->refcnt++;
break; break;
} }
...@@ -293,7 +293,7 @@ static int tmc_enable_etf_sink_perf(struct coresight_device *csdev, void *data) ...@@ -293,7 +293,7 @@ static int tmc_enable_etf_sink_perf(struct coresight_device *csdev, void *data)
/* Associate with monitored process. */ /* Associate with monitored process. */
drvdata->pid = pid; drvdata->pid = pid;
local_set(&csdev->mode, CS_MODE_PERF); local_set(&csdev->mode, CS_MODE_PERF);
atomic_inc(&csdev->refcnt); csdev->refcnt++;
} }
} while (0); } while (0);
spin_unlock_irqrestore(&drvdata->spinlock, flags); spin_unlock_irqrestore(&drvdata->spinlock, flags);
...@@ -338,7 +338,8 @@ static int tmc_disable_etf_sink(struct coresight_device *csdev) ...@@ -338,7 +338,8 @@ static int tmc_disable_etf_sink(struct coresight_device *csdev)
return -EBUSY; return -EBUSY;
} }
if (atomic_dec_return(&csdev->refcnt)) { csdev->refcnt--;
if (csdev->refcnt) {
spin_unlock_irqrestore(&drvdata->spinlock, flags); spin_unlock_irqrestore(&drvdata->spinlock, flags);
return -EBUSY; return -EBUSY;
} }
...@@ -371,7 +372,7 @@ static int tmc_enable_etf_link(struct coresight_device *csdev, ...@@ -371,7 +372,7 @@ static int tmc_enable_etf_link(struct coresight_device *csdev,
return -EBUSY; return -EBUSY;
} }
if (atomic_read(&csdev->refcnt) == 0) { if (csdev->refcnt == 0) {
ret = tmc_etf_enable_hw(drvdata); ret = tmc_etf_enable_hw(drvdata);
if (!ret) { if (!ret) {
local_set(&csdev->mode, CS_MODE_SYSFS); local_set(&csdev->mode, CS_MODE_SYSFS);
...@@ -379,7 +380,7 @@ static int tmc_enable_etf_link(struct coresight_device *csdev, ...@@ -379,7 +380,7 @@ static int tmc_enable_etf_link(struct coresight_device *csdev,
} }
} }
if (!ret) if (!ret)
atomic_inc(&csdev->refcnt); csdev->refcnt++;
spin_unlock_irqrestore(&drvdata->spinlock, flags); spin_unlock_irqrestore(&drvdata->spinlock, flags);
if (first_enable) if (first_enable)
...@@ -401,7 +402,8 @@ static void tmc_disable_etf_link(struct coresight_device *csdev, ...@@ -401,7 +402,8 @@ static void tmc_disable_etf_link(struct coresight_device *csdev,
return; return;
} }
if (atomic_dec_return(&csdev->refcnt) == 0) { csdev->refcnt--;
if (csdev->refcnt == 0) {
tmc_etf_disable_hw(drvdata); tmc_etf_disable_hw(drvdata);
local_set(&csdev->mode, CS_MODE_DISABLED); local_set(&csdev->mode, CS_MODE_DISABLED);
last_disable = true; last_disable = true;
...@@ -489,7 +491,7 @@ static unsigned long tmc_update_etf_buffer(struct coresight_device *csdev, ...@@ -489,7 +491,7 @@ static unsigned long tmc_update_etf_buffer(struct coresight_device *csdev,
spin_lock_irqsave(&drvdata->spinlock, flags); spin_lock_irqsave(&drvdata->spinlock, flags);
/* Don't do anything if another tracer is using this sink */ /* Don't do anything if another tracer is using this sink */
if (atomic_read(&csdev->refcnt) != 1) if (csdev->refcnt != 1)
goto out; goto out;
CS_UNLOCK(drvdata->base); CS_UNLOCK(drvdata->base);
......
...@@ -1231,14 +1231,14 @@ static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev) ...@@ -1231,14 +1231,14 @@ static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev)
* touched, even if the buffer size has changed. * touched, even if the buffer size has changed.
*/ */
if (local_read(&csdev->mode) == CS_MODE_SYSFS) { if (local_read(&csdev->mode) == CS_MODE_SYSFS) {
atomic_inc(&csdev->refcnt); csdev->refcnt++;
goto out; goto out;
} }
ret = tmc_etr_enable_hw(drvdata, sysfs_buf); ret = tmc_etr_enable_hw(drvdata, sysfs_buf);
if (!ret) { if (!ret) {
local_set(&csdev->mode, CS_MODE_SYSFS); local_set(&csdev->mode, CS_MODE_SYSFS);
atomic_inc(&csdev->refcnt); csdev->refcnt++;
} }
out: out:
...@@ -1564,7 +1564,7 @@ tmc_update_etr_buffer(struct coresight_device *csdev, ...@@ -1564,7 +1564,7 @@ tmc_update_etr_buffer(struct coresight_device *csdev,
spin_lock_irqsave(&drvdata->spinlock, flags); spin_lock_irqsave(&drvdata->spinlock, flags);
/* Don't do anything if another tracer is using this sink */ /* Don't do anything if another tracer is using this sink */
if (atomic_read(&csdev->refcnt) != 1) { if (csdev->refcnt != 1) {
spin_unlock_irqrestore(&drvdata->spinlock, flags); spin_unlock_irqrestore(&drvdata->spinlock, flags);
goto out; goto out;
} }
...@@ -1676,7 +1676,7 @@ static int tmc_enable_etr_sink_perf(struct coresight_device *csdev, void *data) ...@@ -1676,7 +1676,7 @@ static int tmc_enable_etr_sink_perf(struct coresight_device *csdev, void *data)
* use for this session. * use for this session.
*/ */
if (drvdata->pid == pid) { if (drvdata->pid == pid) {
atomic_inc(&csdev->refcnt); csdev->refcnt++;
goto unlock_out; goto unlock_out;
} }
...@@ -1686,7 +1686,7 @@ static int tmc_enable_etr_sink_perf(struct coresight_device *csdev, void *data) ...@@ -1686,7 +1686,7 @@ static int tmc_enable_etr_sink_perf(struct coresight_device *csdev, void *data)
drvdata->pid = pid; drvdata->pid = pid;
local_set(&csdev->mode, CS_MODE_PERF); local_set(&csdev->mode, CS_MODE_PERF);
drvdata->perf_buf = etr_perf->etr_buf; drvdata->perf_buf = etr_perf->etr_buf;
atomic_inc(&csdev->refcnt); csdev->refcnt++;
} }
unlock_out: unlock_out:
...@@ -1719,7 +1719,8 @@ static int tmc_disable_etr_sink(struct coresight_device *csdev) ...@@ -1719,7 +1719,8 @@ static int tmc_disable_etr_sink(struct coresight_device *csdev)
return -EBUSY; return -EBUSY;
} }
if (atomic_dec_return(&csdev->refcnt)) { csdev->refcnt--;
if (csdev->refcnt) {
spin_unlock_irqrestore(&drvdata->spinlock, flags); spin_unlock_irqrestore(&drvdata->spinlock, flags);
return -EBUSY; return -EBUSY;
} }
......
...@@ -152,7 +152,8 @@ static int __tpda_enable(struct tpda_drvdata *drvdata, int port) ...@@ -152,7 +152,8 @@ static int __tpda_enable(struct tpda_drvdata *drvdata, int port)
* Only do pre-port enable for first port that calls enable when the * Only do pre-port enable for first port that calls enable when the
* device's main refcount is still 0 * device's main refcount is still 0
*/ */
if (!atomic_read(&drvdata->csdev->refcnt)) lockdep_assert_held(&drvdata->spinlock);
if (!drvdata->csdev->refcnt)
tpda_enable_pre_port(drvdata); tpda_enable_pre_port(drvdata);
ret = tpda_enable_port(drvdata, port); ret = tpda_enable_port(drvdata, port);
...@@ -173,7 +174,7 @@ static int tpda_enable(struct coresight_device *csdev, ...@@ -173,7 +174,7 @@ static int tpda_enable(struct coresight_device *csdev,
ret = __tpda_enable(drvdata, in->dest_port); ret = __tpda_enable(drvdata, in->dest_port);
if (!ret) { if (!ret) {
atomic_inc(&in->dest_refcnt); atomic_inc(&in->dest_refcnt);
atomic_inc(&csdev->refcnt); csdev->refcnt++;
dev_dbg(drvdata->dev, "TPDA inport %d enabled.\n", in->dest_port); dev_dbg(drvdata->dev, "TPDA inport %d enabled.\n", in->dest_port);
} }
} }
...@@ -204,7 +205,7 @@ static void tpda_disable(struct coresight_device *csdev, ...@@ -204,7 +205,7 @@ static void tpda_disable(struct coresight_device *csdev,
spin_lock(&drvdata->spinlock); spin_lock(&drvdata->spinlock);
if (atomic_dec_return(&in->dest_refcnt) == 0) { if (atomic_dec_return(&in->dest_refcnt) == 0) {
__tpda_disable(drvdata, in->dest_port); __tpda_disable(drvdata, in->dest_port);
atomic_dec(&csdev->refcnt); csdev->refcnt--;
} }
spin_unlock(&drvdata->spinlock); spin_unlock(&drvdata->spinlock);
......
...@@ -58,6 +58,7 @@ struct tpiu_drvdata { ...@@ -58,6 +58,7 @@ struct tpiu_drvdata {
void __iomem *base; void __iomem *base;
struct clk *atclk; struct clk *atclk;
struct coresight_device *csdev; struct coresight_device *csdev;
spinlock_t spinlock;
}; };
static void tpiu_enable_hw(struct csdev_access *csa) static void tpiu_enable_hw(struct csdev_access *csa)
...@@ -72,8 +73,11 @@ static void tpiu_enable_hw(struct csdev_access *csa) ...@@ -72,8 +73,11 @@ static void tpiu_enable_hw(struct csdev_access *csa)
static int tpiu_enable(struct coresight_device *csdev, enum cs_mode mode, static int tpiu_enable(struct coresight_device *csdev, enum cs_mode mode,
void *__unused) void *__unused)
{ {
struct tpiu_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
guard(spinlock)(&drvdata->spinlock);
tpiu_enable_hw(&csdev->access); tpiu_enable_hw(&csdev->access);
atomic_inc(&csdev->refcnt); csdev->refcnt++;
dev_dbg(&csdev->dev, "TPIU enabled\n"); dev_dbg(&csdev->dev, "TPIU enabled\n");
return 0; return 0;
} }
...@@ -96,7 +100,11 @@ static void tpiu_disable_hw(struct csdev_access *csa) ...@@ -96,7 +100,11 @@ static void tpiu_disable_hw(struct csdev_access *csa)
static int tpiu_disable(struct coresight_device *csdev) static int tpiu_disable(struct coresight_device *csdev)
{ {
if (atomic_dec_return(&csdev->refcnt)) struct tpiu_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
guard(spinlock)(&drvdata->spinlock);
csdev->refcnt--;
if (csdev->refcnt)
return -EBUSY; return -EBUSY;
tpiu_disable_hw(&csdev->access); tpiu_disable_hw(&csdev->access);
...@@ -132,6 +140,8 @@ static int tpiu_probe(struct amba_device *adev, const struct amba_id *id) ...@@ -132,6 +140,8 @@ static int tpiu_probe(struct amba_device *adev, const struct amba_id *id)
if (!drvdata) if (!drvdata)
return -ENOMEM; return -ENOMEM;
spin_lock_init(&drvdata->spinlock);
drvdata->atclk = devm_clk_get(&adev->dev, "atclk"); /* optional */ drvdata->atclk = devm_clk_get(&adev->dev, "atclk"); /* optional */
if (!IS_ERR(drvdata->atclk)) { if (!IS_ERR(drvdata->atclk)) {
ret = clk_prepare_enable(drvdata->atclk); ret = clk_prepare_enable(drvdata->atclk);
......
...@@ -103,7 +103,7 @@ static int smb_open(struct inode *inode, struct file *file) ...@@ -103,7 +103,7 @@ static int smb_open(struct inode *inode, struct file *file)
if (drvdata->reading) if (drvdata->reading)
return -EBUSY; return -EBUSY;
if (atomic_read(&drvdata->csdev->refcnt)) if (drvdata->csdev->refcnt)
return -EBUSY; return -EBUSY;
smb_update_data_size(drvdata); smb_update_data_size(drvdata);
...@@ -271,7 +271,7 @@ static int smb_enable(struct coresight_device *csdev, enum cs_mode mode, ...@@ -271,7 +271,7 @@ static int smb_enable(struct coresight_device *csdev, enum cs_mode mode,
if (ret) if (ret)
return ret; return ret;
atomic_inc(&csdev->refcnt); csdev->refcnt++;
dev_dbg(&csdev->dev, "Ultrasoc SMB enabled\n"); dev_dbg(&csdev->dev, "Ultrasoc SMB enabled\n");
return ret; return ret;
...@@ -286,7 +286,8 @@ static int smb_disable(struct coresight_device *csdev) ...@@ -286,7 +286,8 @@ static int smb_disable(struct coresight_device *csdev)
if (drvdata->reading) if (drvdata->reading)
return -EBUSY; return -EBUSY;
if (atomic_dec_return(&csdev->refcnt)) csdev->refcnt--;
if (csdev->refcnt)
return -EBUSY; return -EBUSY;
/* Complain if we (somehow) got out of sync */ /* Complain if we (somehow) got out of sync */
...@@ -381,7 +382,7 @@ static unsigned long smb_update_buffer(struct coresight_device *csdev, ...@@ -381,7 +382,7 @@ static unsigned long smb_update_buffer(struct coresight_device *csdev,
guard(spinlock)(&drvdata->spinlock); guard(spinlock)(&drvdata->spinlock);
/* Don't do anything if another tracer is using this sink. */ /* Don't do anything if another tracer is using this sink. */
if (atomic_read(&csdev->refcnt) != 1) if (csdev->refcnt != 1)
return 0; return 0;
smb_disable_hw(drvdata); smb_disable_hw(drvdata);
......
...@@ -230,8 +230,15 @@ struct coresight_sysfs_link { ...@@ -230,8 +230,15 @@ struct coresight_sysfs_link {
* actually an 'enum cs_mode', but is stored in an atomic type. * actually an 'enum cs_mode', but is stored in an atomic type.
* This is always accessed through local_read() and local_set(), * This is always accessed through local_read() and local_set(),
* but wherever it's done from within the Coresight device's lock, * but wherever it's done from within the Coresight device's lock,
* a non-atomic read would also work. * a non-atomic read would also work. This is the main point of
* @refcnt: keep track of what is in use. * synchronisation between code happening inside the sysfs mode's
* coresight_mutex and outside when running in Perf mode. A compare
* and exchange swap is done to atomically claim one mode or the
* other.
* @refcnt: keep track of what is in use. Only access this outside of the
* device's spinlock when the coresight_mutex held and mode ==
* CS_MODE_SYSFS. Otherwise it must be accessed from inside the
* spinlock.
* @orphan: true if the component has connections that haven't been linked. * @orphan: true if the component has connections that haven't been linked.
* @sysfs_sink_activated: 'true' when a sink has been selected for use via sysfs * @sysfs_sink_activated: 'true' when a sink has been selected for use via sysfs
* by writing a 1 to the 'enable_sink' file. A sink can be * by writing a 1 to the 'enable_sink' file. A sink can be
...@@ -257,7 +264,7 @@ struct coresight_device { ...@@ -257,7 +264,7 @@ struct coresight_device {
struct csdev_access access; struct csdev_access access;
struct device dev; struct device dev;
local_t mode; local_t mode;
atomic_t refcnt; int refcnt;
bool orphan; bool orphan;
/* sink specific fields */ /* sink specific fields */
bool sysfs_sink_activated; bool sysfs_sink_activated;
......
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