[PATCH 5/9] coresight-etb10: change etb_drvdata spinlock's type to raw_spinlock_t
From: Yeoreum Yun <hidden>
Date: 2024-11-25 09:48:34
Also in:
linux-rt-devel, lkml
Subsystem:
arm/coresight framework and drivers, hardware tracing facilities, the rest · Maintainers:
Suzuki K Poulose, Alexander Shishkin, Linus Torvalds
From: Levi Yun <redacted> In coresight-etb10 drivers, etb_drvdata->spinlock can be held during __schedule() by perf_event_task_sched_out()/in(). Since etb_drvdata->spinlock type is spinlock_t and perf_event_task_sched_out()/in() is called after acquiring rq_lock, which is raw_spinlock_t (an unsleepable lock), this poses an issue in PREEMPT_RT kernel where spinlock_t is sleepable. To address this, change type etb_drvdata->spinlock in coresight-etb10 drivers, which can be called by perf_event_task_sched_out()/in(), from spinlock_t to raw_spinlock_t. Signed-off-by: Yeoreum Yun <redacted> --- drivers/hwtracing/coresight/coresight-etb10.c | 62 +++++++------------ 1 file changed, 22 insertions(+), 40 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-etb10.c b/drivers/hwtracing/coresight/coresight-etb10.c
index aea9ac9c4bd0..ec439f8fbc1e 100644
--- a/drivers/hwtracing/coresight/coresight-etb10.c
+++ b/drivers/hwtracing/coresight/coresight-etb10.c@@ -84,7 +84,7 @@ struct etb_drvdata { struct clk *atclk; struct coresight_device *csdev; struct miscdevice miscdev; - spinlock_t spinlock; + raw_spinlock_t spinlock; local_t reading; pid_t pid; u8 *buf;
@@ -141,56 +141,47 @@ static int etb_enable_hw(struct etb_drvdata *drvdata) static int etb_enable_sysfs(struct coresight_device *csdev) { - int ret = 0; - unsigned long flags; + int ret; struct etb_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); - spin_lock_irqsave(&drvdata->spinlock, flags); + guard(raw_spinlock_irqsave)(&drvdata->spinlock); /* Don't messup with perf sessions. */ - if (coresight_get_mode(csdev) == CS_MODE_PERF) { - ret = -EBUSY; - goto out; - } + if (coresight_get_mode(csdev) == CS_MODE_PERF) + return -EBUSY; if (coresight_get_mode(csdev) == CS_MODE_DISABLED) { ret = etb_enable_hw(drvdata); if (ret) - goto out; + return ret; coresight_set_mode(csdev, CS_MODE_SYSFS); } csdev->refcnt++; -out: - spin_unlock_irqrestore(&drvdata->spinlock, flags); - return ret; + + return 0; } static int etb_enable_perf(struct coresight_device *csdev, void *data) { - int ret = 0; + int ret; pid_t pid; - unsigned long flags; struct etb_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); struct perf_output_handle *handle = data; struct cs_buffers *buf = etm_perf_sink_config(handle); - spin_lock_irqsave(&drvdata->spinlock, flags); + guard(raw_spinlock_irqsave)(&drvdata->spinlock); /* No need to continue if the component is already in used by sysFS. */ - if (coresight_get_mode(drvdata->csdev) == CS_MODE_SYSFS) { - ret = -EBUSY; - goto out; - } + if (coresight_get_mode(drvdata->csdev) == CS_MODE_SYSFS) + return -EBUSY; /* Get a handle on the pid of the process to monitor */ pid = buf->pid; - if (drvdata->pid != -1 && drvdata->pid != pid) { - ret = -EBUSY; - goto out; - } + if (drvdata->pid != -1 && drvdata->pid != pid) + return -EBUSY; /* * No HW configuration is needed if the sink is already in
@@ -198,7 +189,7 @@ static int etb_enable_perf(struct coresight_device *csdev, void *data) */ if (drvdata->pid == pid) { csdev->refcnt++; - goto out; + return 0; } /*
@@ -208,7 +199,7 @@ static int etb_enable_perf(struct coresight_device *csdev, void *data) */ ret = etb_set_buffer(csdev, handle); if (ret) - goto out; + return ret; ret = etb_enable_hw(drvdata); if (!ret) {
@@ -218,8 +209,6 @@ static int etb_enable_perf(struct coresight_device *csdev, void *data) csdev->refcnt++; } -out: - spin_unlock_irqrestore(&drvdata->spinlock, flags); return ret; }
@@ -350,13 +339,11 @@ static void etb_disable_hw(struct etb_drvdata *drvdata) static int etb_disable(struct coresight_device *csdev) { struct etb_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); - unsigned long flags; - spin_lock_irqsave(&drvdata->spinlock, flags); + guard(raw_spinlock_irqsave)(&drvdata->spinlock); csdev->refcnt--; if (csdev->refcnt) { - spin_unlock_irqrestore(&drvdata->spinlock, flags); return -EBUSY; }
@@ -366,7 +353,6 @@ static int etb_disable(struct coresight_device *csdev) /* Dissociate from monitored process. */ drvdata->pid = -1; coresight_set_mode(csdev, CS_MODE_DISABLED); - spin_unlock_irqrestore(&drvdata->spinlock, flags); dev_dbg(&csdev->dev, "ETB disabled\n"); return 0;
@@ -434,7 +420,7 @@ static unsigned long etb_update_buffer(struct coresight_device *csdev, const u32 *barrier; u32 read_ptr, write_ptr, capacity; u32 status, read_data; - unsigned long offset, to_read = 0, flags; + unsigned long offset, to_read = 0; struct cs_buffers *buf = sink_config; struct etb_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
@@ -443,11 +429,11 @@ static unsigned long etb_update_buffer(struct coresight_device *csdev, capacity = drvdata->buffer_depth * ETB_FRAME_SIZE_WORDS; - spin_lock_irqsave(&drvdata->spinlock, flags); + guard(raw_spinlock_irqsave)(&drvdata->spinlock); /* Don't do anything if another tracer is using this sink */ if (csdev->refcnt != 1) - goto out; + return 0; __etb_disable_hw(drvdata); CS_UNLOCK(drvdata->base);
@@ -565,8 +551,6 @@ static unsigned long etb_update_buffer(struct coresight_device *csdev, __etb_enable_hw(drvdata); CS_LOCK(drvdata->base); -out: - spin_unlock_irqrestore(&drvdata->spinlock, flags); return to_read; }
@@ -585,15 +569,13 @@ static const struct coresight_ops etb_cs_ops = { static void etb_dump(struct etb_drvdata *drvdata) { - unsigned long flags; + guard(raw_spinlock_irqsave)(&drvdata->spinlock); - spin_lock_irqsave(&drvdata->spinlock, flags); if (coresight_get_mode(drvdata->csdev) == CS_MODE_SYSFS) { __etb_disable_hw(drvdata); etb_dump_hw(drvdata); __etb_enable_hw(drvdata); } - spin_unlock_irqrestore(&drvdata->spinlock, flags); dev_dbg(&drvdata->csdev->dev, "ETB dumped\n"); }
@@ -746,7 +728,7 @@ static int etb_probe(struct amba_device *adev, const struct amba_id *id) drvdata->base = base; desc.access = CSDEV_ACCESS_IOMEM(base); - spin_lock_init(&drvdata->spinlock); + raw_spin_lock_init(&drvdata->spinlock); drvdata->buffer_depth = etb_get_buffer_depth(drvdata);
--
LEVI:{C3F47F37-75D8-414A-A8BA-3980EC8A46D7}