[PATCH v2 05/14] drm/panfrost: use spinlock instead of atomic

From: ClÃment PÃron
Date: Sat Jul 04 2020 - 06:26:32 EST


Convert busy_count to a simple int protected by spinlock.

Signed-off-by: ClÃment PÃron <peron.clem@xxxxxxxxx>
Reviewed-by: Steven Price <steven.price@xxxxxxx>
---
drivers/gpu/drm/panfrost/panfrost_devfreq.c | 43 +++++++++++++++------
drivers/gpu/drm/panfrost/panfrost_devfreq.h | 9 ++++-
2 files changed, 40 insertions(+), 12 deletions(-)

diff --git a/drivers/gpu/drm/panfrost/panfrost_devfreq.c b/drivers/gpu/drm/panfrost/panfrost_devfreq.c
index 962550363391..78753cfb59fb 100644
--- a/drivers/gpu/drm/panfrost/panfrost_devfreq.c
+++ b/drivers/gpu/drm/panfrost/panfrost_devfreq.c
@@ -12,16 +12,12 @@

static void panfrost_devfreq_update_utilization(struct panfrost_devfreq *pfdevfreq)
{
- ktime_t now;
- ktime_t last;
-
- if (!pfdevfreq->devfreq)
- return;
+ ktime_t now, last;

now = ktime_get();
last = pfdevfreq->time_last_update;

- if (atomic_read(&pfdevfreq->busy_count) > 0)
+ if (pfdevfreq->busy_count > 0)
pfdevfreq->busy_time += ktime_sub(now, last);
else
pfdevfreq->idle_time += ktime_sub(now, last);
@@ -59,10 +55,14 @@ static int panfrost_devfreq_get_dev_status(struct device *dev,
{
struct panfrost_device *pfdev = dev_get_drvdata(dev);
struct panfrost_devfreq *pfdevfreq = &pfdev->pfdevfreq;
+ unsigned long irqflags;
+
+ status->current_frequency = clk_get_rate(pfdev->clock);
+
+ spin_lock_irqsave(&pfdevfreq->lock, irqflags);

panfrost_devfreq_update_utilization(pfdevfreq);

- status->current_frequency = clk_get_rate(pfdev->clock);
status->total_time = ktime_to_ns(ktime_add(pfdevfreq->busy_time,
pfdevfreq->idle_time));

@@ -70,6 +70,8 @@ static int panfrost_devfreq_get_dev_status(struct device *dev,

panfrost_devfreq_reset(pfdevfreq);

+ spin_unlock_irqrestore(&pfdevfreq->lock, irqflags);
+
dev_dbg(pfdev->dev, "busy %lu total %lu %lu %% freq %lu MHz\n",
status->busy_time, status->total_time,
status->busy_time / (status->total_time / 100),
@@ -100,6 +102,8 @@ int panfrost_devfreq_init(struct panfrost_device *pfdev)
else if (ret)
return ret;

+ spin_lock_init(&pfdevfreq->lock);
+
panfrost_devfreq_reset(pfdevfreq);

cur_freq = clk_get_rate(pfdev->clock);
@@ -162,15 +166,32 @@ void panfrost_devfreq_suspend(struct panfrost_device *pfdev)

void panfrost_devfreq_record_busy(struct panfrost_devfreq *pfdevfreq)
{
+ unsigned long irqflags;
+
+ if (!pfdevfreq->devfreq)
+ return;
+
+ spin_lock_irqsave(&pfdevfreq->lock, irqflags);
+
panfrost_devfreq_update_utilization(pfdevfreq);
- atomic_inc(&pfdevfreq->busy_count);
+
+ pfdevfreq->busy_count++;
+
+ spin_unlock_irqrestore(&pfdevfreq->lock, irqflags);
}

void panfrost_devfreq_record_idle(struct panfrost_devfreq *pfdevfreq)
{
- int count;
+ unsigned long irqflags;
+
+ if (!pfdevfreq->devfreq)
+ return;
+
+ spin_lock_irqsave(&pfdevfreq->lock, irqflags);

panfrost_devfreq_update_utilization(pfdevfreq);
- count = atomic_dec_if_positive(&pfdevfreq->busy_count);
- WARN_ON(count < 0);
+
+ WARN_ON(--pfdevfreq->busy_count < 0);
+
+ spin_unlock_irqrestore(&pfdevfreq->lock, irqflags);
}
diff --git a/drivers/gpu/drm/panfrost/panfrost_devfreq.h b/drivers/gpu/drm/panfrost/panfrost_devfreq.h
index 0697f8d5aa34..3392df1020be 100644
--- a/drivers/gpu/drm/panfrost/panfrost_devfreq.h
+++ b/drivers/gpu/drm/panfrost/panfrost_devfreq.h
@@ -4,6 +4,7 @@
#ifndef __PANFROST_DEVFREQ_H__
#define __PANFROST_DEVFREQ_H__

+#include <linux/spinlock.h>
#include <linux/ktime.h>

struct devfreq;
@@ -14,10 +15,16 @@ struct panfrost_device;
struct panfrost_devfreq {
struct devfreq *devfreq;
struct thermal_cooling_device *cooling;
+
ktime_t busy_time;
ktime_t idle_time;
ktime_t time_last_update;
- atomic_t busy_count;
+ int busy_count;
+ /*
+ * Protect busy_time, idle_time, time_last_update and busy_count
+ * because these can be updated concurrently between multiple jobs.
+ */
+ spinlock_t lock;
};

int panfrost_devfreq_init(struct panfrost_device *pfdev);
--
2.25.1