[PATCH] drm/panthor: Wrap register accessor helpers for type safety

From: Nicolas Frattaroli

Date: Fri May 08 2026 - 14:01:33 EST


In Commit a8f5738779a9 ("drm/panthor: Pass an iomem pointer to GPU
register access helpers"), the gpu register access helpers were changed
from taking a pointer to a struct panthor_device in their first
argument, to taking a void pointer.

This can cause problems, as patches based on panthor before this change
will still compile fine after it. struct panthor_device * implicitly
casts to a void pointer, resulting in completely wrong semantics.

Prevent this problem by wrapping the affected functions with macros that
specifically check for and reject the struct panthor_device * type as
the first argument.

Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@xxxxxxxxxxxxx>
---
drivers/gpu/drm/panthor/panthor_device.h | 68 +++++++++++++++++++++++++-------
1 file changed, 53 insertions(+), 15 deletions(-)

diff --git a/drivers/gpu/drm/panthor/panthor_device.h b/drivers/gpu/drm/panthor/panthor_device.h
index 4e4607bca7cc..91e9f499bf69 100644
--- a/drivers/gpu/drm/panthor/panthor_device.h
+++ b/drivers/gpu/drm/panthor/panthor_device.h
@@ -630,49 +630,87 @@ static inline void panthor_ ## __name ## _irq_disable_events(struct panthor_irq

extern struct workqueue_struct *panthor_cleanup_wq;

-static inline void gpu_write(void __iomem *iomem, u32 reg, u32 data)
+static inline void _gpu_write(void __iomem *iomem, u32 reg, u32 data)
{
writel(data, iomem + reg);
}

-static inline u32 gpu_read(void __iomem *iomem, u32 reg)
+static inline u32 _gpu_read(void __iomem *iomem, u32 reg)
{
return readl(iomem + reg);
}

-static inline u32 gpu_read_relaxed(void __iomem *iomem, u32 reg)
+static inline u32 _gpu_read_relaxed(void __iomem *iomem, u32 reg)
{
return readl_relaxed(iomem + reg);
}

-static inline void gpu_write64(void __iomem *iomem, u32 reg, u64 data)
+/*
+ * The function signature of gpu_read/gpu_write/gpu_read_relaxed/... used to
+ * take a &struct panthor_device* as the first parameter. During the split of
+ * iomem ranges into individual sub-components, this was changed to take a
+ * void __iomem* instead. These wrappers exists Tto avoid situations wherein
+ * pre-refactor patches are applied in error, as they'd compile fine. That's
+ * because the old calling convention's first parameter implicitly casts to a
+ * void pointer.
+ */
+
+#define gpu_write(iomem, reg, data) ({ \
+ static_assert(!__same_type((iomem), struct panthor_device *)); \
+ _gpu_write((iomem), (reg), (data)); })
+
+#define gpu_read(iomem, reg) ({ \
+ static_assert(!__same_type((iomem), struct panthor_device *)); \
+ _gpu_read((iomem), (reg)); })
+
+#define gpu_read_relaxed(iomem, reg) ({ \
+ static_assert(!__same_type((iomem), struct panthor_device *)); \
+ _gpu_read_relaxed((iomem), (reg)); })
+
+static inline void _gpu_write64(void __iomem *iomem, u32 reg, u64 data)
{
- gpu_write(iomem, reg, lower_32_bits(data));
- gpu_write(iomem, reg + 4, upper_32_bits(data));
+ _gpu_write(iomem, reg, lower_32_bits(data));
+ _gpu_write(iomem, reg + 4, upper_32_bits(data));
}

-static inline u64 gpu_read64(void __iomem *iomem, u32 reg)
+#define gpu_write64(iomem, reg, data) ({ \
+ static_assert(!__same_type((iomem), struct panthor_device *)); \
+ _gpu_write64((iomem), (reg), (data)); })
+
+static inline u64 _gpu_read64(void __iomem *iomem, u32 reg)
{
- return (gpu_read(iomem, reg) | ((u64)gpu_read(iomem, reg + 4) << 32));
+ return (_gpu_read(iomem, reg) | ((u64)_gpu_read(iomem, reg + 4) << 32));
}

-static inline u64 gpu_read64_relaxed(void __iomem *iomem, u32 reg)
+#define gpu_read64(iomem, reg) ({ \
+ static_assert(!__same_type((iomem), struct panthor_device *)); \
+ _gpu_read64((iomem), (reg)); })
+
+static inline u64 _gpu_read64_relaxed(void __iomem *iomem, u32 reg)
{
- return (gpu_read_relaxed(iomem, reg) |
- ((u64)gpu_read_relaxed(iomem, reg + 4) << 32));
+ return (_gpu_read_relaxed(iomem, reg) |
+ ((u64)_gpu_read_relaxed(iomem, reg + 4) << 32));
}

-static inline u64 gpu_read64_counter(void __iomem *iomem, u32 reg)
+#define gpu_read64_relaxed(iomem, reg) ({ \
+ static_assert(!__same_type((iomem), struct panthor_device *)); \
+ _gpu_read64_relaxed((iomem), (reg)); })
+
+static inline u64 _gpu_read64_counter(void __iomem *iomem, u32 reg)
{
u32 lo, hi1, hi2;
do {
- hi1 = gpu_read(iomem, reg + 4);
- lo = gpu_read(iomem, reg);
- hi2 = gpu_read(iomem, reg + 4);
+ hi1 = _gpu_read(iomem, reg + 4);
+ lo = _gpu_read(iomem, reg);
+ hi2 = _gpu_read(iomem, reg + 4);
} while (hi1 != hi2);
return lo | ((u64)hi2 << 32);
}

+#define gpu_read64_counter(iomem, reg) ({ \
+ static_assert(!__same_type((iomem), struct panthor_device *)); \
+ _gpu_read64_counter((iomem), (reg)); })
+
#define gpu_read_poll_timeout(iomem, reg, val, cond, delay_us, timeout_us) \
read_poll_timeout(gpu_read, val, cond, delay_us, timeout_us, false, \
iomem, reg)

---
base-commit: 3c253a3bef01b39d4640cfe3dfd38d8d5557ae0c
change-id: 20260508-panthor-gpu-read-type-7ac3fffd124c

Best regards,
--
Nicolas Frattaroli <nicolas.frattaroli@xxxxxxxxxxxxx>