Message ID | 20200510165538.19720-6-peron.clem@gmail.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | Add regulator devfreq support to Panfrost | expand |
On 10/05/2020 17:55, Clément Péron wrote: > Convert busy_count to a simple int protected by spinlock. > > Signed-off-by: Clément Péron <peron.clem@gmail.com> Looks like a fairly mechanical cleanup. Reviewed-by: Steven Price <steven.price@arm.com> > --- > drivers/gpu/drm/panfrost/panfrost_devfreq.c | 43 +++++++++++++++------ > drivers/gpu/drm/panfrost/panfrost_devfreq.h | 10 ++++- > 2 files changed, 41 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..e6629900a618 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,17 @@ 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, for example by the GP > + * and PP interrupts. > + */ > + spinlock_t lock; > }; > > int panfrost_devfreq_init(struct panfrost_device *pfdev); >
On 2020-05-10 17:55, Clément Péron wrote: > Convert busy_count to a simple int protected by spinlock. A little more reasoning might be nice. > Signed-off-by: Clément Péron <peron.clem@gmail.com> > --- [...] > diff --git a/drivers/gpu/drm/panfrost/panfrost_devfreq.h b/drivers/gpu/drm/panfrost/panfrost_devfreq.h > index 0697f8d5aa34..e6629900a618 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,17 @@ 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, for example by the GP > + * and PP interrupts. > + */ Nit: this comment is clearly wrong, since we only have Job, GPU and MMU interrupts here. I guess if there is a race it would be between submission/completion/timeout on different job slots. Given that, should this actually be considered a fix for 9e62b885f715 ("drm/panfrost: Simplify devfreq utilisation tracking")? Robin.
Hi Robin, On Fri, 29 May 2020 at 14:20, Robin Murphy <robin.murphy@arm.com> wrote: > > On 2020-05-10 17:55, Clément Péron wrote: > > Convert busy_count to a simple int protected by spinlock. > > A little more reasoning might be nice. I have follow the modification requested for lima devfreq and clearly don't have any argument to switch to spinlock. The Lima Maintainer asked to change witht the following reason : "Better make this count a normal int which is also protected by the spinlock, because current implementation can't protect atomic ops for state change and busy idle check and we are using spinlock already" > > > Signed-off-by: Clément Péron <peron.clem@gmail.com> > > --- > [...] > > diff --git a/drivers/gpu/drm/panfrost/panfrost_devfreq.h b/drivers/gpu/drm/panfrost/panfrost_devfreq.h > > index 0697f8d5aa34..e6629900a618 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,17 @@ 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, for example by the GP > > + * and PP interrupts. > > + */ > > Nit: this comment is clearly wrong, since we only have Job, GPU and MMU > interrupts here. I guess if there is a race it would be between > submission/completion/timeout on different job slots. It's copy/paste from lima I will update it, > > Given that, should this actually be considered a fix for 9e62b885f715 > ("drm/panfrost: Simplify devfreq utilisation tracking")? I can't say if it can be considered as a fix, I didn't see any improvement on my board before and after this patch. I'm still facing some issue and didn't have time to fully investigate it. Thanks for you review, > > Robin.
On 29/05/2020 13:35, Clément Péron wrote: > Hi Robin, > > On Fri, 29 May 2020 at 14:20, Robin Murphy <robin.murphy@arm.com> wrote: >> >> On 2020-05-10 17:55, Clément Péron wrote: >>> Convert busy_count to a simple int protected by spinlock. >> >> A little more reasoning might be nice. > > I have follow the modification requested for lima devfreq and clearly > don't have any argument to switch to spinlock. > > The Lima Maintainer asked to change witht the following reason : > "Better make this count a normal int which is also protected by the spinlock, > because current implementation can't protect atomic ops for state change > and busy idle check and we are using spinlock already" > >> >>> Signed-off-by: Clément Péron <peron.clem@gmail.com> >>> --- >> [...] >>> diff --git a/drivers/gpu/drm/panfrost/panfrost_devfreq.h b/drivers/gpu/drm/panfrost/panfrost_devfreq.h >>> index 0697f8d5aa34..e6629900a618 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,17 @@ 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, for example by the GP >>> + * and PP interrupts. >>> + */ >> >> Nit: this comment is clearly wrong, since we only have Job, GPU and MMU >> interrupts here. I guess if there is a race it would be between >> submission/completion/timeout on different job slots. > > It's copy/paste from lima I will update it, Lima ('Utgard') has separate units for geometry and pixel processing (GP/PP). For Panfrost ('Midgard'/'Bifrost') we don't have that separation, however there are multiple job slots. which are implemented as multiple DRM schedulers. So the same fix is appropriate, but clearly I missed this comment because it's referring to GP/PP which don't exist for Midgard/Bifrost. >> >> Given that, should this actually be considered a fix for 9e62b885f715 >> ("drm/panfrost: Simplify devfreq utilisation tracking")? > > I can't say if it can be considered as a fix, I didn't see any > improvement on my board before and after this patch. > I'm still facing some issue and didn't have time to fully investigate it. Technically this is a fix - there's a small race which could cause the devfreq information to become corrupted. However it would resolve itself on the next devfreq interval when panfrost_devfreq_reset() is called. So the impact is very minor (devfreq gets some bogus figures). The important variable (busy_count) was already an atomic so won't be affected. Steve > Thanks for you review, > > >> >> Robin.
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..e6629900a618 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,17 @@ 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, for example by the GP + * and PP interrupts. + */ + spinlock_t lock; }; int panfrost_devfreq_init(struct panfrost_device *pfdev);
Convert busy_count to a simple int protected by spinlock. Signed-off-by: Clément Péron <peron.clem@gmail.com> --- drivers/gpu/drm/panfrost/panfrost_devfreq.c | 43 +++++++++++++++------ drivers/gpu/drm/panfrost/panfrost_devfreq.h | 10 ++++- 2 files changed, 41 insertions(+), 12 deletions(-)