[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20260209-arm_coresight_cti_refactor_v1-v1-1-db71ab4d200b@arm.com>
Date: Mon, 09 Feb 2026 18:01:11 +0000
From: Leo Yan <leo.yan@....com>
To: Suzuki K Poulose <suzuki.poulose@....com>,
Mike Leach <mike.leach@....com>, James Clark <james.clark@...aro.org>,
Alexander Shishkin <alexander.shishkin@...ux.intel.com>,
Greg Kroah-Hartman <gregkh@...uxfoundation.org>,
Mathieu Poirier <mathieu.poirier@...aro.org>,
Tingwei Zhang <quic_tingwei@...cinc.com>,
Yingchao Deng <yingchao.deng@....qualcomm.com>,
Jie Gan <jie.gan@....qualcomm.com>
Cc: coresight@...ts.linaro.org, linux-arm-kernel@...ts.infradead.org,
linux-kernel@...r.kernel.org, Leo Yan <leo.yan@....com>
Subject: [PATCH 1/8] coresight: cti: Make spinlock usage consistent
The spinlock is acquired sometimes with IRQs disabled and sometimes
without. This leads to inconsistent semantics: the lock can be either
HARDIRQ-safe or HARDIRQ-unsafe, which may trigger lockdep complaints.
Make spinlock usage consistent by acquiring it with disabling IRQs. It
is possible for sysfs knobs to acquire the spinlock for accessing a
CTI device, while at the same time a perf session sends an IPI to
enable the same CTI device. In this case, the spinlock must be
IRQ-safe, which is why all lock acquisitions are changed to disable
IRQs.
Use guard() and scoped_guard() for spinlock to tidy up the code.
Fixes: 984f37efa385 ("coresight: cti: Write regsiters directly in cti_enable_hw()")
Tested-by: James Clark <james.clark@...aro.org>
Signed-off-by: Leo Yan <leo.yan@....com>
---
drivers/hwtracing/coresight/coresight-cti-core.c | 74 ++++-------
drivers/hwtracing/coresight/coresight-cti-sysfs.c | 145 ++++++++++++----------
2 files changed, 103 insertions(+), 116 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-cti-core.c b/drivers/hwtracing/coresight/coresight-cti-core.c
index bfbc365bb2ef2744efab11c056b8450472957005..b75c4ec2c8d5d58da8761334643dba34001b48c7 100644
--- a/drivers/hwtracing/coresight/coresight-cti-core.c
+++ b/drivers/hwtracing/coresight/coresight-cti-core.c
@@ -90,10 +90,9 @@ void cti_write_all_hw_regs(struct cti_drvdata *drvdata)
static int cti_enable_hw(struct cti_drvdata *drvdata)
{
struct cti_config *config = &drvdata->config;
- unsigned long flags;
- int rc = 0;
+ int rc;
- raw_spin_lock_irqsave(&drvdata->spinlock, flags);
+ guard(raw_spinlock_irqsave)(&drvdata->spinlock);
/* no need to do anything if enabled or unpowered*/
if (config->hw_enabled || !config->hw_powered)
@@ -102,22 +101,15 @@ static int cti_enable_hw(struct cti_drvdata *drvdata)
/* claim the device */
rc = coresight_claim_device(drvdata->csdev);
if (rc)
- goto cti_err_not_enabled;
+ return rc;
cti_write_all_hw_regs(drvdata);
config->hw_enabled = true;
- drvdata->config.enable_req_count++;
- raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
- return rc;
cti_state_unchanged:
drvdata->config.enable_req_count++;
-
- /* cannot enable due to error */
-cti_err_not_enabled:
- raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
- return rc;
+ return 0;
}
/* re-enable CTI on CPU when using CPU hotplug */
@@ -125,25 +117,21 @@ static void cti_cpuhp_enable_hw(struct cti_drvdata *drvdata)
{
struct cti_config *config = &drvdata->config;
- raw_spin_lock(&drvdata->spinlock);
+ guard(raw_spinlock_irqsave)(&drvdata->spinlock);
+
config->hw_powered = true;
/* no need to do anything if no enable request */
if (!drvdata->config.enable_req_count)
- goto cti_hp_not_enabled;
+ return;
/* try to claim the device */
if (coresight_claim_device(drvdata->csdev))
- goto cti_hp_not_enabled;
+ return;
cti_write_all_hw_regs(drvdata);
config->hw_enabled = true;
- raw_spin_unlock(&drvdata->spinlock);
return;
-
- /* did not re-enable due to no claim / no request */
-cti_hp_not_enabled:
- raw_spin_unlock(&drvdata->spinlock);
}
/* disable hardware */
@@ -151,23 +139,20 @@ static int cti_disable_hw(struct cti_drvdata *drvdata)
{
struct cti_config *config = &drvdata->config;
struct coresight_device *csdev = drvdata->csdev;
- int ret = 0;
- raw_spin_lock(&drvdata->spinlock);
+ guard(raw_spinlock_irqsave)(&drvdata->spinlock);
/* don't allow negative refcounts, return an error */
- if (!drvdata->config.enable_req_count) {
- ret = -EINVAL;
- goto cti_not_disabled;
- }
+ if (!drvdata->config.enable_req_count)
+ return -EINVAL;
/* check refcount - disable on 0 */
if (--drvdata->config.enable_req_count > 0)
- goto cti_not_disabled;
+ return 0;
/* no need to do anything if disabled or cpu unpowered */
if (!config->hw_enabled || !config->hw_powered)
- goto cti_not_disabled;
+ return 0;
CS_UNLOCK(drvdata->base);
@@ -177,13 +162,7 @@ static int cti_disable_hw(struct cti_drvdata *drvdata)
coresight_disclaim_device_unlocked(csdev);
CS_LOCK(drvdata->base);
- raw_spin_unlock(&drvdata->spinlock);
- return ret;
-
- /* not disabled this call */
-cti_not_disabled:
- raw_spin_unlock(&drvdata->spinlock);
- return ret;
+ return 0;
}
void cti_write_single_reg(struct cti_drvdata *drvdata, int offset, u32 value)
@@ -198,11 +177,11 @@ void cti_write_intack(struct device *dev, u32 ackval)
struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
struct cti_config *config = &drvdata->config;
- raw_spin_lock(&drvdata->spinlock);
+ guard(raw_spinlock_irqsave)(&drvdata->spinlock);
+
/* write if enabled */
if (cti_active(config))
cti_write_single_reg(drvdata, CTIINTACK, ackval);
- raw_spin_unlock(&drvdata->spinlock);
}
/*
@@ -369,7 +348,7 @@ int cti_channel_trig_op(struct device *dev, enum cti_chan_op op,
reg_offset = (direction == CTI_TRIG_IN ? CTIINEN(trigger_idx) :
CTIOUTEN(trigger_idx));
- raw_spin_lock(&drvdata->spinlock);
+ guard(raw_spinlock_irqsave)(&drvdata->spinlock);
/* read - modify write - the trigger / channel enable value */
reg_value = direction == CTI_TRIG_IN ? config->ctiinen[trigger_idx] :
@@ -388,7 +367,7 @@ int cti_channel_trig_op(struct device *dev, enum cti_chan_op op,
/* write through if enabled */
if (cti_active(config))
cti_write_single_reg(drvdata, reg_offset, reg_value);
- raw_spin_unlock(&drvdata->spinlock);
+
return 0;
}
@@ -406,7 +385,8 @@ int cti_channel_gate_op(struct device *dev, enum cti_chan_gate_op op,
chan_bitmask = BIT(channel_idx);
- raw_spin_lock(&drvdata->spinlock);
+ guard(raw_spinlock_irqsave)(&drvdata->spinlock);
+
reg_value = config->ctigate;
switch (op) {
case CTI_GATE_CHAN_ENABLE:
@@ -426,7 +406,7 @@ int cti_channel_gate_op(struct device *dev, enum cti_chan_gate_op op,
if (cti_active(config))
cti_write_single_reg(drvdata, CTIGATE, reg_value);
}
- raw_spin_unlock(&drvdata->spinlock);
+
return err;
}
@@ -445,7 +425,8 @@ int cti_channel_setop(struct device *dev, enum cti_chan_set_op op,
chan_bitmask = BIT(channel_idx);
- raw_spin_lock(&drvdata->spinlock);
+ guard(raw_spinlock_irqsave)(&drvdata->spinlock);
+
reg_value = config->ctiappset;
switch (op) {
case CTI_CHAN_SET:
@@ -473,7 +454,6 @@ int cti_channel_setop(struct device *dev, enum cti_chan_set_op op,
if ((err == 0) && cti_active(config))
cti_write_single_reg(drvdata, reg_offset, reg_value);
- raw_spin_unlock(&drvdata->spinlock);
return err;
}
@@ -676,7 +656,7 @@ static int cti_cpu_pm_notify(struct notifier_block *nb, unsigned long cmd,
if (WARN_ON_ONCE(drvdata->ctidev.cpu != cpu))
return NOTIFY_BAD;
- raw_spin_lock(&drvdata->spinlock);
+ guard(raw_spinlock_irqsave)(&drvdata->spinlock);
switch (cmd) {
case CPU_PM_ENTER:
@@ -716,7 +696,6 @@ static int cti_cpu_pm_notify(struct notifier_block *nb, unsigned long cmd,
}
cti_notify_exit:
- raw_spin_unlock(&drvdata->spinlock);
return notify_res;
}
@@ -743,11 +722,12 @@ static int cti_dying_cpu(unsigned int cpu)
if (!drvdata)
return 0;
- raw_spin_lock(&drvdata->spinlock);
+ guard(raw_spinlock_irqsave)(&drvdata->spinlock);
+
drvdata->config.hw_powered = false;
if (drvdata->config.hw_enabled)
coresight_disclaim_device(drvdata->csdev);
- raw_spin_unlock(&drvdata->spinlock);
+
return 0;
}
diff --git a/drivers/hwtracing/coresight/coresight-cti-sysfs.c b/drivers/hwtracing/coresight/coresight-cti-sysfs.c
index 572b80ee96fbf18ec8cf9abc30d109a676dfbc5d..455d08bcccd49a3f1eac8abd8246806ef73a9ab6 100644
--- a/drivers/hwtracing/coresight/coresight-cti-sysfs.c
+++ b/drivers/hwtracing/coresight/coresight-cti-sysfs.c
@@ -84,11 +84,11 @@ static ssize_t enable_show(struct device *dev,
bool enabled, powered;
struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
- raw_spin_lock(&drvdata->spinlock);
- enable_req = drvdata->config.enable_req_count;
- powered = drvdata->config.hw_powered;
- enabled = drvdata->config.hw_enabled;
- raw_spin_unlock(&drvdata->spinlock);
+ scoped_guard(raw_spinlock_irqsave, &drvdata->spinlock) {
+ enable_req = drvdata->config.enable_req_count;
+ powered = drvdata->config.hw_powered;
+ enabled = drvdata->config.hw_enabled;
+ }
if (powered)
return sprintf(buf, "%d\n", enabled);
@@ -134,9 +134,8 @@ static ssize_t powered_show(struct device *dev,
bool powered;
struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
- raw_spin_lock(&drvdata->spinlock);
- powered = drvdata->config.hw_powered;
- raw_spin_unlock(&drvdata->spinlock);
+ scoped_guard(raw_spinlock_irqsave, &drvdata->spinlock)
+ powered = drvdata->config.hw_powered;
return sprintf(buf, "%d\n", powered);
}
@@ -181,10 +180,12 @@ static ssize_t coresight_cti_reg_show(struct device *dev,
u32 val = 0;
pm_runtime_get_sync(dev->parent);
- raw_spin_lock(&drvdata->spinlock);
- if (drvdata->config.hw_powered)
- val = readl_relaxed(drvdata->base + cti_attr->off);
- raw_spin_unlock(&drvdata->spinlock);
+
+ scoped_guard(raw_spinlock_irqsave, &drvdata->spinlock) {
+ if (drvdata->config.hw_powered)
+ val = readl_relaxed(drvdata->base + cti_attr->off);
+ }
+
pm_runtime_put_sync(dev->parent);
return sysfs_emit(buf, "0x%x\n", val);
}
@@ -202,10 +203,12 @@ static __maybe_unused ssize_t coresight_cti_reg_store(struct device *dev,
return -EINVAL;
pm_runtime_get_sync(dev->parent);
- raw_spin_lock(&drvdata->spinlock);
- if (drvdata->config.hw_powered)
- cti_write_single_reg(drvdata, cti_attr->off, val);
- raw_spin_unlock(&drvdata->spinlock);
+
+ scoped_guard(raw_spinlock_irqsave, &drvdata->spinlock) {
+ if (drvdata->config.hw_powered)
+ cti_write_single_reg(drvdata, cti_attr->off, val);
+ }
+
pm_runtime_put_sync(dev->parent);
return size;
}
@@ -264,17 +267,18 @@ static ssize_t cti_reg32_show(struct device *dev, char *buf,
struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
struct cti_config *config = &drvdata->config;
- raw_spin_lock(&drvdata->spinlock);
- if ((reg_offset >= 0) && cti_active(config)) {
- CS_UNLOCK(drvdata->base);
- val = readl_relaxed(drvdata->base + reg_offset);
- if (pcached_val)
- *pcached_val = val;
- CS_LOCK(drvdata->base);
- } else if (pcached_val) {
- val = *pcached_val;
+ scoped_guard(raw_spinlock_irqsave, &drvdata->spinlock) {
+ if ((reg_offset >= 0) && cti_active(config)) {
+ CS_UNLOCK(drvdata->base);
+ val = readl_relaxed(drvdata->base + reg_offset);
+ if (pcached_val)
+ *pcached_val = val;
+ CS_LOCK(drvdata->base);
+ } else if (pcached_val) {
+ val = *pcached_val;
+ }
}
- raw_spin_unlock(&drvdata->spinlock);
+
return sprintf(buf, "%#x\n", val);
}
@@ -293,15 +297,16 @@ static ssize_t cti_reg32_store(struct device *dev, const char *buf,
if (kstrtoul(buf, 0, &val))
return -EINVAL;
- raw_spin_lock(&drvdata->spinlock);
- /* local store */
- if (pcached_val)
- *pcached_val = (u32)val;
+ scoped_guard(raw_spinlock_irqsave, &drvdata->spinlock) {
+ /* local store */
+ if (pcached_val)
+ *pcached_val = (u32)val;
+
+ /* write through if offset and enabled */
+ if ((reg_offset >= 0) && cti_active(config))
+ cti_write_single_reg(drvdata, reg_offset, val);
+ }
- /* write through if offset and enabled */
- if ((reg_offset >= 0) && cti_active(config))
- cti_write_single_reg(drvdata, reg_offset, val);
- raw_spin_unlock(&drvdata->spinlock);
return size;
}
@@ -349,9 +354,9 @@ static ssize_t inout_sel_store(struct device *dev,
if (val > (CTIINOUTEN_MAX - 1))
return -EINVAL;
- raw_spin_lock(&drvdata->spinlock);
+ guard(raw_spinlock_irqsave)(&drvdata->spinlock);
+
drvdata->config.ctiinout_sel = val;
- raw_spin_unlock(&drvdata->spinlock);
return size;
}
static DEVICE_ATTR_RW(inout_sel);
@@ -364,10 +369,11 @@ static ssize_t inen_show(struct device *dev,
int index;
struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
- raw_spin_lock(&drvdata->spinlock);
- index = drvdata->config.ctiinout_sel;
- val = drvdata->config.ctiinen[index];
- raw_spin_unlock(&drvdata->spinlock);
+ scoped_guard(raw_spinlock_irqsave, &drvdata->spinlock) {
+ index = drvdata->config.ctiinout_sel;
+ val = drvdata->config.ctiinen[index];
+ }
+
return sprintf(buf, "%#lx\n", val);
}
@@ -383,14 +389,15 @@ static ssize_t inen_store(struct device *dev,
if (kstrtoul(buf, 0, &val))
return -EINVAL;
- raw_spin_lock(&drvdata->spinlock);
+ guard(raw_spinlock_irqsave)(&drvdata->spinlock);
+
index = config->ctiinout_sel;
config->ctiinen[index] = val;
/* write through if enabled */
if (cti_active(config))
cti_write_single_reg(drvdata, CTIINEN(index), val);
- raw_spin_unlock(&drvdata->spinlock);
+
return size;
}
static DEVICE_ATTR_RW(inen);
@@ -403,10 +410,11 @@ static ssize_t outen_show(struct device *dev,
int index;
struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
- raw_spin_lock(&drvdata->spinlock);
- index = drvdata->config.ctiinout_sel;
- val = drvdata->config.ctiouten[index];
- raw_spin_unlock(&drvdata->spinlock);
+ scoped_guard(raw_spinlock_irqsave, &drvdata->spinlock) {
+ index = drvdata->config.ctiinout_sel;
+ val = drvdata->config.ctiouten[index];
+ }
+
return sprintf(buf, "%#lx\n", val);
}
@@ -422,14 +430,15 @@ static ssize_t outen_store(struct device *dev,
if (kstrtoul(buf, 0, &val))
return -EINVAL;
- raw_spin_lock(&drvdata->spinlock);
+ guard(raw_spinlock_irqsave)(&drvdata->spinlock);
+
index = config->ctiinout_sel;
config->ctiouten[index] = val;
/* write through if enabled */
if (cti_active(config))
cti_write_single_reg(drvdata, CTIOUTEN(index), val);
- raw_spin_unlock(&drvdata->spinlock);
+
return size;
}
static DEVICE_ATTR_RW(outen);
@@ -463,7 +472,7 @@ static ssize_t appclear_store(struct device *dev,
if (kstrtoul(buf, 0, &val))
return -EINVAL;
- raw_spin_lock(&drvdata->spinlock);
+ guard(raw_spinlock_irqsave)(&drvdata->spinlock);
/* a 1'b1 in appclr clears down the same bit in appset*/
config->ctiappset &= ~val;
@@ -471,7 +480,7 @@ static ssize_t appclear_store(struct device *dev,
/* write through if enabled */
if (cti_active(config))
cti_write_single_reg(drvdata, CTIAPPCLEAR, val);
- raw_spin_unlock(&drvdata->spinlock);
+
return size;
}
static DEVICE_ATTR_WO(appclear);
@@ -487,12 +496,12 @@ static ssize_t apppulse_store(struct device *dev,
if (kstrtoul(buf, 0, &val))
return -EINVAL;
- raw_spin_lock(&drvdata->spinlock);
+ guard(raw_spinlock_irqsave)(&drvdata->spinlock);
/* write through if enabled */
if (cti_active(config))
cti_write_single_reg(drvdata, CTIAPPPULSE, val);
- raw_spin_unlock(&drvdata->spinlock);
+
return size;
}
static DEVICE_ATTR_WO(apppulse);
@@ -681,9 +690,9 @@ static ssize_t trig_filter_enable_show(struct device *dev,
u32 val;
struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
- raw_spin_lock(&drvdata->spinlock);
- val = drvdata->config.trig_filter_enable;
- raw_spin_unlock(&drvdata->spinlock);
+ scoped_guard(raw_spinlock_irqsave, &drvdata->spinlock)
+ val = drvdata->config.trig_filter_enable;
+
return sprintf(buf, "%d\n", val);
}
@@ -697,9 +706,9 @@ static ssize_t trig_filter_enable_store(struct device *dev,
if (kstrtoul(buf, 0, &val))
return -EINVAL;
- raw_spin_lock(&drvdata->spinlock);
+ guard(raw_spinlock_irqsave)(&drvdata->spinlock);
+
drvdata->config.trig_filter_enable = !!val;
- raw_spin_unlock(&drvdata->spinlock);
return size;
}
static DEVICE_ATTR_RW(trig_filter_enable);
@@ -728,7 +737,7 @@ static ssize_t chan_xtrigs_reset_store(struct device *dev,
struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
struct cti_config *config = &drvdata->config;
- raw_spin_lock(&drvdata->spinlock);
+ guard(raw_spinlock_irqsave)(&drvdata->spinlock);
/* clear the CTI trigger / channel programming registers */
for (i = 0; i < config->nr_trig_max; i++) {
@@ -747,7 +756,6 @@ static ssize_t chan_xtrigs_reset_store(struct device *dev,
if (cti_active(config))
cti_write_all_hw_regs(drvdata);
- raw_spin_unlock(&drvdata->spinlock);
return size;
}
static DEVICE_ATTR_WO(chan_xtrigs_reset);
@@ -768,9 +776,9 @@ static ssize_t chan_xtrigs_sel_store(struct device *dev,
if (val > (drvdata->config.nr_ctm_channels - 1))
return -EINVAL;
- raw_spin_lock(&drvdata->spinlock);
+ guard(raw_spinlock_irqsave)(&drvdata->spinlock);
+
drvdata->config.xtrig_rchan_sel = val;
- raw_spin_unlock(&drvdata->spinlock);
return size;
}
@@ -781,9 +789,8 @@ static ssize_t chan_xtrigs_sel_show(struct device *dev,
unsigned long val;
struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
- raw_spin_lock(&drvdata->spinlock);
- val = drvdata->config.xtrig_rchan_sel;
- raw_spin_unlock(&drvdata->spinlock);
+ scoped_guard(raw_spinlock_irqsave, &drvdata->spinlock)
+ val = drvdata->config.xtrig_rchan_sel;
return sprintf(buf, "%ld\n", val);
}
@@ -838,12 +845,12 @@ static ssize_t print_chan_list(struct device *dev,
unsigned long inuse_bits = 0, chan_mask;
/* scan regs to get bitmap of channels in use. */
- raw_spin_lock(&drvdata->spinlock);
- for (i = 0; i < config->nr_trig_max; i++) {
- inuse_bits |= config->ctiinen[i];
- inuse_bits |= config->ctiouten[i];
+ scoped_guard(raw_spinlock_irqsave, &drvdata->spinlock) {
+ for (i = 0; i < config->nr_trig_max; i++) {
+ inuse_bits |= config->ctiinen[i];
+ inuse_bits |= config->ctiouten[i];
+ }
}
- raw_spin_unlock(&drvdata->spinlock);
/* inverse bits if printing free channels */
if (!inuse)
--
2.34.1
Powered by blists - more mailing lists