BACKPORT: FROMGIT: coresight: catu: Introduce refcount and spinlock for enabling/disabling

When tracing ETM data on multiple CPUs concurrently via the
perf interface, the CATU device is shared across different CPU
paths. This can lead to race conditions when multiple CPUs attempt
to enable or disable the CATU device simultaneously.

To address these race conditions, this patch introduces the
following changes:

1. The enable and disable operations for the CATU device are not
   reentrant. Therefore, a spinlock is added to ensure that only
   one CPU can enable or disable a given CATU device at any point
   in time.

2. A reference counter is used to manage the enable/disable state
   of the CATU device. The device is enabled when the first CPU
   requires it and is only disabled when the last CPU finishes
   using it. This ensures the device remains active as long as at
   least one CPU needs it.

Bug: 393467632
(cherry picked from commit a03a0a08c6fe5e50c1b12ea41b9e228e7f649c22
 https: //git.kernel.org/pub/scm/linux/kernel/git/coresight/linux.git
 next)
Fixes: fcacb5c154 ("coresight: Introduce support for Coresight Address Translation Unit")
Change-Id: Idf0f1cbb863c3acd4ac61d071f5c57cbcb16a160
Signed-off-by: Yabin Cui <yabinc@google.com>
Reviewed-by: James Clark <james.clark@linaro.org>
Reviewed-by: Leo Yan <leo.yan@arm.com>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Link: https://lore.kernel.org/r/20250429231301.1952246-2-yabinc@google.com
This commit is contained in:
Yabin Cui
2025-04-29 16:12:59 -07:00
parent 335e1cd00d
commit 2956315ed5
2 changed files with 18 additions and 8 deletions

View File

@@ -456,12 +456,17 @@ static int catu_enable_hw(struct catu_drvdata *drvdata, enum cs_mode cs_mode,
static int catu_enable(struct coresight_device *csdev, enum cs_mode mode,
void *data)
{
int rc;
int rc = 0;
struct catu_drvdata *catu_drvdata = csdev_to_catu_drvdata(csdev);
guard(raw_spinlock_irqsave)(&catu_drvdata->spinlock);
if (atomic_read(&csdev->refcnt) == 0) {
CS_UNLOCK(catu_drvdata->base);
rc = catu_enable_hw(catu_drvdata, mode, data);
CS_LOCK(catu_drvdata->base);
}
if (!rc)
atomic_inc(&csdev->refcnt);
return rc;
}
@@ -484,12 +489,15 @@ static int catu_disable_hw(struct catu_drvdata *drvdata)
static int catu_disable(struct coresight_device *csdev, void *__unused)
{
int rc;
int rc = 0;
struct catu_drvdata *catu_drvdata = csdev_to_catu_drvdata(csdev);
guard(raw_spinlock_irqsave)(&catu_drvdata->spinlock);
if (atomic_dec_return(&csdev->refcnt) == 0) {
CS_UNLOCK(catu_drvdata->base);
rc = catu_disable_hw(catu_drvdata);
CS_LOCK(catu_drvdata->base);
}
return rc;
}
@@ -556,6 +564,7 @@ static int catu_probe(struct amba_device *adev, const struct amba_id *id)
dev->platform_data = pdata;
drvdata->base = base;
raw_spin_lock_init(&drvdata->spinlock);
catu_desc.access = CSDEV_ACCESS_IOMEM(base);
catu_desc.pdata = pdata;
catu_desc.dev = dev;

View File

@@ -64,6 +64,7 @@ struct catu_drvdata {
void __iomem *base;
struct coresight_device *csdev;
int irq;
raw_spinlock_t spinlock;
};
#define CATU_REG32(name, offset) \