[PATCH 6/6] gpu: host1x: Annotate intentional syncpoint wrap-around

From: Mikko Perttunen

Date: Tue Jun 09 2026 - 04:27:26 EST


Host1x syncpoints are 32-bit counters that roll over by design.
To make that explicit in the code, use wrapping_* functions whenever
arithmetic is done on syncpoint values.

Atomic operations cannot be updated but a comment is added.

Signed-off-by: Mikko Perttunen <mperttunen@xxxxxxxxxx>
---
drivers/gpu/host1x/cdma.c | 3 ++-
drivers/gpu/host1x/hw/channel_hw.c | 10 +++++++---
drivers/gpu/host1x/intr.c | 5 +++--
drivers/gpu/host1x/syncpt.c | 7 ++++++-
drivers/gpu/host1x/syncpt.h | 3 ++-
5 files changed, 20 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/host1x/cdma.c b/drivers/gpu/host1x/cdma.c
index ba2e572567c0..f6d3db2c8c39 100644
--- a/drivers/gpu/host1x/cdma.c
+++ b/drivers/gpu/host1x/cdma.c
@@ -13,6 +13,7 @@
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/kfifo.h>
+#include <linux/overflow.h>
#include <linux/slab.h>
#include <trace/events/host1x.h>

@@ -419,7 +420,7 @@ void host1x_cdma_update_sync_queue(struct host1x_cdma *cdma,
/* won't need a timeout when replayed */
job->timeout = 0;

- syncpt_incrs = job->syncpt_end - syncpt_val;
+ syncpt_incrs = wrapping_sub(u32, job->syncpt_end, syncpt_val);
dev_dbg(dev, "%s: CPU incr (%d)\n", __func__, syncpt_incrs);

host1x_job_dump(dev, job);
diff --git a/drivers/gpu/host1x/hw/channel_hw.c b/drivers/gpu/host1x/hw/channel_hw.c
index 9dda73199889..a8251ec0810c 100644
--- a/drivers/gpu/host1x/hw/channel_hw.c
+++ b/drivers/gpu/host1x/hw/channel_hw.c
@@ -7,6 +7,7 @@

#include <linux/host1x.h>
#include <linux/iommu.h>
+#include <linux/overflow.h>
#include <linux/slab.h>

#include <trace/events/host1x.h>
@@ -120,7 +121,8 @@ static void submit_gathers(struct host1x_job *job, struct host1x_job_cmd *cmds,

if (cmd->is_wait) {
if (cmd->wait.relative)
- threshold = job_syncpt_base + cmd->wait.threshold;
+ threshold = wrapping_add(u32, job_syncpt_base,
+ cmd->wait.threshold);
else
threshold = cmd->wait.threshold;

@@ -259,7 +261,8 @@ static void channel_program_cdma(struct host1x_job *job)

/* Submit work. */
job->syncpt_end = host1x_syncpt_incr_max(sp, job->syncpt_incrs);
- submit_gathers(job, job->cmds + i, job->num_cmds - i, job->syncpt_end - job->syncpt_incrs);
+ submit_gathers(job, job->cmds + i, job->num_cmds - i,
+ wrapping_sub(u32, job->syncpt_end, job->syncpt_incrs));

/* Before releasing MLOCK, ensure engine is idle again. */
fence = host1x_syncpt_incr_max(sp, 1);
@@ -297,7 +300,8 @@ static void channel_program_cdma(struct host1x_job *job)

job->syncpt_end = host1x_syncpt_incr_max(sp, job->syncpt_incrs);

- submit_gathers(job, job->cmds, job->num_cmds, job->syncpt_end - job->syncpt_incrs);
+ submit_gathers(job, job->cmds, job->num_cmds,
+ wrapping_sub(u32, job->syncpt_end, job->syncpt_incrs));
#endif
}

diff --git a/drivers/gpu/host1x/intr.c b/drivers/gpu/host1x/intr.c
index f77a678949e9..f9fd8a471e60 100644
--- a/drivers/gpu/host1x/intr.c
+++ b/drivers/gpu/host1x/intr.c
@@ -7,6 +7,7 @@

#include <linux/clk.h>
#include <linux/interrupt.h>
+#include <linux/overflow.h>
#include "dev.h"
#include "fence.h"
#include "intr.h"
@@ -17,7 +18,7 @@ static void host1x_intr_add_fence_to_list(struct host1x_fence_list *list,
struct host1x_syncpt_fence *fence_in_list;

list_for_each_entry_reverse(fence_in_list, &list->list, list) {
- if ((s32)(fence_in_list->threshold - fence->threshold) <= 0) {
+ if ((s32)wrapping_sub(u32, fence_in_list->threshold, fence->threshold) <= 0) {
/* Fence in list is before us, we can insert here */
list_add(&fence->list, &fence_in_list->list);
return;
@@ -83,7 +84,7 @@ void host1x_intr_handle_interrupt(struct host1x *host, unsigned int id)
spin_lock(&sp->fences.lock);

list_for_each_entry_safe(fence, tmp, &sp->fences.list, list) {
- if (((value - fence->threshold) & 0x80000000U) != 0U) {
+ if ((wrapping_sub(u32, value, fence->threshold) & 0x80000000U) != 0U) {
/* Fence is not yet expired, we are done */
break;
}
diff --git a/drivers/gpu/host1x/syncpt.c b/drivers/gpu/host1x/syncpt.c
index acc7d82e0585..9ac4f0c80728 100644
--- a/drivers/gpu/host1x/syncpt.c
+++ b/drivers/gpu/host1x/syncpt.c
@@ -8,6 +8,7 @@
#include <linux/module.h>
#include <linux/device.h>
#include <linux/dma-fence.h>
+#include <linux/overflow.h>
#include <linux/slab.h>

#include <trace/events/host1x.h>
@@ -126,6 +127,10 @@ EXPORT_SYMBOL(host1x_syncpt_id);
*/
u32 host1x_syncpt_incr_max(struct host1x_syncpt *sp, u32 incrs)
{
+ /*
+ * Syncpoint values are intended to be modulo 2^32, so overflow
+ * here is intended.
+ */
return (u32)atomic_add_return(incrs, &sp->max_val);
}
EXPORT_SYMBOL(host1x_syncpt_incr_max);
@@ -274,7 +279,7 @@ bool host1x_syncpt_is_expired(struct host1x_syncpt *sp, u32 thresh)

current_val = (u32)atomic_read(&sp->min_val);

- return ((current_val - thresh) & 0x80000000U) == 0U;
+ return (wrapping_sub(u32, current_val, thresh) & 0x80000000U) == 0U;
}

int host1x_syncpt_init(struct host1x *host)
diff --git a/drivers/gpu/host1x/syncpt.h b/drivers/gpu/host1x/syncpt.h
index 4c3f3b2f0e9c..9eff42efc445 100644
--- a/drivers/gpu/host1x/syncpt.h
+++ b/drivers/gpu/host1x/syncpt.h
@@ -12,6 +12,7 @@
#include <linux/host1x.h>
#include <linux/kernel.h>
#include <linux/kref.h>
+#include <linux/overflow.h>
#include <linux/sched.h>

#include "fence.h"
@@ -77,7 +78,7 @@ static inline bool host1x_syncpt_check_max(struct host1x_syncpt *sp, u32 real)
if (sp->client_managed)
return true;
max = host1x_syncpt_read_max(sp);
- return (s32)(max - real) >= 0;
+ return (s32)wrapping_sub(u32, max, real) >= 0;
}

/* Return true if sync point is client managed. */

--
2.53.0