Linux Framebuffer Layer development
 help / color / mirror / Atom feed
* Re: [RFC PATCH] fbcon: Fix out-of-bounds memory in fbcon_putcs
From: Thomas Zimmermann @ 2026-02-27 15:56 UTC (permalink / raw)
  To: Chen Jun, simona, deller, linux-fbdev, linux-kernel; +Cc: linruifeng4
In-Reply-To: <20260227144358.101173-1-chenjun102@huawei.com>

Hi,

thanks for the patch.

Am 27.02.26 um 15:43 schrieb Chen Jun:
> When a font is set on an invisible console, the screen will not update.
> However, the fontbuffer is not updated to match the new font dimensions.

I looked through vc_resize() but cannot quite find the logic that calls 
fbcon_rotate_font(). Can you please point to correct place?

Best regards
Thomas

>
> This inconsistency leads to out-of-bounds memory access when writing to
> the tty bound to fbcon, as demonstrated by the following KASAN report:
>
> BUG: KASAN: slab-out-of-bounds in fb_pad_aligned_buffer+0xdf/0x140
> Read of size 1 at addr ffff8881195a2280 by task a.out/971
> Call Trace:
>   <TASK>
>   fb_pad_aligned_buffer+0xdf/0x140
>   ud_putcs+0x88a/0xde0
>   fbcon_putcs+0x319/0x430
>   do_update_region+0x23c/0x3b0
>   do_con_write+0x225c/0x67f0
>   con_write+0xe/0x30
>   n_tty_write+0x4b5/0xff0
>   file_tty_write.isra.41+0x46c/0x880
>   vfs_write+0x868/0xd60
>   ksys_write+0xf2/0x1d0
>   do_syscall_64+0xfa/0x570
>
> Fix this by calling fbcon_rotate_font() if vc is invisible in
> fbcon_do_set_font().
>
> Signed-off-by: Chen Jun <chenjun102@huawei.com>
> ---
>   drivers/video/fbdev/core/fbcon.c | 5 +++++
>   1 file changed, 5 insertions(+)
>
> diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
> index 666261ae59d8..d76100188bee 100644
> --- a/drivers/video/fbdev/core/fbcon.c
> +++ b/drivers/video/fbdev/core/fbcon.c
> @@ -2444,6 +2444,11 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h, int charcount,
>   		rows = FBCON_SWAP(par->rotate, info->var.yres, info->var.xres);
>   		cols /= w;
>   		rows /= h;
> +		if (!con_is_visible(vc)) {
> +			ret = fbcon_rotate_font(info, vc);
> +			if (ret)
> +				goto err_out;
> +		}
>   		ret = vc_resize(vc, cols, rows);
>   		if (ret)
>   			goto err_out;

-- 
--
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Frankenstr. 146, 90461 Nürnberg, Germany, www.suse.com
GF: Jochen Jaser, Andrew McDonald, Werner Knoblich, (HRB 36809, AG Nürnberg)



^ permalink raw reply

* Re: [PATCH v11 2/2] rust: clist: Add support to interface with C linked lists
From: Alvin Sun @ 2026-02-27 15:50 UTC (permalink / raw)
  To: Joel Fernandes
  Cc: linux-kernel, Miguel Ojeda, Boqun Feng, Gary Guo, Bjorn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Alex Gaynor, Danilo Krummrich, Dave Airlie, David Airlie,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	Simona Vetter, Daniel Almeida, Koen Koning, Nikola Djukic,
	Alexandre Courbot, Philipp Stanner, Elle Rhumsaa, Jonathan Corbet,
	Alex Deucher, Christian Koenig, Jani Nikula, Joonas Lahtinen,
	Rodrigo Vivi, Tvrtko Ursulin, Huang Rui, Matthew Auld,
	Matthew Brost, Lucas De Marchi, Thomas Hellstrom, Helge Deller,
	John Hubbard, Alistair Popple, Timur Tabi, Edwin Peer,
	Andrea Righi, Andy Ritger, Zhi Wang, Balbir Singh, alexeyi,
	Eliot Courtney, dri-devel, nouveau, rust-for-linux, linux-doc,
	amd-gfx, intel-gfx, intel-xe, linux-fbdev
In-Reply-To: <20260226193442.GA4077409@joelbox2>


On 2/27/26 03:34, Joel Fernandes wrote:
> On Fri, 27 Feb 2026, Alvin Sun wrote:
>> Thanks for the clist abstraction. The Tyr debugfs [1] I'm implementing
>> needs to iterate over a GpuVm's VA list, and I'd like to switch that to
>> a CList-based implementation.
> Thanks for looking into using CList for this!
>
>> Could you make CListHeadIter public and expose a public constructor?
>> Or do you have a better suggestion?
> I think this can be handled without exposing CListHeadIter. See below.
>
>> The VA list mixes two node types in one list — GpuVa (with driver-specific
>> data) and KernelGpuVa — so we have to filter/skip nodes and can't use
>> CList as-is. With a public CListHeadIter and new(), we can implement a
>> custom iterator (like our current GpuVaIter) on top of CListHeadIter and
>> then migrate that code to clist instead of hand-rolled list traversal.
> Looking at the Tyr code, both GpuVa and KernelGpuVa are
> #[repr(transparent)] wrappers over the same C struct (drm_gpuva), linked
> through the same list_head field at the same offset. The "two types" are
> a Rust-level modeling choice for safety, not a structural difference in
> the list — every node in that list is a drm_gpuva.
>
> So CList's typed iteration already works here. You can iterate over all
> nodes using a common Rust wrapper type (like a #[repr(transparent)]
> wrapper over drm_gpuva), and then skip the kernel-reserved node by
> pointer identity — since drm_gpuvm has its kernel_alloc_node as a named
> field, its address is known. Something like:
>
>      // Iterate all nodes as a common base type.
>      let list = clist_create!(unsafe { head, RawGpuVa, drm_gpuva, rb.entry });
>      let kernel_ptr = unsafe { &raw mut (*gpuvm_raw).kernel_alloc_node };
>
>      for va in list.iter() {
>          if va.as_raw() == kernel_ptr {
>              continue;  // skip
>          }
>
>          // Cast to &GpuVa
>          let gpu_va = unsafe { GpuVa::from_raw(va.as_raw()) };
>          ...
>      }
>
> If you need a named iterator type (e.g. for returning from a method),
> you can wrap CListIter in your own GpuVaIter struct that stores the
> kernel node pointer and filters in its Iterator::next() impl. That would
> probably also be cleaner.
That's a good idea! I will try to implement GpuVaIter based on CListIter.

Thanks,
Alvin Sun
>
> OTOH, with CListHeadIter you'd need to do container_of manually on each node,
> which might be more erroneous code, whereas CListIter handles that for you.
> And anyway, the pointer comparison needed to skip the kernel node is the same
> in both approaches.
>
> Would this work for the Tyr debugfs use case?
>
> --
> Joel Fernandes
>

^ permalink raw reply

* Re: [RFC PATCH] fbcon: Fix out-of-bounds memory in fbcon_putcs
From: chenjun (AM) @ 2026-02-27 14:53 UTC (permalink / raw)
  To: simona@ffwll.ch, deller@gmx.de, tzimmermann@suse.de,
	linux-fbdev@vger.kernel.org, linux-kernel@vger.kernel.org
  Cc: linruifeng (A)
In-Reply-To: <20260227144358.101173-1-chenjun102@huawei.com>

在 2026/2/27 22:50, chenjun (AM) 写道:
> When a font is set on an invisible console, the screen will not update.
> However, the fontbuffer is not updated to match the new font dimensions.
> 
> This inconsistency leads to out-of-bounds memory access when writing to
> the tty bound to fbcon, as demonstrated by the following KASAN report:
> 
> BUG: KASAN: slab-out-of-bounds in fb_pad_aligned_buffer+0xdf/0x140
> Read of size 1 at addr ffff8881195a2280 by task a.out/971
> Call Trace:
>   <TASK>
>   fb_pad_aligned_buffer+0xdf/0x140
>   ud_putcs+0x88a/0xde0
>   fbcon_putcs+0x319/0x430
>   do_update_region+0x23c/0x3b0
>   do_con_write+0x225c/0x67f0
>   con_write+0xe/0x30
>   n_tty_write+0x4b5/0xff0
>   file_tty_write.isra.41+0x46c/0x880
>   vfs_write+0x868/0xd60
>   ksys_write+0xf2/0x1d0
>   do_syscall_64+0xfa/0x570
> 
> Fix this by calling fbcon_rotate_font() if vc is invisible in
> fbcon_do_set_font().
> 
> Signed-off-by: Chen Jun <chenjun102@huawei.com>
> ---
>   drivers/video/fbdev/core/fbcon.c | 5 +++++
>   1 file changed, 5 insertions(+)
> 
> diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
> index 666261ae59d8..d76100188bee 100644
> --- a/drivers/video/fbdev/core/fbcon.c
> +++ b/drivers/video/fbdev/core/fbcon.c
> @@ -2444,6 +2444,11 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h, int charcount,
>   		rows = FBCON_SWAP(par->rotate, info->var.yres, info->var.xres);
>   		cols /= w;
>   		rows /= h;
> +		if (!con_is_visible(vc)) {
> +			ret = fbcon_rotate_font(info, vc);
> +			if (ret)
> +				goto err_out;
> +		}
>   		ret = vc_resize(vc, cols, rows);
>   		if (ret)
>   			goto err_out;
> 

There is a poc:
```
#define _GNU_SOURCE

#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdint.h>
#include <sys/ioctl.h>

#include <linux/capability.h>

char my_font_data[512 * 1 * 32 * 32];

struct console_font_op {
         unsigned int op;
         unsigned int flags;
         unsigned int width, height;
         unsigned int charcount;
         unsigned char *data;
};

void execute_one(void)
{
   int tty = open("/dev/tty2", O_APPEND|O_RDWR, 0);
   char buf[100] = {27, '#', '8', 0xa, 0x5, 0x5, 0x5, 0x5};
   struct console_font_op op = {
         .op = 0,
         .width = 32,
         .height = 32,
         .charcount = 512,
         .data = my_font_data,
   };

   ioctl(tty, 0x4B72, &op);
   write(tty, buf, 100);
}
int main(void)
{
   execute_one();
   return 0;
}
```
echo 2 > /sys/class/graphics/fbcon/rotate_all
./poc

^ permalink raw reply

* [RFC PATCH] fbcon: Fix out-of-bounds memory in fbcon_putcs
From: Chen Jun @ 2026-02-27 14:43 UTC (permalink / raw)
  To: simona, deller, tzimmermann, linux-fbdev, linux-kernel
  Cc: chenjun102, linruifeng4

When a font is set on an invisible console, the screen will not update.
However, the fontbuffer is not updated to match the new font dimensions.

This inconsistency leads to out-of-bounds memory access when writing to
the tty bound to fbcon, as demonstrated by the following KASAN report:

BUG: KASAN: slab-out-of-bounds in fb_pad_aligned_buffer+0xdf/0x140
Read of size 1 at addr ffff8881195a2280 by task a.out/971
Call Trace:
 <TASK>
 fb_pad_aligned_buffer+0xdf/0x140
 ud_putcs+0x88a/0xde0
 fbcon_putcs+0x319/0x430
 do_update_region+0x23c/0x3b0
 do_con_write+0x225c/0x67f0
 con_write+0xe/0x30
 n_tty_write+0x4b5/0xff0
 file_tty_write.isra.41+0x46c/0x880
 vfs_write+0x868/0xd60
 ksys_write+0xf2/0x1d0
 do_syscall_64+0xfa/0x570

Fix this by calling fbcon_rotate_font() if vc is invisible in
fbcon_do_set_font().

Signed-off-by: Chen Jun <chenjun102@huawei.com>
---
 drivers/video/fbdev/core/fbcon.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
index 666261ae59d8..d76100188bee 100644
--- a/drivers/video/fbdev/core/fbcon.c
+++ b/drivers/video/fbdev/core/fbcon.c
@@ -2444,6 +2444,11 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h, int charcount,
 		rows = FBCON_SWAP(par->rotate, info->var.yres, info->var.xres);
 		cols /= w;
 		rows /= h;
+		if (!con_is_visible(vc)) {
+			ret = fbcon_rotate_font(info, vc);
+			if (ret)
+				goto err_out;
+		}
 		ret = vc_resize(vc, cols, rows);
 		if (ret)
 			goto err_out;
-- 
2.22.0


^ permalink raw reply related

* Re: [PATCH] fbdev/tdfxfb: Make the VGA register initialisation a bit more obvious
From: Helge Deller @ 2026-02-27 14:27 UTC (permalink / raw)
  To: Daniel Palmer, linux-fbdev; +Cc: dri-devel, linux-kernel
In-Reply-To: <20260227122500.3885069-1-daniel@thingy.jp>

On 2/27/26 13:25, Daniel Palmer wrote:
> For a while I was trying to get this working on m68k, for some reason
> the card doesn't display anything if it's own video BIOS didn't run..
> 
> Anyhow, I spent a long time looking up what each of these offsets
> were to work out what the code is configuring and eventually
> replaced them with the human readable defines in video/vga.h.
> 
> Functionally there is no change but maybe it makes it a bit easier to
> look at for the next person that finds themselves in here.
> 
> Tested on a real voodoo 3 on x86_64.
> 
> Signed-off-by: Daniel Palmer <daniel@thingy.jp>
> ---
>   drivers/video/fbdev/tdfxfb.c | 109 ++++++++++++++++++-----------------
>   1 file changed, 55 insertions(+), 54 deletions(-)

applied to fbdev git tree.

Thanks for the cleanup!
Helge

^ permalink raw reply

* [PATCH] fbdev/tdfxfb: Make the VGA register initialisation a bit more obvious
From: Daniel Palmer @ 2026-02-27 12:25 UTC (permalink / raw)
  To: deller, linux-fbdev; +Cc: dri-devel, linux-kernel, Daniel Palmer

For a while I was trying to get this working on m68k, for some reason
the card doesn't display anything if it's own video BIOS didn't run..

Anyhow, I spent a long time looking up what each of these offsets
were to work out what the code is configuring and eventually
replaced them with the human readable defines in video/vga.h.

Functionally there is no change but maybe it makes it a bit easier to
look at for the next person that finds themselves in here.

Tested on a real voodoo 3 on x86_64.

Signed-off-by: Daniel Palmer <daniel@thingy.jp>
---
 drivers/video/fbdev/tdfxfb.c | 109 ++++++++++++++++++-----------------
 1 file changed, 55 insertions(+), 54 deletions(-)

diff --git a/drivers/video/fbdev/tdfxfb.c b/drivers/video/fbdev/tdfxfb.c
index 51ebe78359ec..7606e024fa3f 100644
--- a/drivers/video/fbdev/tdfxfb.c
+++ b/drivers/video/fbdev/tdfxfb.c
@@ -77,6 +77,7 @@
 #include <asm/io.h>
 
 #include <video/tdfx.h>
+#include <video/vga.h>
 
 #define DPRINTK(a, b...) pr_debug("fb: %s: " a, __func__ , ## b)
 
@@ -591,7 +592,7 @@ static int tdfxfb_set_par(struct fb_info *info)
 		vt = ve + (info->var.upper_margin << 1) - 1;
 		reg.screensize = info->var.xres | (info->var.yres << 13);
 		reg.vidcfg |= VIDCFG_HALF_MODE;
-		reg.crt[0x09] = 0x80;
+		reg.crt[VGA_CRTC_MAX_SCAN] = 0x80;
 	} else {
 		vd = info->var.yres - 1;
 		vs  = vd + info->var.lower_margin;
@@ -609,59 +610,59 @@ static int tdfxfb_set_par(struct fb_info *info)
 			 info->var.xres < 480 ? 0x60 :
 			 info->var.xres < 768 ? 0xe0 : 0x20);
 
-	reg.gra[0x05] = 0x40;
-	reg.gra[0x06] = 0x05;
-	reg.gra[0x07] = 0x0f;
-	reg.gra[0x08] = 0xff;
-
-	reg.att[0x00] = 0x00;
-	reg.att[0x01] = 0x01;
-	reg.att[0x02] = 0x02;
-	reg.att[0x03] = 0x03;
-	reg.att[0x04] = 0x04;
-	reg.att[0x05] = 0x05;
-	reg.att[0x06] = 0x06;
-	reg.att[0x07] = 0x07;
-	reg.att[0x08] = 0x08;
-	reg.att[0x09] = 0x09;
-	reg.att[0x0a] = 0x0a;
-	reg.att[0x0b] = 0x0b;
-	reg.att[0x0c] = 0x0c;
-	reg.att[0x0d] = 0x0d;
-	reg.att[0x0e] = 0x0e;
-	reg.att[0x0f] = 0x0f;
-	reg.att[0x10] = 0x41;
-	reg.att[0x12] = 0x0f;
-
-	reg.seq[0x00] = 0x03;
-	reg.seq[0x01] = 0x01; /* fixme: clkdiv2? */
-	reg.seq[0x02] = 0x0f;
-	reg.seq[0x03] = 0x00;
-	reg.seq[0x04] = 0x0e;
-
-	reg.crt[0x00] = ht - 4;
-	reg.crt[0x01] = hd;
-	reg.crt[0x02] = hbs;
-	reg.crt[0x03] = 0x80 | (hbe & 0x1f);
-	reg.crt[0x04] = hs;
-	reg.crt[0x05] = ((hbe & 0x20) << 2) | (he & 0x1f);
-	reg.crt[0x06] = vt;
-	reg.crt[0x07] = ((vs & 0x200) >> 2) |
-			((vd & 0x200) >> 3) |
-			((vt & 0x200) >> 4) | 0x10 |
-			((vbs & 0x100) >> 5) |
-			((vs & 0x100) >> 6) |
-			((vd & 0x100) >> 7) |
-			((vt & 0x100) >> 8);
-	reg.crt[0x09] |= 0x40 | ((vbs & 0x200) >> 4);
-	reg.crt[0x10] = vs;
-	reg.crt[0x11] = (ve & 0x0f) | 0x20;
-	reg.crt[0x12] = vd;
-	reg.crt[0x13] = wd;
-	reg.crt[0x15] = vbs;
-	reg.crt[0x16] = vbe + 1;
-	reg.crt[0x17] = 0xc3;
-	reg.crt[0x18] = 0xff;
+	reg.gra[VGA_GFX_MODE]         = 0x40;
+	reg.gra[VGA_GFX_MISC]         = 0x05;
+	reg.gra[VGA_GFX_COMPARE_MASK] = 0x0f;
+	reg.gra[VGA_GFX_BIT_MASK]     = 0xff;
+
+	reg.att[VGA_ATC_PALETTE0]     = 0x00;
+	reg.att[VGA_ATC_PALETTE1]     = 0x01;
+	reg.att[VGA_ATC_PALETTE2]     = 0x02;
+	reg.att[VGA_ATC_PALETTE3]     = 0x03;
+	reg.att[VGA_ATC_PALETTE4]     = 0x04;
+	reg.att[VGA_ATC_PALETTE5]     = 0x05;
+	reg.att[VGA_ATC_PALETTE6]     = 0x06;
+	reg.att[VGA_ATC_PALETTE7]     = 0x07;
+	reg.att[VGA_ATC_PALETTE8]     = 0x08;
+	reg.att[VGA_ATC_PALETTE9]     = 0x09;
+	reg.att[VGA_ATC_PALETTEA]     = 0x0a;
+	reg.att[VGA_ATC_PALETTEB]     = 0x0b;
+	reg.att[VGA_ATC_PALETTEC]     = 0x0c;
+	reg.att[VGA_ATC_PALETTED]     = 0x0d;
+	reg.att[VGA_ATC_PALETTEE]     = 0x0e;
+	reg.att[VGA_ATC_PALETTEF]     = 0x0f;
+	reg.att[VGA_ATC_MODE]         = 0x41;
+	reg.att[VGA_ATC_PLANE_ENABLE] = 0x0f;
+
+	reg.seq[VGA_SEQ_RESET]         = 0x03;
+	reg.seq[VGA_SEQ_CLOCK_MODE]    = 0x01; /* fixme: clkdiv2? */
+	reg.seq[VGA_SEQ_PLANE_WRITE]   = 0x0f;
+	reg.seq[VGA_SEQ_CHARACTER_MAP] = 0x00;
+	reg.seq[VGA_SEQ_MEMORY_MODE]   = 0x0e;
+
+	reg.crt[VGA_CRTC_H_TOTAL]       = ht - 4;
+	reg.crt[VGA_CRTC_H_DISP]        = hd;
+	reg.crt[VGA_CRTC_H_BLANK_START] = hbs;
+	reg.crt[VGA_CRTC_H_BLANK_END]   = 0x80 | (hbe & 0x1f);
+	reg.crt[VGA_CRTC_H_SYNC_START]  = hs;
+	reg.crt[VGA_CRTC_H_SYNC_END]    = ((hbe & 0x20) << 2) | (he & 0x1f);
+	reg.crt[VGA_CRTC_V_TOTAL]       = vt;
+	reg.crt[VGA_CRTC_OVERFLOW]      = ((vs & 0x200) >> 2) |
+					  ((vd & 0x200) >> 3) |
+					  ((vt & 0x200) >> 4) | 0x10 |
+					  ((vbs & 0x100) >> 5) |
+					  ((vs & 0x100) >> 6) |
+					  ((vd & 0x100) >> 7) |
+					  ((vt & 0x100) >> 8);
+	reg.crt[VGA_CRTC_MAX_SCAN]     |= 0x40 | ((vbs & 0x200) >> 4);
+	reg.crt[VGA_CRTC_V_SYNC_START]  = vs;
+	reg.crt[VGA_CRTC_V_SYNC_END]    = (ve & 0x0f) | 0x20;
+	reg.crt[VGA_CRTC_V_DISP_END]    = vd;
+	reg.crt[VGA_CRTC_OFFSET]        = wd;
+	reg.crt[VGA_CRTC_V_BLANK_START] = vbs;
+	reg.crt[VGA_CRTC_V_BLANK_END]   = vbe + 1;
+	reg.crt[VGA_CRTC_MODE]          = 0xc3;
+	reg.crt[VGA_CRTC_LINE_COMPARE]  = 0xff;
 
 	/* Banshee's nonvga stuff */
 	reg.ext[0x00] = (((ht & 0x100) >> 8) |
-- 
2.51.0


^ permalink raw reply related

* Re: [PATCH v11 4/4] rust: gpu: Add GPU buddy allocator bindings
From: Danilo Krummrich @ 2026-02-27 12:08 UTC (permalink / raw)
  To: Joel Fernandes
  Cc: linux-kernel, Miguel Ojeda, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
	Trevor Gross, Dave Airlie, Daniel Almeida, Koen Koning, dri-devel,
	nouveau, rust-for-linux, Nikola Djukic, Maarten Lankhorst,
	Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
	Jonathan Corbet, Alex Deucher, Christian König, Jani Nikula,
	Joonas Lahtinen, Rodrigo Vivi, Tvrtko Ursulin, Huang Rui,
	Matthew Auld, Matthew Brost, Lucas De Marchi,
	Thomas Hellström, Helge Deller, Alex Gaynor, Boqun Feng,
	John Hubbard, Alistair Popple, Timur Tabi, Edwin Peer,
	Alexandre Courbot, Andrea Righi, Andy Ritger, Zhi Wang,
	Balbir Singh, Philipp Stanner, Elle Rhumsaa, alexeyi,
	Eliot Courtney, joel, linux-doc, amd-gfx, intel-gfx, intel-xe,
	linux-fbdev
In-Reply-To: <20260224224005.3232841-5-joelagnelf@nvidia.com>

On Tue Feb 24, 2026 at 11:40 PM CET, Joel Fernandes wrote:
> diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
> index 58dbb02c5197..b8287601f464 100644
> --- a/rust/kernel/lib.rs
> +++ b/rust/kernel/lib.rs
> @@ -97,6 +97,8 @@
>  pub mod firmware;
>  pub mod fmt;
>  pub mod fs;
> +#[cfg(CONFIG_GPU_BUDDY)]

Has to be #[cfg(CONFIG_GPU_BUDDY = "y")] for now.

> +pub mod gpu;
>  #[cfg(CONFIG_I2C = "y")]
>  pub mod i2c;
>  pub mod id_pool;
> -- 
> 2.34.1


^ permalink raw reply

* Re: [PATCH v11 4/4] rust: gpu: Add GPU buddy allocator bindings
From: Alexandre Courbot @ 2026-02-27 12:00 UTC (permalink / raw)
  To: Joel Fernandes
  Cc: linux-kernel, Miguel Ojeda, Boqun Feng, Gary Guo, Bjorn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Danilo Krummrich, Dave Airlie, Daniel Almeida, Koen Koning,
	dri-devel, nouveau, rust-for-linux, Nikola Djukic,
	Maarten Lankhorst, Maxime Ripard, Simona Vetter, Jonathan Corbet,
	Alex Deucher, Christian Koenig, Jani Nikula, Joonas Lahtinen,
	Rodrigo Vivi, Tvrtko Ursulin, Huang Rui, Matthew Auld,
	Matthew Brost, Lucas De Marchi, Thomas Hellstrom, Helge Deller,
	Alex Gaynor, Boqun Feng, Alistair Popple, Andrea Righi, Zhi Wang,
	Philipp Stanner, Elle Rhumsaa, alexeyi, Eliot Courtney, linux-doc,
	amd-gfx, intel-gfx, intel-xe, linux-fbdev
In-Reply-To: <3161a017-a9f8-465c-b4dd-fef085d75b98@nvidia.com>

On Fri Feb 27, 2026 at 6:42 AM JST, Joel Fernandes wrote:
<snip>
>> 
>> And the job of `alloc_blocks` is also simplified:
>> 
>>     let (start, end) = match mode {
>>         GpuBuddyAllocMode::Range { start, end } => (start, end),
>>         _ => (0, 0),
>>     };
>>     let flags = mode.into_flags() | u32::from(flags) as usize;
>>     // ... and just invoke the C API with these parameters.
>> 
>>> if the C allocator evolves its flag semantics (new combinations become
>>> valid, or existing constraints change), an enum on the Rust side would
>>> break. It's simpler and more maintainable to pass combinable flags and
>>> let the C allocator validate -- which it already does. The switch to
>>> `impl_flags!` will work for us without over-constraining.
>> 
>> The evolution you describe is speculative and unlikely to happen as it
>> would break all C users just the same. And if the C API adds new flags
>> or allocation modes, we will have to update the Rust abstraction either
>> way.
>
> How/why would it break C users? Currently top down + range is silently ignored,
> implementing it is unlikely to break them.
>
> I also wouldn't call it speculative: top-down within a range is a natural
> feature the C allocator could add right? By modeling modes as a mutually
> exclusive enum, we're disallowing a flag combination that could become
> valid in the future. That's fine for now, but something to keep in mind as we
> choose this design. We could add a new RangeTopDown mode variant in the future,
> though. That said, I've made the switch to the enum as
> you suggested since it is cleaner code! And is more Rust-like as you pointed.

Ah, I thought you were talking about new flags - the case you are
quoting is different, and indeed more concerning. I guess if things were
to change in that direction we would have to move top-down into its own
flag and update our users. But for now we should try to support the
existing actual semantics as closely as possible, and without any
surprise if possible - what you get is exactly what you get, without
anything swept under the rug (the silent masking done on the C side
freaks me out a little bit tbh ^_^;).

Should top-down become a flag, our current API also wouldn't become
incorrect - it would just be incomplete in that it doesn't support the
new use-case until we update it, so thankfully that wouldn't be a
critical issue.

^ permalink raw reply

* Re: [PATCH v11 4/4] rust: gpu: Add GPU buddy allocator bindings
From: Danilo Krummrich @ 2026-02-27 11:30 UTC (permalink / raw)
  To: Joel Fernandes
  Cc: linux-kernel, Miguel Ojeda, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
	Trevor Gross, Dave Airlie, Daniel Almeida, Koen Koning, dri-devel,
	nouveau, rust-for-linux, Nikola Djukic, Maarten Lankhorst,
	Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
	Jonathan Corbet, Alex Deucher, Christian König, Jani Nikula,
	Joonas Lahtinen, Rodrigo Vivi, Tvrtko Ursulin, Huang Rui,
	Matthew Auld, Matthew Brost, Lucas De Marchi,
	Thomas Hellström, Helge Deller, Alex Gaynor, Boqun Feng,
	John Hubbard, Alistair Popple, Timur Tabi, Edwin Peer,
	Alexandre Courbot, Andrea Righi, Andy Ritger, Zhi Wang,
	Balbir Singh, Philipp Stanner, Elle Rhumsaa, alexeyi,
	Eliot Courtney, joel, linux-doc, amd-gfx, intel-gfx, intel-xe,
	linux-fbdev, arunpravin.paneerselvam
In-Reply-To: <20260224224005.3232841-5-joelagnelf@nvidia.com>

(Cc: Arun)

On Tue Feb 24, 2026 at 11:40 PM CET, Joel Fernandes wrote:
> +RUST [GPU BUDDY]
> +M:	Joel Fernandes <joelagnelf@nvidia.com>
> +L:	dri-devel@lists.freedesktop.org
> +L:	rust-for-linux@vger.kernel.org
> +S:	Maintained
> +F:	rust/helpers/gpu.c
> +F:	rust/kernel/gpu/

What about adding this to the existing GPU BUDDY ALLOCATOR entry? Maybe you can
offer Matthew and Arun your help.

Also, this wouldn't be a subentry of "RUST", but the rust version of GPU BUDDY,
so it would be "GPU BUDDY [RUST]".

Also, please add rust/kernel/gpu/ to the "DRM DRIVERS AND COMMON INFRASTRUCTURE
[RUST]" entry.

> +/// Inner structure holding the actual buddy allocator.
> +///
> +/// # Synchronization
> +///
> +/// The C `gpu_buddy` API requires synchronization (see `include/linux/gpu_buddy.h`).
> +/// The internal [`GpuBuddyGuard`] ensures that the lock is held for all
> +/// allocator and free operations, preventing races between concurrent allocations
> +/// and the freeing that occurs when [`AllocatedBlocks`] is dropped.
> +///
> +/// # Invariants
> +///
> +/// The inner [`Opaque`] contains a valid, initialized buddy allocator.

The invariant should be justified in the constructor. Also, where is it used?

> +// SAFETY: GpuBuddyInner is `Sync` because the internal GpuBuddyGuard

I think it's more precise to refer to GpuBuddyInner::lock.

> +// serializes all access to the C allocator, preventing data races.
> +unsafe impl Sync for GpuBuddyInner {}
> +
> +/// Guard that proves the lock is held, enabling access to the allocator.
> +///
> +/// # Invariants
> +///
> +/// The inner `_guard` holds the lock for the duration of this guard's lifetime.
> +pub(crate) struct GpuBuddyGuard<'a> {
> +    inner: &'a GpuBuddyInner,
> +    _guard: MutexGuard<'a, ()>,
> +}
> +
> +impl GpuBuddyGuard<'_> {
> +    /// Get a raw pointer to the underlying C `gpu_buddy` structure.
> +    fn as_raw(&self) -> *mut bindings::gpu_buddy {
> +        self.inner.inner.get()
> +    }
> +}
> +
> +/// GPU buddy allocator instance.
> +///
> +/// This structure wraps the C `gpu_buddy` allocator using reference counting.
> +/// The allocator is automatically cleaned up when all references are dropped.
> +///
> +/// # Invariants
> +///
> +/// The inner [`Arc`] points to a valid, initialized GPU buddy allocator.

Do we need this invariant? Isn't this implied by the GpuBuddyInner type?

> +    /// Iterate over allocated blocks.
> +    ///
> +    /// Returns an iterator yielding [`AllocatedBlock`] values. Each [`AllocatedBlock`]
> +    /// borrows `self` and is only valid for the duration of that borrow.
> +    pub fn iter(&self) -> impl Iterator<Item = AllocatedBlock<'_>> + '_ {
> +        // SAFETY: list contains gpu_buddy_block items linked via __bindgen_anon_1.link.
> +        let clist = clist_create!(unsafe {

This macro has three separate safety requirements, please justify all of them.
Also, please also use markdown in safety comments. Personally, I don't care too
much, but it would be good to keep things consistent.

> +            self.list.as_raw(),
> +            Block,
> +            bindings::gpu_buddy_block,
> +            __bindgen_anon_1.link
> +        });
> +
> +        clist
> +            .iter()
> +            .map(|block| AllocatedBlock { block, alloc: self })
> +    }
> +}
> +
> +#[pinned_drop]
> +impl PinnedDrop for AllocatedBlocks {
> +    fn drop(self: Pin<&mut Self>) {
> +        let guard = self.buddy.lock();
> +
> +        // SAFETY:
> +        // - list is valid per the type's invariants.
> +        // - guard provides exclusive access to the allocator.
> +        // CAST: BuddyFlags were validated to fit in u32 at construction.
> +        unsafe {
> +            bindings::gpu_buddy_free_list(
> +                guard.as_raw(),
> +                self.list.as_raw(),
> +                self.flags.as_raw() as u32,
> +            );
> +        }
> +    }
> +}
> +
> +/// A GPU buddy block.
> +///
> +/// Transparent wrapper over C `gpu_buddy_block` structure. This type is returned
> +/// as references during iteration over [`AllocatedBlocks`].
> +///
> +/// # Invariants
> +///
> +/// The inner [`Opaque`] contains a valid, allocated `gpu_buddy_block`.
> +#[repr(transparent)]
> +pub struct Block(Opaque<bindings::gpu_buddy_block>);

Does this need to be public? I don't see it being exposed by any API.

> +
> +impl Block {
> +    /// Get a raw pointer to the underlying C block.
> +    fn as_raw(&self) -> *mut bindings::gpu_buddy_block {
> +        self.0.get()
> +    }
> +
> +    /// Get the block's offset in the address space.
> +    pub(crate) fn offset(&self) -> u64 {
> +        // SAFETY: self.as_raw() is valid per the type's invariants.
> +        unsafe { bindings::gpu_buddy_block_offset(self.as_raw()) }
> +    }
> +
> +    /// Get the block order.
> +    pub(crate) fn order(&self) -> u32 {
> +        // SAFETY: self.as_raw() is valid per the type's invariants.
> +        unsafe { bindings::gpu_buddy_block_order(self.as_raw()) }
> +    }
> +}
> +
> +// SAFETY: `Block` is not modified after allocation for the lifetime
> +// of `AllocatedBlock`.
> +unsafe impl Send for Block {}
> +
> +// SAFETY: `Block` is not modified after allocation for the lifetime
> +// of `AllocatedBlock`.
> +unsafe impl Sync for Block {}
> +
> +/// An allocated block with access to the GPU buddy allocator.

This needs a better description, i.e. what makes an `AllocatedBlock different
compared to a "normal" Block.

> +///
> +/// It is returned by [`AllocatedBlocks::iter()`] and provides access to the
> +/// GPU buddy allocator required for some accessors.
> +///
> +/// # Invariants
> +///
> +/// - `block` is a valid reference to an allocated [`Block`].
> +/// - `alloc` is a valid reference to the [`AllocatedBlocks`] that owns this block.

References should always be valid, no need to mention that.

> +pub struct AllocatedBlock<'a> {
> +    block: &'a Block,

NIT: What about just naming it "this" and

> +    alloc: &'a AllocatedBlocks,

"blocks"?

> +}
> +
> +impl AllocatedBlock<'_> {
> +    /// Get the block's offset in the address space.
> +    ///
> +    /// Returns the absolute offset including the allocator's base offset.
> +    /// This is the actual address to use for accessing the allocated memory.
> +    pub fn offset(&self) -> u64 {
> +        self.alloc.buddy.base_offset + self.block.offset()
> +    }
> +
> +    /// Get the block order (size = chunk_size << order).
> +    pub fn order(&self) -> u32 {
> +        self.block.order()
> +    }
> +
> +    /// Get the block's size in bytes.
> +    pub fn size(&self) -> u64 {
> +        self.alloc.buddy.chunk_size << self.block.order()
> +    }
> +}

^ permalink raw reply

* Re: [PATCH] staging: fbtft: fix macro whitespace errors
From: Dhyan K Prajapati @ 2026-02-27  4:51 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Andy Shevchenko, Greg Kroah-Hartman, Jason Donenfeld, dri-devel,
	linux-fbdev, linux-staging, linux-kernel
In-Reply-To: <aaCIqUXPB75vR6rK@smile.fi.intel.com>

On Thu, Feb 26, 2026 at 07:53:45PM +0200, Andy Shevchenko wrote:
>On Thu, Feb 26, 2026 at 10:55:31PM +0530, dhyan19022009@gmail.com wrote:
>>
>> Remove prohibited spaces before closing parentheses in macro calls in
>> fbtft-bus.c, reported by checkpatch.pl
>
>You haven't compiled this, have you?
>
>
>-- 
>With Best Regards,
>Andy Shevchenko
>
>

Hey, sorry I atleast should've checked the definition, i'll keep in mind
not to trust checkpatch.pl blindly

^ permalink raw reply

* Re: [PATCH] staging: fbtft: fix macro whitespace errors
From: kernel test robot @ 2026-02-26 23:35 UTC (permalink / raw)
  To: dhyan19022009, Andy Shevchenko, Greg Kroah-Hartman
  Cc: llvm, oe-kbuild-all, Jason Donenfeld, dri-devel, linux-fbdev,
	linux-staging, linux-kernel, Dhyan K Prajapati
In-Reply-To: <20260226172531.13714-1-dhyan19022009@gmail.com>

Hi,

kernel test robot noticed the following build errors:

[auto build test ERROR on staging/staging-testing]

url:    https://github.com/intel-lab-lkp/linux/commits/dhyan19022009-gmail-com/staging-fbtft-fix-macro-whitespace-errors/20260227-021646
base:   staging/staging-testing
patch link:    https://lore.kernel.org/r/20260226172531.13714-1-dhyan19022009%40gmail.com
patch subject: [PATCH] staging: fbtft: fix macro whitespace errors
config: hexagon-allmodconfig (https://download.01.org/0day-ci/archive/20260227/202602270720.2J4j3gHF-lkp@intel.com/config)
compiler: clang version 17.0.6 (https://github.com/llvm/llvm-project 6009708b4367171ccdbf4b5905cb6a803753fe18)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260227/202602270720.2J4j3gHF-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202602270720.2J4j3gHF-lkp@intel.com/

All errors (new ones prefixed by >>):

>> drivers/staging/fbtft/fbtft-bus.c:65:53: error: too few arguments provided to function-like macro invocation
      65 | define_fbtft_write_reg(fbtft_write_reg8_bus8, u8, u8)
         |                                                     ^
   drivers/staging/fbtft/fbtft-bus.c:14:9: note: macro 'define_fbtft_write_reg' defined here
      14 | #define define_fbtft_write_reg(func, buffer_type, data_type, modifier)        \
         |         ^
>> drivers/staging/fbtft/fbtft-bus.c:65:1: error: unknown type name 'define_fbtft_write_reg'
      65 | define_fbtft_write_reg(fbtft_write_reg8_bus8, u8, u8)
         | ^
   drivers/staging/fbtft/fbtft-bus.c:67:57: error: too few arguments provided to function-like macro invocation
      67 | define_fbtft_write_reg(fbtft_write_reg16_bus16, u16, u16)
         |                                                         ^
   drivers/staging/fbtft/fbtft-bus.c:14:9: note: macro 'define_fbtft_write_reg' defined here
      14 | #define define_fbtft_write_reg(func, buffer_type, data_type, modifier)        \
         |         ^
   drivers/staging/fbtft/fbtft-bus.c:67:1: error: unknown type name 'define_fbtft_write_reg'
      67 | define_fbtft_write_reg(fbtft_write_reg16_bus16, u16, u16)
         | ^
   4 errors generated.


vim +65 drivers/staging/fbtft/fbtft-bus.c

    64	
  > 65	define_fbtft_write_reg(fbtft_write_reg8_bus8, u8, u8)
    66	define_fbtft_write_reg(fbtft_write_reg16_bus8, __be16, u16, cpu_to_be16)
    67	define_fbtft_write_reg(fbtft_write_reg16_bus16, u16, u16)
    68	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply

* Re: [PATCH v11 4/4] rust: gpu: Add GPU buddy allocator bindings
From: Joel Fernandes @ 2026-02-26 21:42 UTC (permalink / raw)
  To: Alexandre Courbot
  Cc: linux-kernel, Miguel Ojeda, Boqun Feng, Gary Guo, Bjorn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Danilo Krummrich, Dave Airlie, Daniel Almeida, Koen Koning,
	dri-devel, nouveau, rust-for-linux, Nikola Djukic,
	Maarten Lankhorst, Maxime Ripard, Simona Vetter, Jonathan Corbet,
	Alex Deucher, Christian Koenig, Jani Nikula, Joonas Lahtinen,
	Rodrigo Vivi, Tvrtko Ursulin, Huang Rui, Matthew Auld,
	Matthew Brost, Lucas De Marchi, Thomas Hellstrom, Helge Deller,
	Alex Gaynor, Boqun Feng, Alistair Popple, Andrea Righi, Zhi Wang,
	Philipp Stanner, Elle Rhumsaa, alexeyi, Eliot Courtney, linux-doc,
	amd-gfx, intel-gfx, intel-xe, linux-fbdev
In-Reply-To: <DGOJDXWDOJD0.2J6NENL44SQJJ@nvidia.com>



On 2/25/2026 9:26 PM, Alexandre Courbot wrote:
> On Thu Feb 26, 2026 at 5:41 AM JST, Joel Fernandes wrote:
>>> This structure doesn't seem to be useful. I would understand using one
>>> if `GpuBuddyParams` had lots of members, some of which have a sensible
>>> default value - then we could implement `Default` and let users fill in
>>> the parameters they need.
>>>
>>> But this structure has no constructor of any sort, requiring users to
>>> fill its 3 members manually - which is actually heavier than having 3
>>> parameters to `GpuBuddy::new`. It is even deconstructed in
>>> `GpuBuddyInner` to store its members as 3 different fields! So let's
>>> skip it.
>>
>> I'd prefer to keep the struct -- all three parameters are `u64`, so
>> positional arguments would be easy to silently misorder. The struct
>> also makes call sites more readable since Rust has no named function call
>> parameters.
> 
> Fair point about the 3 parameters being easily confused. If you keep it,
> can you also store it in `GpuBuddyInner` instead of deconstructing it
> into 3 members?

Done, good idea.

> 
>>
>>>> +pub struct GpuBuddyAllocParams {
>>>
>>> This one also feels like it could be rustified some more.
>>>
>>> By this I mean that it e.g. allows the user to specify a range even if
>>> `RANGE_ALLOCATION` is not set. A C API rejects invalid combinations at
>>> runtime. A Rust API should make it impossible to even express them.
>>>
>>> [...]
>>>
>>> That would turn `alloc_blocks` into something like:
>>>
>>>   `fn alloc_blocks(&self, alloc: AllocType, size: u64, min_block_size: Alignment, flags: AllocBlocksFlags)`
>>
>> The C API supports combining allocation modes with modifiers (e.g.
>> RANGE+CLEAR, TOPDOWN+CLEAR), so modeling the mode as a
>> mutually-exclusive enum would lose valid combinations. More importantly,
> 
> What I suggested does allow you to combine allocation modes with
> modifiers. I should have pasted a bit of code for clarity, so here goes:
> 
>     #[derive(Copy, Clone, Debug, PartialEq, Eq)]
>     pub enum GpuBuddyAllocMode {
>         Simple,
>         Range { start: u64, end: u64 },
>         TopDown,
>     }
> 
>     impl GpuBuddyAllocMode {
>         // Returns the flag corresponding to the allocation mode.
>         //
>         // Intentionally private - for internal use.
>         fn into_flags(self) -> usize {
>             match self {
>                 Self::Simple => 0,
>                 Self::Range { .. } => bindings::GPU_BUDDY_RANGE_ALLOCATION,
>                 Self::TopDown => bindings::GPU_BUDDY_TOPDOWN_ALLOCATION,
>             }
>         }
>     }

I took this bit from  yours(more comments below).
> 
>     impl_flags!(
>         #[derive(Copy, Clone, PartialEq, Eq, Default)]
>         pub struct GpuBuddyAllocFlags(u32);
> 
>         #[derive(Copy, Clone, PartialEq, Eq)]
>         pub enum GpuBuddyAllocFlag {
>             Contiguous = bindings::GPU_BUDDY_CONTIGUOUS_ALLOCATION as u32,
>             Clear = bindings::GPU_BUDDY_CLEAR_ALLOCATION as u32,
>             TrimDisable = bindings::GPU_BUDDY_TRIM_DISABLE as u32,
>         }
>     );
> 
>     pub struct GpuBuddyAllocParams {
>         mode: GpuBuddyAllocMode,
>         size: u64,
>         min_block_size: u64,
>         flags: GpuBuddyAllocFlags,
>     }
> 
I took this bit from  yours(more comments below).

> Now instead of doing something like:
> 
>     let params = GpuBuddyAllocParams {
>         start_range_address: 0,
>         end_range_address: 0,
>         size: SZ_16M as u64,
>         min_block_size: SZ_16M as u64,
>         buddy_flags: BuddyFlag::TopdownAllocation.into(),
>     };
> 
> You would have:
> 
>     let params = GpuBuddyAllocParams {
>         // No unneeded `start_range` and `end_range`!
>         mode: GpuBuddyAllocMode::TopDown,
>         size: SZ_16M as u64,
>         min_block_size: SZ_16M as u64,
>         flags: Default::default(),
>     };
> 
I took this bit from  yours(more comments below).

> And for a cleared range allocation:
> 
>     let params = GpuBuddyAllocParams {
>         mode: GpuBuddyAllocMode::Range {
>             start: 0,
>             end: SZ_16M as u64,
>         },
>         size: SZ_16M as u64,
>         min_block_size: SZ_16M as u64,
>         flags: GpuBuddyAllocFlag::Clear,
>     };
> 
> Actually the parameters are now distinct enough that you don't need a
> type to prevent confusion. A block allocation now just reads like a nice
> sentence:
> 
>     buddy.alloc_blocks(
>         GpuBuddyAllocMode::Range {
>             start: 0,
>             end: SZ_16M,
>         },
>         SZ_16M,
>         // `min_block_size` should be an `Alignment`, the C API even
>         // returns an error if it is not a power of 2.
>         Alignment::new::<SZ_16M>(),
>         GpuBuddyAllocFlag::Clear,
>     )?;

Makes sense, this is indeed better, I'll do it this way.

> 
> And the job of `alloc_blocks` is also simplified:
> 
>     let (start, end) = match mode {
>         GpuBuddyAllocMode::Range { start, end } => (start, end),
>         _ => (0, 0),
>     };
>     let flags = mode.into_flags() | u32::from(flags) as usize;
>     // ... and just invoke the C API with these parameters.
> 
>> if the C allocator evolves its flag semantics (new combinations become
>> valid, or existing constraints change), an enum on the Rust side would
>> break. It's simpler and more maintainable to pass combinable flags and
>> let the C allocator validate -- which it already does. The switch to
>> `impl_flags!` will work for us without over-constraining.
> 
> The evolution you describe is speculative and unlikely to happen as it
> would break all C users just the same. And if the C API adds new flags
> or allocation modes, we will have to update the Rust abstraction either
> way.

How/why would it break C users? Currently top down + range is silently ignored,
implementing it is unlikely to break them.

I also wouldn't call it speculative: top-down within a range is a natural
feature the C allocator could add right? By modeling modes as a mutually
exclusive enum, we're disallowing a flag combination that could become
valid in the future. That's fine for now, but something to keep in mind as we
choose this design. We could add a new RangeTopDown mode variant in the future,
though. That said, I've made the switch to the enum as
you suggested since it is cleaner code! And is more Rust-like as you pointed.

> 
> Rust abstractions should model the C API correctly. By hardening the way
> the C API can be used and stripping out invalid uses, we save headaches
> to users of the API who don't need to worry about whether the flag they
> pass will result in an error or simply be ignored, and we also save
> maintainer time who don't have to explain the intricacies of their APIs
> to confused users. :)
> 

Sure, no argument on that one. ;-)

[...]
>>>> +    base_offset: u64,
>>>
>>> This does not appear to be used in the C API - does it belong here? It
>>> looks like an additional convenience, but I'm not convinced that's the
>>> role of this type to provide this. But if it really is needed by all
>>> users (guess I'll find out after looking the Nova code :)), then keeping
>>> it is fair I guess.
>>
>> Yes, `base_offset` is needed by nova-core. The GPU's usable VRAM
>> starts at `usable_vram_start` from the GSP firmware parameters:
>>
>>     GpuBuddyParams {
>>         base_offset: params.usable_vram_start,
>>         physical_memory_size: params.usable_vram_size,
>>         chunk_size: SZ_4K.into_safe_cast(),
>>     }
>>
>> `AllocatedBlock::offset()` then adds `base_offset` to return absolute
>> VRAM addresses, so callers don't need to track the offset themselves.
> 
> Sounds fair, I'll check how this is used in Nova.
> 
> Ah, another thing I've noticed while writing the example above:
> 
>> +#[pinned_drop]
>> +impl PinnedDrop for AllocatedBlocks {
>> +    fn drop(self: Pin<&mut Self>) {
>> +        let guard = self.buddy.lock();
>> +
>> +        // SAFETY:
>> +        // - list is valid per the type's invariants.
>> +        // - guard provides exclusive access to the allocator.
>> +        // CAST: BuddyFlags were validated to fit in u32 at construction.
>> +        unsafe {
>> +            bindings::gpu_buddy_free_list(
>> +                guard.as_raw(),
>> +                self.list.as_raw(),
>> +                self.flags.as_raw() as u32,
> 
> `gpu_buddy_free_list` only expects the `CLEARED` flag - actually it
> silently masks other flags. So you probably want to just pass `0` here -
> adding a `Cleared` field to `GpuBuddyAllocFlag` would also do the trick,
> but it looks risky to me as it relies on the promise that the user has
> cleared the buffer, which is not something we can guarantee. So I don't
> think we can support this safely.
> 
> If you just pass `0`, then the `flags` member of `AllocatedBlocks`
> becomes unused and you can just drop it.

Good catch, done!

> 
> And another small one - some methods of `Block` are `pub(crate)` - I
> believe they should either be `pub` or kept private.

Changed to pub. thanks,

-- 
Joel Fernandes


^ permalink raw reply

* Re: [PATCH] staging: fbtft: fix macro whitespace errors
From: kernel test robot @ 2026-02-26 21:36 UTC (permalink / raw)
  To: dhyan19022009, Andy Shevchenko, Greg Kroah-Hartman
  Cc: oe-kbuild-all, Jason Donenfeld, dri-devel, linux-fbdev,
	linux-staging, linux-kernel, Dhyan K Prajapati
In-Reply-To: <20260226172531.13714-1-dhyan19022009@gmail.com>

Hi,

kernel test robot noticed the following build errors:

[auto build test ERROR on staging/staging-testing]

url:    https://github.com/intel-lab-lkp/linux/commits/dhyan19022009-gmail-com/staging-fbtft-fix-macro-whitespace-errors/20260227-021646
base:   staging/staging-testing
patch link:    https://lore.kernel.org/r/20260226172531.13714-1-dhyan19022009%40gmail.com
patch subject: [PATCH] staging: fbtft: fix macro whitespace errors
config: parisc-randconfig-001-20260227 (https://download.01.org/0day-ci/archive/20260227/202602270527.UlXqo4xH-lkp@intel.com/config)
compiler: hppa-linux-gcc (GCC) 8.5.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260227/202602270527.UlXqo4xH-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202602270527.UlXqo4xH-lkp@intel.com/

All errors (new ones prefixed by >>):

>> drivers/staging/fbtft/fbtft-bus.c:65:53: error: macro "define_fbtft_write_reg" requires 4 arguments, but only 3 given
    define_fbtft_write_reg(fbtft_write_reg8_bus8, u8, u8)
                                                        ^
>> drivers/staging/fbtft/fbtft-bus.c:65:23: error: expected ';' before 'void'
    define_fbtft_write_reg(fbtft_write_reg8_bus8, u8, u8)
                          ^
                          ;
   drivers/staging/fbtft/fbtft-bus.c:67:57: error: macro "define_fbtft_write_reg" requires 4 arguments, but only 3 given
    define_fbtft_write_reg(fbtft_write_reg16_bus16, u16, u16)
                                                            ^
   drivers/staging/fbtft/fbtft-bus.c:67:23: error: expected ';' before 'void'
    define_fbtft_write_reg(fbtft_write_reg16_bus16, u16, u16)
                          ^
                          ;
   drivers/staging/fbtft/fbtft-bus.c:69:1:
    void fbtft_write_reg8_bus9(struct fbtft_par *par, int len, ...)
    ~~~~                   


vim +/define_fbtft_write_reg +65 drivers/staging/fbtft/fbtft-bus.c

    64	
  > 65	define_fbtft_write_reg(fbtft_write_reg8_bus8, u8, u8)
    66	define_fbtft_write_reg(fbtft_write_reg16_bus8, __be16, u16, cpu_to_be16)
    67	define_fbtft_write_reg(fbtft_write_reg16_bus16, u16, u16)
    68	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply

* Re: [PATCH v11 2/2] rust: clist: Add support to interface with C linked lists
From: Joel Fernandes @ 2026-02-26 19:34 UTC (permalink / raw)
  To: Alvin Sun
  Cc: linux-kernel, Miguel Ojeda, Boqun Feng, Gary Guo, Bjorn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Alex Gaynor, Danilo Krummrich, Dave Airlie, David Airlie,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	Simona Vetter, Daniel Almeida, Koen Koning, Nikola Djukic,
	Alexandre Courbot, Philipp Stanner, Elle Rhumsaa, Jonathan Corbet,
	Alex Deucher, Christian Koenig, Jani Nikula, Joonas Lahtinen,
	Rodrigo Vivi, Tvrtko Ursulin, Huang Rui, Matthew Auld,
	Matthew Brost, Lucas De Marchi, Thomas Hellstrom, Helge Deller,
	John Hubbard, Alistair Popple, Timur Tabi, Edwin Peer,
	Andrea Righi, Andy Ritger, Zhi Wang, Balbir Singh, alexeyi,
	Eliot Courtney, dri-devel, nouveau, rust-for-linux, linux-doc,
	amd-gfx, intel-gfx, intel-xe, linux-fbdev
In-Reply-To: <dbbb1a93-93fc-4ea6-bd6f-6f7fbfcc4710@linux.dev>

On Fri, 27 Feb 2026, Alvin Sun wrote:
> Thanks for the clist abstraction. The Tyr debugfs [1] I'm implementing
> needs to iterate over a GpuVm's VA list, and I'd like to switch that to
> a CList-based implementation.

Thanks for looking into using CList for this!

> Could you make CListHeadIter public and expose a public constructor?
> Or do you have a better suggestion?

I think this can be handled without exposing CListHeadIter. See below.

> The VA list mixes two node types in one list — GpuVa (with driver-specific
> data) and KernelGpuVa — so we have to filter/skip nodes and can't use
> CList as-is. With a public CListHeadIter and new(), we can implement a
> custom iterator (like our current GpuVaIter) on top of CListHeadIter and
> then migrate that code to clist instead of hand-rolled list traversal.

Looking at the Tyr code, both GpuVa and KernelGpuVa are
#[repr(transparent)] wrappers over the same C struct (drm_gpuva), linked
through the same list_head field at the same offset. The "two types" are
a Rust-level modeling choice for safety, not a structural difference in
the list — every node in that list is a drm_gpuva.

So CList's typed iteration already works here. You can iterate over all
nodes using a common Rust wrapper type (like a #[repr(transparent)]
wrapper over drm_gpuva), and then skip the kernel-reserved node by
pointer identity — since drm_gpuvm has its kernel_alloc_node as a named
field, its address is known. Something like:

    // Iterate all nodes as a common base type.
    let list = clist_create!(unsafe { head, RawGpuVa, drm_gpuva, rb.entry });
    let kernel_ptr = unsafe { &raw mut (*gpuvm_raw).kernel_alloc_node };

    for va in list.iter() {
        if va.as_raw() == kernel_ptr {
            continue;  // skip
        }

        // Cast to &GpuVa
        let gpu_va = unsafe { GpuVa::from_raw(va.as_raw()) };
        ...
    }

If you need a named iterator type (e.g. for returning from a method),
you can wrap CListIter in your own GpuVaIter struct that stores the
kernel node pointer and filters in its Iterator::next() impl. That would
probably also be cleaner.

OTOH, with CListHeadIter you'd need to do container_of manually on each node,
which might be more erroneous code, whereas CListIter handles that for you.
And anyway, the pointer comparison needed to skip the kernel node is the same
in both approaches.

Would this work for the Tyr debugfs use case?

--
Joel Fernandes


^ permalink raw reply

* Re: [PATCH] staging: fbtft: fix macro whitespace errors
From: Andy Shevchenko @ 2026-02-26 17:53 UTC (permalink / raw)
  To: dhyan19022009
  Cc: Andy Shevchenko, Greg Kroah-Hartman, Jason Donenfeld, dri-devel,
	linux-fbdev, linux-staging, linux-kernel
In-Reply-To: <20260226172531.13714-1-dhyan19022009@gmail.com>

On Thu, Feb 26, 2026 at 10:55:31PM +0530, dhyan19022009@gmail.com wrote:
> 
> Remove prohibited spaces before closing parentheses in macro calls in
> fbtft-bus.c, reported by checkpatch.pl

You haven't compiled this, have you?


-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply

* [PATCH] staging: fbtft: fix macro whitespace errors
From: dhyan19022009 @ 2026-02-26 17:25 UTC (permalink / raw)
  To: Andy Shevchenko, Greg Kroah-Hartman
  Cc: Jason Donenfeld, dri-devel, linux-fbdev, linux-staging,
	linux-kernel, Dhyan K Prajapati

From: Dhyan K Prajapati <dhyan19022009@gmail.com>

Remove prohibited spaces before closing parentheses in macro calls in
fbtft-bus.c, reported by checkpatch.pl

Signed-off-by: Dhyan K Prajapati <dhyan19022009@gmail.com>
---
 drivers/staging/fbtft/fbtft-bus.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/staging/fbtft/fbtft-bus.c b/drivers/staging/fbtft/fbtft-bus.c
index 30e436ff1..409770891 100644
--- a/drivers/staging/fbtft/fbtft-bus.c
+++ b/drivers/staging/fbtft/fbtft-bus.c
@@ -62,9 +62,9 @@ out:									      \
 }                                                                             \
 EXPORT_SYMBOL(func);
 
-define_fbtft_write_reg(fbtft_write_reg8_bus8, u8, u8, )
+define_fbtft_write_reg(fbtft_write_reg8_bus8, u8, u8)
 define_fbtft_write_reg(fbtft_write_reg16_bus8, __be16, u16, cpu_to_be16)
-define_fbtft_write_reg(fbtft_write_reg16_bus16, u16, u16, )
+define_fbtft_write_reg(fbtft_write_reg16_bus16, u16, u16)
 
 void fbtft_write_reg8_bus9(struct fbtft_par *par, int len, ...)
 {
-- 
2.53.0


^ permalink raw reply related

* Re: [PATCH v11 2/2] rust: clist: Add support to interface with C linked lists
From: Alvin Sun @ 2026-02-26 16:23 UTC (permalink / raw)
  To: Joel Fernandes, linux-kernel
  Cc: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Alex Gaynor, Danilo Krummrich, Dave Airlie, David Airlie,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	Simona Vetter, Daniel Almeida, Koen Koning, Nikola Djukic,
	Alexandre Courbot, Philipp Stanner, Elle Rhumsaa, Jonathan Corbet,
	Alex Deucher, Christian König, Jani Nikula, Joonas Lahtinen,
	Rodrigo Vivi, Tvrtko Ursulin, Huang Rui, Matthew Auld,
	Matthew Brost, Lucas De Marchi, Thomas Hellström,
	Helge Deller, John Hubbard, Alistair Popple, Timur Tabi,
	Edwin Peer, Andrea Righi, Andy Ritger, Zhi Wang, Balbir Singh,
	alexeyi, Eliot Courtney, dri-devel, nouveau, rust-for-linux,
	linux-doc, amd-gfx, intel-gfx, intel-xe, linux-fbdev
In-Reply-To: <20260224222734.3153931-3-joelagnelf@nvidia.com>


On 2/25/26 06:27, Joel Fernandes wrote:
> Add a new module `clist` for working with C's doubly circular linked
> lists. Provide low-level iteration over list nodes.
>
> Typed iteration over actual items is provided with a `clist_create`
> macro to assist in creation of the `CList` type.
>
> Cc: Nikola Djukic <ndjukic@nvidia.com>
> Reviewed-by: Daniel Almeida <daniel.almeida@collabora.com>
> Acked-by: Gary Guo <gary@garyguo.net>
> Signed-off-by: Joel Fernandes <joelagnelf@nvidia.com>
> ---
>   MAINTAINERS              |   8 +
>   rust/helpers/helpers.c   |   1 +
>   rust/helpers/list.c      |  17 ++
>   rust/kernel/ffi/clist.rs | 338 +++++++++++++++++++++++++++++++++++++++
>   rust/kernel/ffi/mod.rs   |   2 +
>   rust/kernel/lib.rs       |   1 +
>   6 files changed, 367 insertions(+)
>   create mode 100644 rust/helpers/list.c
>   create mode 100644 rust/kernel/ffi/clist.rs
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index dc82a6bd1a61..0dc318c94c99 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -23181,6 +23181,14 @@ T:	git https://github.com/Rust-for-Linux/linux.git alloc-next
>   F:	rust/kernel/alloc.rs
>   F:	rust/kernel/alloc/
>   
> +RUST [FFI HELPER]
> +M:	Joel Fernandes <joelagnelf@nvidia.com> (CLIST)
> +M:	Alexandre Courbot <acourbot@nvidia.com> (CLIST)
> +L:	rust-for-linux@vger.kernel.org
> +S:	Maintained
> +T:	git https://github.com/Rust-for-Linux/linux.git ffi-next
> +F:	rust/kernel/ffi/
> +
>   RUST [NUM]
>   M:	Alexandre Courbot <acourbot@nvidia.com>
>   R:	Yury Norov <yury.norov@gmail.com>
> diff --git a/rust/helpers/helpers.c b/rust/helpers/helpers.c
> index a3c42e51f00a..724fcb8240ac 100644
> --- a/rust/helpers/helpers.c
> +++ b/rust/helpers/helpers.c
> @@ -35,6 +35,7 @@
>   #include "io.c"
>   #include "jump_label.c"
>   #include "kunit.c"
> +#include "list.c"
>   #include "maple_tree.c"
>   #include "mm.c"
>   #include "mutex.c"
> diff --git a/rust/helpers/list.c b/rust/helpers/list.c
> new file mode 100644
> index 000000000000..18095a5593c5
> --- /dev/null
> +++ b/rust/helpers/list.c
> @@ -0,0 +1,17 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +/*
> + * Helpers for C circular doubly linked list implementation.
> + */
> +
> +#include <linux/list.h>
> +
> +__rust_helper void rust_helper_INIT_LIST_HEAD(struct list_head *list)
> +{
> +	INIT_LIST_HEAD(list);
> +}
> +
> +__rust_helper void rust_helper_list_add_tail(struct list_head *new, struct list_head *head)
> +{
> +	list_add_tail(new, head);
> +}
> diff --git a/rust/kernel/ffi/clist.rs b/rust/kernel/ffi/clist.rs
> new file mode 100644
> index 000000000000..a645358eee58
> --- /dev/null
> +++ b/rust/kernel/ffi/clist.rs
> @@ -0,0 +1,338 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +//! FFI interface for C doubly circular intrusive linked lists.
> +//!
> +//! This module provides Rust abstractions for iterating over C `list_head`-based
> +//! linked lists. It should only be used for cases where C and Rust code share
> +//! direct access to the same linked list through an FFI interface.
> +//!
> +//! Note: This *must not* be used by Rust components that just need a linked list
> +//! primitive. Use [`kernel::list::List`] instead.
> +//!
> +//! # Examples
> +//!
> +//! ```
> +//! use kernel::{
> +//!     bindings,
> +//!     clist_create,
> +//!     types::Opaque,
> +//! };
> +//! # // Create test list with values (0, 10, 20) - normally done by C code but it is
> +//! # // emulated here for doctests using the C bindings.
> +//! # use core::mem::MaybeUninit;
> +//! #
> +//! # /// C struct with embedded `list_head` (typically will be allocated by C code).
> +//! # #[repr(C)]
> +//! # pub struct SampleItemC {
> +//! #     pub value: i32,
> +//! #     pub link: bindings::list_head,
> +//! # }
> +//! #
> +//! # let mut head = MaybeUninit::<bindings::list_head>::uninit();
> +//! #
> +//! # let head = head.as_mut_ptr();
> +//! # // SAFETY: head and all the items are test objects allocated in this scope.
> +//! # unsafe { bindings::INIT_LIST_HEAD(head) };
> +//! #
> +//! # let mut items = [
> +//! #     MaybeUninit::<SampleItemC>::uninit(),
> +//! #     MaybeUninit::<SampleItemC>::uninit(),
> +//! #     MaybeUninit::<SampleItemC>::uninit(),
> +//! # ];
> +//! #
> +//! # for (i, item) in items.iter_mut().enumerate() {
> +//! #     let ptr = item.as_mut_ptr();
> +//! #     // SAFETY: `ptr` points to a valid `MaybeUninit<SampleItemC>`.
> +//! #     unsafe { (*ptr).value = i as i32 * 10 };
> +//! #     // SAFETY: `&raw mut` creates a pointer valid for `INIT_LIST_HEAD`.
> +//! #     unsafe { bindings::INIT_LIST_HEAD(&raw mut (*ptr).link) };
> +//! #     // SAFETY: `link` was just initialized and `head` is a valid list head.
> +//! #     unsafe { bindings::list_add_tail(&mut (*ptr).link, head) };
> +//! # }
> +//!
> +//! // Rust wrapper for the C struct.
> +//! // The list item struct in this example is defined in C code as:
> +//! //   struct SampleItemC {
> +//! //       int value;
> +//! //       struct list_head link;
> +//! //   };
> +//! //
> +//! #[repr(transparent)]
> +//! pub struct Item(Opaque<SampleItemC>);
> +//!
> +//! impl Item {
> +//!     pub fn value(&self) -> i32 {
> +//!         // SAFETY: [`Item`] has same layout as [`SampleItemC`].
> +//!         unsafe { (*self.0.get()).value }
> +//!     }
> +//! }
> +//!
> +//! // Create typed [`CList`] from sentinel head.
> +//! // SAFETY: head is valid and initialized, items are `SampleItemC` with
> +//! // embedded `link` field, and `Item` is `#[repr(transparent)]` over `SampleItemC`.
> +//! let list = clist_create!(unsafe { head, Item, SampleItemC, link });
> +//!
> +//! // Iterate directly over typed items.
> +//! let mut found_0 = false;
> +//! let mut found_10 = false;
> +//! let mut found_20 = false;
> +//!
> +//! for item in list.iter() {
> +//!     let val = item.value();
> +//!     if val == 0 { found_0 = true; }
> +//!     if val == 10 { found_10 = true; }
> +//!     if val == 20 { found_20 = true; }
> +//! }
> +//!
> +//! assert!(found_0 && found_10 && found_20);
> +//! ```
> +
> +use core::{
> +    iter::FusedIterator,
> +    marker::PhantomData, //
> +};
> +
> +use crate::{
> +    bindings,
> +    types::Opaque, //
> +};
> +
> +use pin_init::{
> +    pin_data,
> +    pin_init,
> +    PinInit, //
> +};
> +
> +/// FFI wrapper for a C `list_head` object used in intrusive linked lists.
> +///
> +/// # Invariants
> +///
> +/// - The underlying `list_head` has been initialized (e.g. via `INIT_LIST_HEAD()`) and its
> +///   `next`/`prev` pointers are valid and non-NULL.
> +#[pin_data]
> +#[repr(transparent)]
> +pub struct CListHead {
> +    #[pin]
> +    inner: Opaque<bindings::list_head>,
> +}
> +
> +impl CListHead {
> +    /// Create a `&CListHead` reference from a raw `list_head` pointer.
> +    ///
> +    /// # Safety
> +    ///
> +    /// - `ptr` must be a valid pointer to an initialized `list_head` (e.g. via
> +    ///   `INIT_LIST_HEAD()`), with valid non-NULL `next`/`prev` pointers.
> +    /// - `ptr` must remain valid for the lifetime `'a`.
> +    /// - The list and all linked `list_head` nodes must not be modified from
> +    ///   anywhere for the lifetime `'a`, unless done so via any [`CListHead`] APIs.
> +    #[inline]
> +    pub unsafe fn from_raw<'a>(ptr: *mut bindings::list_head) -> &'a Self {
> +        // SAFETY:
> +        // - [`CListHead`] has same layout as `list_head`.
> +        // - `ptr` is valid and unmodified for 'a per caller guarantees.
> +        unsafe { &*ptr.cast() }
> +    }
> +
> +    /// Get the raw `list_head` pointer.
> +    #[inline]
> +    pub fn as_raw(&self) -> *mut bindings::list_head {
> +        self.inner.get()
> +    }
> +
> +    /// Get the next [`CListHead`] in the list.
> +    #[inline]
> +    pub fn next(&self) -> &Self {
> +        let raw = self.as_raw();
> +        // SAFETY:
> +        // - `self.as_raw()` is valid and initialized per type invariants.
> +        // - The `next` pointer is valid and non-NULL per type invariants
> +        //   (initialized via `INIT_LIST_HEAD()` or equivalent).
> +        unsafe { Self::from_raw((*raw).next) }
> +    }
> +
> +    /// Check if this node is linked in a list (not isolated).
> +    #[inline]
> +    pub fn is_linked(&self) -> bool {
> +        let raw = self.as_raw();
> +        // SAFETY: self.as_raw() is valid per type invariants.
> +        unsafe { (*raw).next != raw && (*raw).prev != raw }
> +    }
> +
> +    /// Pin-initializer that initializes the list head.
> +    pub fn new() -> impl PinInit<Self> {
> +        pin_init!(Self {
> +            // SAFETY: `INIT_LIST_HEAD` initializes `slot` to a valid empty list.
> +            inner <- Opaque::ffi_init(|slot| unsafe { bindings::INIT_LIST_HEAD(slot) }),
> +        })
> +    }
> +}
> +
> +// SAFETY: `list_head` contains no thread-bound state; it only holds
> +// `next`/`prev` pointers.
> +unsafe impl Send for CListHead {}
> +
> +// SAFETY: `CListHead` can be shared among threads as modifications are
> +// not allowed at the moment.
> +unsafe impl Sync for CListHead {}
> +
> +impl PartialEq for CListHead {
> +    #[inline]
> +    fn eq(&self, other: &Self) -> bool {
> +        core::ptr::eq(self, other)
> +    }
> +}
> +
> +impl Eq for CListHead {}
> +
> +/// Low-level iterator over `list_head` nodes.
> +///
> +/// An iterator used to iterate over a C intrusive linked list (`list_head`). Caller has to
> +/// perform conversion of returned [`CListHead`] to an item (using `container_of` macro or similar).
> +///
> +/// # Invariants
> +///
> +/// [`CListHeadIter`] is iterating over an initialized and valid list.
> +struct CListHeadIter<'a> {
Hi,
Joel

Thanks for the clist abstraction. The Tyr debugfs [1] I'm implementing
needs to iterate over a GpuVm's VA list, and I'd like to switch that to
a CList-based implementation.

Could you make CListHeadIter public and expose a public constructor?
Or do you have a better suggestion?

The VA list mixes two node types in one list — GpuVa (with driver-specific
data) and KernelGpuVa — so we have to filter/skip nodes and can't use
CList as-is. With a public CListHeadIter and new(), we can implement a
custom iterator (like our current GpuVaIter) on top of CListHeadIter and 
then
migrate that code to clist instead of hand-rolled list traversal.

[1] 
https://gitlab.freedesktop.org/panfrost/linux/-/merge_requests/59/diffs?commit_id=0853a7b69a42b32832c8e57da63272a8585cb76b#23581e10c8b583e85ebde61a1675ac3a70e37c14_84_148

Thanks,
Alvin Sun


> +    /// Current position in the list.
> +    current: &'a CListHead,
> +    /// The sentinel head (used to detect end of iteration).
> +    sentinel: &'a CListHead,
> +}
> +
> +impl<'a> Iterator for CListHeadIter<'a> {
> +    type Item = &'a CListHead;
> +
> +    #[inline]
> +    fn next(&mut self) -> Option<Self::Item> {
> +        // Check if we've reached the sentinel (end of list).
> +        if self.current == self.sentinel {
> +            return None;
> +        }
> +
> +        let item = self.current;
> +        self.current = item.next();
> +        Some(item)
> +    }
> +}
> +
> +impl<'a> FusedIterator for CListHeadIter<'a> {}
> +
> +/// A typed C linked list with a sentinel head intended for FFI use-cases where
> +/// C subsystem manages a linked list that Rust code needs to read. Generally
> +/// required only for special cases.
> +///
> +/// A sentinel head [`CListHead`] represents the entire linked list and can be used
> +/// for iteration over items of type `T`, it is not associated with a specific item.
> +///
> +/// The const generic `OFFSET` specifies the byte offset of the `list_head` field within
> +/// the struct that `T` wraps.
> +///
> +/// # Invariants
> +///
> +/// - The sentinel [`CListHead`] has been initialized (e.g. via `INIT_LIST_HEAD()`) with valid
> +///   non-NULL `next`/`prev` pointers.
> +/// - `OFFSET` is the byte offset of the `list_head` field within the struct that `T` wraps.
> +/// - All the list's `list_head` nodes have been initialized with valid non-NULL `next`/`prev`
> +///   pointers.
> +#[repr(transparent)]
> +pub struct CList<T, const OFFSET: usize>(CListHead, PhantomData<T>);
> +
> +impl<T, const OFFSET: usize> CList<T, OFFSET> {
> +    /// Create a typed [`CList`] reference from a raw sentinel `list_head` pointer.
> +    ///
> +    /// # Safety
> +    ///
> +    /// - `ptr` must be a valid pointer to an initialized sentinel `list_head` (e.g. via
> +    ///   `INIT_LIST_HEAD()`), with valid non-NULL `next`/`prev` pointers.
> +    /// - `ptr` must remain valid for the lifetime `'a`.
> +    /// - The list and all linked nodes must not be concurrently modified for the lifetime `'a`.
> +    /// - The list must contain items where the `list_head` field is at byte offset `OFFSET`.
> +    /// - `T` must be `#[repr(transparent)]` over the C struct.
> +    #[inline]
> +    pub unsafe fn from_raw<'a>(ptr: *mut bindings::list_head) -> &'a Self {
> +        // SAFETY:
> +        // - [`CList`] has same layout as [`CListHead`] due to repr(transparent).
> +        // - Caller guarantees `ptr` is a valid, sentinel `list_head` object.
> +        unsafe { &*ptr.cast() }
> +    }
> +
> +    /// Check if the list is empty.
> +    #[inline]
> +    pub fn is_empty(&self) -> bool {
> +        !self.0.is_linked()
> +    }
> +
> +    /// Create an iterator over typed items.
> +    #[inline]
> +    pub fn iter(&self) -> CListIter<'_, T, OFFSET> {
> +        let head = &self.0;
> +        CListIter {
> +            head_iter: CListHeadIter {
> +                current: head.next(),
> +                sentinel: head,
> +            },
> +            _phantom: PhantomData,
> +        }
> +    }
> +}
> +
> +/// High-level iterator over typed list items.
> +pub struct CListIter<'a, T, const OFFSET: usize> {
> +    head_iter: CListHeadIter<'a>,
> +    _phantom: PhantomData<&'a T>,
> +}
> +
> +impl<'a, T, const OFFSET: usize> Iterator for CListIter<'a, T, OFFSET> {
> +    type Item = &'a T;
> +
> +    #[inline]
> +    fn next(&mut self) -> Option<Self::Item> {
> +        let head = self.head_iter.next()?;
> +
> +        // Convert to item using OFFSET.
> +        // SAFETY: `item_ptr` calculation from `OFFSET` (calculated using offset_of!)
> +        // is valid per invariants.
> +        Some(unsafe { &*head.as_raw().byte_sub(OFFSET).cast::<T>() })
> +    }
> +}
> +
> +impl<'a, T, const OFFSET: usize> FusedIterator for CListIter<'a, T, OFFSET> {}
> +
> +/// Create a C doubly-circular linked list interface `CList` from a raw `list_head` pointer.
> +///
> +/// This macro creates a `CList<T, OFFSET>` that can iterate over items of type `$rust_type`
> +/// linked via the `$field` field in the underlying C struct `$c_type`.
> +///
> +/// # Arguments
> +///
> +/// - `$head`: Raw pointer to the sentinel `list_head` object (`*mut bindings::list_head`).
> +/// - `$rust_type`: Each item's rust wrapper type.
> +/// - `$c_type`: Each item's C struct type that contains the embedded `list_head`.
> +/// - `$field`: The name of the `list_head` field within the C struct.
> +///
> +/// # Safety
> +///
> +/// The caller must ensure:
> +///
> +/// - `$head` is a valid, initialized sentinel `list_head` (e.g. via `INIT_LIST_HEAD()`)
> +///   pointing to a list that is not concurrently modified for the lifetime of the `CList`.
> +/// - The list contains items of type `$c_type` linked via an embedded `$field`.
> +/// - `$rust_type` is `#[repr(transparent)]` over `$c_type` or has compatible layout.
> +///
> +/// # Examples
> +///
> +/// Refer to the examples in this module's documentation.
> +#[macro_export]
> +macro_rules! clist_create {
> +    (unsafe { $head:expr, $rust_type:ty, $c_type:ty, $($field:tt).+ }) => {{
> +        // Compile-time check that field path is a list_head.
> +        let _: fn(*const $c_type) -> *const $crate::bindings::list_head =
> +            |p| unsafe { &raw const (*p).$($field).+ };
> +
> +        // Calculate offset and create `CList`.
> +        const OFFSET: usize = ::core::mem::offset_of!($c_type, $($field).+);
> +        // SAFETY: The caller of this macro is responsible for ensuring safety.
> +        unsafe { $crate::ffi::clist::CList::<$rust_type, OFFSET>::from_raw($head) }
> +    }};
> +}
> diff --git a/rust/kernel/ffi/mod.rs b/rust/kernel/ffi/mod.rs
> index 7d844e9cb339..8c235ca0d1e3 100644
> --- a/rust/kernel/ffi/mod.rs
> +++ b/rust/kernel/ffi/mod.rs
> @@ -5,3 +5,5 @@
>   // Re-export C type definitions from the `ffi` crate so that existing
>   // `kernel::ffi::c_int` etc. paths continue to work.
>   pub use ::ffi::*;
> +
> +pub mod clist;
> diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
> index 0a77b4c0ffeb..58dbb02c5197 100644
> --- a/rust/kernel/lib.rs
> +++ b/rust/kernel/lib.rs
> @@ -28,6 +28,7 @@
>   #![feature(lint_reasons)]
>   //
>   // Stable since Rust 1.82.0.
> +#![feature(offset_of_nested)]
>   #![feature(raw_ref_op)]
>   //
>   // Stable since Rust 1.83.0.

^ permalink raw reply

* Re: [PATCH v2] staging: fbtft: fb_ra8875: replace udelays with fsleep
From: Jose A. Perez de Azpillaga @ 2026-02-26  8:31 UTC (permalink / raw)
  To: Andriy Shevchenko
  Cc: Andy Shevchenko, Jose A . Perez de Azpillaga, dri-devel,
	Greg Kroah-Hartman, linux-fbdev, linux-kernel, linux-staging
In-Reply-To: <aZ_6QvJPZplh6xtd@smile.fi.intel.com>

Hi Andy,

write_reg8_bus8() calls par->fbtftops.write(), which in this driver
resolves to write_spi(), which calls spi_sync(). Since spi_sync()
requires sleepable context, write_reg8_bus8() is transitively guaranteed
to run in non-atomic context, making fsleep() safe to use.

Best regards, Jose

^ permalink raw reply

* [PATCH v1 1/1] fbtft: Update REAMDE to slow down the stream of undesired cleanups
From: Andy Shevchenko @ 2026-02-26  8:08 UTC (permalink / raw)
  To: Andy Shevchenko, dri-devel, linux-fbdev, linux-staging,
	linux-kernel
  Cc: Andy Shevchenko, Greg Kroah-Hartman, Randy Dunlap, Helge Deller,
	Dan Carpenter

Lately the enormous amount of some untested cleanups started coming
to a mailing list. This adds an unneeded and undesired burden on
the reviewers and maintainers. Try to stop that by clearly state
what we accept and on what conditions in the README file.

Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
---
 drivers/staging/fbtft/README | 29 +++++++----------------------
 1 file changed, 7 insertions(+), 22 deletions(-)

diff --git a/drivers/staging/fbtft/README b/drivers/staging/fbtft/README
index ba4c74c92e4c..91f152d622bd 100644
--- a/drivers/staging/fbtft/README
+++ b/drivers/staging/fbtft/README
@@ -6,27 +6,12 @@ The module 'fbtft' makes writing drivers for some of these displays very easy.
 
 Development is done on a Raspberry Pi running the Raspbian "wheezy" distribution.
 
-INSTALLATION
-  Download kernel sources
+For new hardware support consider using DRM subsystem (see TODO).
 
-  From Linux 3.15
-    cd drivers/video/fbdev/fbtft
-    git clone https://github.com/notro/fbtft.git
+NOTE:
 
-    Add to drivers/video/fbdev/Kconfig:   source "drivers/video/fbdev/fbtft/Kconfig"
-    Add to drivers/video/fbdev/Makefile:  obj-y += fbtft/
-
-  Before Linux 3.15
-    cd drivers/video
-    git clone https://github.com/notro/fbtft.git
-
-    Add to drivers/video/Kconfig:   source "drivers/video/fbtft/Kconfig"
-    Add to drivers/video/Makefile:  obj-y += fbtft/
-
-  Enable driver(s) in menuconfig and build the kernel
-
-
-See wiki for more information: https://github.com/notro/fbtft/wiki
-
-
-Source: https://github.com/notro/fbtft/
+The driver is in maintenance mode, only performance issue or bug fixes
+are accepted, which effectively means the patches must be tested on
+the real hardware (the patch must be accompanied with the information
+what hardware is that). The treewide changes may also be accepted as
+an exception.
-- 
2.50.1


^ permalink raw reply related

* Re: [PATCH v2] staging: fbtft: fb_ra8875: replace udelays with fsleep
From: Andy Shevchenko @ 2026-02-26  7:46 UTC (permalink / raw)
  To: Jose A. Perez de Azpillaga
  Cc: Greg Kroah-Hartman, Andy Shevchenko, dri-devel, linux-fbdev,
	linux-kernel, linux-staging
In-Reply-To: <20260225234100.152320-1-azpijr@gmail.com>

On Thu, Feb 26, 2026 at 12:40:36AM +0100, Jose A. Perez de Azpillaga wrote:
> The write_reg8_bus8 function uses udelay(100) twice to wait for the

write_reg8_bus8()

> display controller. In non-atomic contexts, fsleep() is the preferred
> API as it automatically selects the most efficient sleeping mechanism
> and avoids busy-waiting.

But how do you know this is the non-atomic context?

> Update both instances to use fsleep(100).

-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply

* Re: [PATCH v11 4/4] rust: gpu: Add GPU buddy allocator bindings
From: Alexandre Courbot @ 2026-02-26  2:26 UTC (permalink / raw)
  To: Joel Fernandes
  Cc: linux-kernel, Miguel Ojeda, Boqun Feng, Gary Guo, Bjorn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Danilo Krummrich, Dave Airlie, Daniel Almeida, Koen Koning,
	dri-devel, nouveau, rust-for-linux, Nikola Djukic,
	Maarten Lankhorst, Maxime Ripard, Simona Vetter, Jonathan Corbet,
	Alex Deucher, Christian Koenig, Jani Nikula, Joonas Lahtinen,
	Rodrigo Vivi, Tvrtko Ursulin, Huang Rui, Matthew Auld,
	Matthew Brost, Lucas De Marchi, Thomas Hellstrom, Helge Deller,
	Alex Gaynor, Boqun Feng, Alistair Popple, Andrea Righi, Zhi Wang,
	Philipp Stanner, Elle Rhumsaa, alexeyi, Eliot Courtney, linux-doc,
	amd-gfx, intel-gfx, intel-xe, linux-fbdev
In-Reply-To: <eff888d1-2caa-45bd-a611-e5772ee94e1b@nvidia.com>

On Thu Feb 26, 2026 at 5:41 AM JST, Joel Fernandes wrote:
>> This structure doesn't seem to be useful. I would understand using one
>> if `GpuBuddyParams` had lots of members, some of which have a sensible
>> default value - then we could implement `Default` and let users fill in
>> the parameters they need.
>>
>> But this structure has no constructor of any sort, requiring users to
>> fill its 3 members manually - which is actually heavier than having 3
>> parameters to `GpuBuddy::new`. It is even deconstructed in
>> `GpuBuddyInner` to store its members as 3 different fields! So let's
>> skip it.
>
> I'd prefer to keep the struct -- all three parameters are `u64`, so
> positional arguments would be easy to silently misorder. The struct
> also makes call sites more readable since Rust has no named function call
> parameters.

Fair point about the 3 parameters being easily confused. If you keep it,
can you also store it in `GpuBuddyInner` instead of deconstructing it
into 3 members?

>
>>> +pub struct GpuBuddyAllocParams {
>>
>> This one also feels like it could be rustified some more.
>>
>> By this I mean that it e.g. allows the user to specify a range even if
>> `RANGE_ALLOCATION` is not set. A C API rejects invalid combinations at
>> runtime. A Rust API should make it impossible to even express them.
>>
>> [...]
>>
>> That would turn `alloc_blocks` into something like:
>>
>>   `fn alloc_blocks(&self, alloc: AllocType, size: u64, min_block_size: Alignment, flags: AllocBlocksFlags)`
>
> The C API supports combining allocation modes with modifiers (e.g.
> RANGE+CLEAR, TOPDOWN+CLEAR), so modeling the mode as a
> mutually-exclusive enum would lose valid combinations. More importantly,

What I suggested does allow you to combine allocation modes with
modifiers. I should have pasted a bit of code for clarity, so here goes:

    #[derive(Copy, Clone, Debug, PartialEq, Eq)]
    pub enum GpuBuddyAllocMode {
        Simple,
        Range { start: u64, end: u64 },
        TopDown,
    }

    impl GpuBuddyAllocMode {
        // Returns the flag corresponding to the allocation mode.
        //
        // Intentionally private - for internal use.
        fn into_flags(self) -> usize {
            match self {
                Self::Simple => 0,
                Self::Range { .. } => bindings::GPU_BUDDY_RANGE_ALLOCATION,
                Self::TopDown => bindings::GPU_BUDDY_TOPDOWN_ALLOCATION,
            }
        }
    }

    impl_flags!(
        #[derive(Copy, Clone, PartialEq, Eq, Default)]
        pub struct GpuBuddyAllocFlags(u32);

        #[derive(Copy, Clone, PartialEq, Eq)]
        pub enum GpuBuddyAllocFlag {
            Contiguous = bindings::GPU_BUDDY_CONTIGUOUS_ALLOCATION as u32,
            Clear = bindings::GPU_BUDDY_CLEAR_ALLOCATION as u32,
            TrimDisable = bindings::GPU_BUDDY_TRIM_DISABLE as u32,
        }
    );

    pub struct GpuBuddyAllocParams {
        mode: GpuBuddyAllocMode,
        size: u64,
        min_block_size: u64,
        flags: GpuBuddyAllocFlags,
    }

Now instead of doing something like:

    let params = GpuBuddyAllocParams {
        start_range_address: 0,
        end_range_address: 0,
        size: SZ_16M as u64,
        min_block_size: SZ_16M as u64,
        buddy_flags: BuddyFlag::TopdownAllocation.into(),
    };

You would have:

    let params = GpuBuddyAllocParams {
        // No unneeded `start_range` and `end_range`!
        mode: GpuBuddyAllocMode::TopDown,
        size: SZ_16M as u64,
        min_block_size: SZ_16M as u64,
        flags: Default::default(),
    };

And for a cleared range allocation:

    let params = GpuBuddyAllocParams {
        mode: GpuBuddyAllocMode::Range {
            start: 0,
            end: SZ_16M as u64,
        },
        size: SZ_16M as u64,
        min_block_size: SZ_16M as u64,
        flags: GpuBuddyAllocFlag::Clear,
    };

Actually the parameters are now distinct enough that you don't need a
type to prevent confusion. A block allocation now just reads like a nice
sentence:

    buddy.alloc_blocks(
        GpuBuddyAllocMode::Range {
            start: 0,
            end: SZ_16M,
        },
        SZ_16M,
        // `min_block_size` should be an `Alignment`, the C API even
        // returns an error if it is not a power of 2.
        Alignment::new::<SZ_16M>(),
        GpuBuddyAllocFlag::Clear,
    )?;

And the job of `alloc_blocks` is also simplified:

    let (start, end) = match mode {
        GpuBuddyAllocMode::Range { start, end } => (start, end),
        _ => (0, 0),
    };
    let flags = mode.into_flags() | u32::from(flags) as usize;
    // ... and just invoke the C API with these parameters.

> if the C allocator evolves its flag semantics (new combinations become
> valid, or existing constraints change), an enum on the Rust side would
> break. It's simpler and more maintainable to pass combinable flags and
> let the C allocator validate -- which it already does. The switch to
> `impl_flags!` will work for us without over-constraining.

The evolution you describe is speculative and unlikely to happen as it
would break all C users just the same. And if the C API adds new flags
or allocation modes, we will have to update the Rust abstraction either
way.

Rust abstractions should model the C API correctly. By hardening the way
the C API can be used and stripping out invalid uses, we save headaches
to users of the API who don't need to worry about whether the flag they
pass will result in an error or simply be ignored, and we also save
maintainer time who don't have to explain the intricacies of their APIs
to confused users. :)

>
>>> +/// The internal [`GpuBuddyGuard`] ensures that the lock is held for all
>>
>> `GpuBuddyGuard` is exported and not internal though.
>
> Fixed, removed "internal" wording.
>
>>> +    base_offset: u64,
>>
>> This does not appear to be used in the C API - does it belong here? It
>> looks like an additional convenience, but I'm not convinced that's the
>> role of this type to provide this. But if it really is needed by all
>> users (guess I'll find out after looking the Nova code :)), then keeping
>> it is fair I guess.
>
> Yes, `base_offset` is needed by nova-core. The GPU's usable VRAM
> starts at `usable_vram_start` from the GSP firmware parameters:
>
>     GpuBuddyParams {
>         base_offset: params.usable_vram_start,
>         physical_memory_size: params.usable_vram_size,
>         chunk_size: SZ_4K.into_safe_cast(),
>     }
>
> `AllocatedBlock::offset()` then adds `base_offset` to return absolute
> VRAM addresses, so callers don't need to track the offset themselves.

Sounds fair, I'll check how this is used in Nova.

Ah, another thing I've noticed while writing the example above:

> +#[pinned_drop]
> +impl PinnedDrop for AllocatedBlocks {
> +    fn drop(self: Pin<&mut Self>) {
> +        let guard = self.buddy.lock();
> +
> +        // SAFETY:
> +        // - list is valid per the type's invariants.
> +        // - guard provides exclusive access to the allocator.
> +        // CAST: BuddyFlags were validated to fit in u32 at construction.
> +        unsafe {
> +            bindings::gpu_buddy_free_list(
> +                guard.as_raw(),
> +                self.list.as_raw(),
> +                self.flags.as_raw() as u32,

`gpu_buddy_free_list` only expects the `CLEARED` flag - actually it
silently masks other flags. So you probably want to just pass `0` here -
adding a `Cleared` field to `GpuBuddyAllocFlag` would also do the trick,
but it looks risky to me as it relies on the promise that the user has
cleared the buffer, which is not something we can guarantee. So I don't
think we can support this safely.

If you just pass `0`, then the `flags` member of `AllocatedBlocks`
becomes unused and you can just drop it.

And another small one - some methods of `Block` are `pub(crate)` - I
believe they should either be `pub` or kept private.

^ permalink raw reply

* Re: [PATCH v11 2/2] rust: clist: Add support to interface with C linked lists
From: Joel Fernandes @ 2026-02-26  0:24 UTC (permalink / raw)
  To: Alexandre Courbot
  Cc: linux-kernel, Miguel Ojeda, Boqun Feng, Gary Guo, Bjorn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Alex Gaynor, Danilo Krummrich, Dave Airlie, Maarten Lankhorst,
	Maxime Ripard, Simona Vetter, Daniel Almeida, Koen Koning,
	Nikola Djukic, Philipp Stanner, Elle Rhumsaa, Jonathan Corbet,
	Alex Deucher, Christian Koenig, Jani Nikula, Joonas Lahtinen,
	Rodrigo Vivi, Tvrtko Ursulin, Huang Rui, Matthew Auld,
	Matthew Brost, Lucas De Marchi, Thomas Hellstrom, Helge Deller,
	Alistair Popple, Andrea Righi, Zhi Wang, alexeyi, Eliot Courtney,
	dri-devel, nouveau, rust-for-linux, linux-doc, amd-gfx, intel-gfx,
	intel-xe, linux-fbdev
In-Reply-To: <DGNW1KH6TCE1.3DIVLKYG6OURI@nvidia.com>

On Wed, 25 Feb 2026 17:09:22 +0900, Alexandre Courbot wrote:
> On Wed Feb 25, 2026 at 7:27 AM JST, Joel Fernandes wrote:
>> Add a new module `clist` for working with C's doubly circular linked
>> lists. Provide low-level iteration over list nodes.

<snip>

> +        // SAFETY: `item_ptr` calculation from `OFFSET` (calculated using offset_of!)
>
> `item_ptr` does not exist.

Good catch, thanks! Fixed.

-- 
Joel Fernandes


^ permalink raw reply

* [PATCH v2] staging: fbtft: fb_ra8875: replace udelays with fsleep
From: Jose A. Perez de Azpillaga @ 2026-02-25 23:40 UTC (permalink / raw)
  To: Greg Kroah-Hartman, Andy Shevchenko
  Cc: Jose A . Perez de Azpillaga, dri-devel, linux-fbdev, linux-kernel,
	linux-staging
In-Reply-To: <20260225204602.134218-1-azpijr@gmail.com>

The write_reg8_bus8 function uses udelay(100) twice to wait for the
display controller. In non-atomic contexts, fsleep() is the preferred
API as it automatically selects the most efficient sleeping mechanism
and avoids busy-waiting.

Update both instances to use fsleep(100).

Signed-off-by: Jose A. Perez de Azpillaga <azpijr@gmail.com>
---
v2: Switch from usleep_range() to fsleep() for modernizing delay calls.
---
 drivers/staging/fbtft/fb_ra8875.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/staging/fbtft/fb_ra8875.c b/drivers/staging/fbtft/fb_ra8875.c
index 0ab1de6647d0..fe95ec6da064 100644
--- a/drivers/staging/fbtft/fb_ra8875.c
+++ b/drivers/staging/fbtft/fb_ra8875.c
@@ -210,7 +210,7 @@ static void write_reg8_bus8(struct fbtft_par *par, int len, ...)
 	}
 	len--;

-	udelay(100);
+	fsleep(100);

 	if (len) {
 		buf = (u8 *)par->buf;
@@ -231,7 +231,7 @@ static void write_reg8_bus8(struct fbtft_par *par, int len, ...)

 	/* restore user spi-speed */
 	par->fbtftops.write = fbtft_write_spi;
-	udelay(100);
+	fsleep(100);
 }

 static int write_vmem16_bus8(struct fbtft_par *par, size_t offset, size_t len)
--
2.53.0


^ permalink raw reply related

* Re: [PATCH] staging: fbtft: fb_ra8875: replace udelays with usleep_range
From: Greg KH @ 2026-02-25 21:14 UTC (permalink / raw)
  To: Jose A. Perez de Azpillaga
  Cc: andy, dri-devel, linux-fbdev, linux-staging, linux-kernel
In-Reply-To: <20260225204602.134218-1-azpijr@gmail.com>

On Wed, Feb 25, 2026 at 09:45:59PM +0100, Jose A. Perez de Azpillaga wrote:
> The write_reg8_bus8 function uses udelay(100) twice to wait for the
> display controller. For delays of this duration in non-atomic context,
> usleep_range() is preferred as it avoids busy-waiting.
> 
> Update both instances to use usleep_range(100, 120), allowing the
> scheduler to utilize the CPU during these wait periods.
> 
> Signed-off-by: Jose A. Perez de Azpillaga <azpijr@gmail.com>
> ---
>  drivers/staging/fbtft/fb_ra8875.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/staging/fbtft/fb_ra8875.c b/drivers/staging/fbtft/fb_ra8875.c
> index 0ab1de6647d0..6058934e2ca2 100644
> --- a/drivers/staging/fbtft/fb_ra8875.c
> +++ b/drivers/staging/fbtft/fb_ra8875.c
> @@ -210,7 +210,7 @@ static void write_reg8_bus8(struct fbtft_par *par, int len, ...)
>  	}
>  	len--;
>  
> -	udelay(100);
> +	usleep_range(100, 120);
>  
>  	if (len) {
>  		buf = (u8 *)par->buf;
> @@ -231,7 +231,7 @@ static void write_reg8_bus8(struct fbtft_par *par, int len, ...)
>  
>  	/* restore user spi-speed */
>  	par->fbtftops.write = fbtft_write_spi;
> -	udelay(100);
> +	usleep_range(100, 120);
>  }
>  
>  static int write_vmem16_bus8(struct fbtft_par *par, size_t offset, size_t len)
> -- 
> 2.53.0
> 
> 

Hi,

This is the friendly patch-bot of Greg Kroah-Hartman.  You have sent him
a patch that has triggered this response.  He used to manually respond
to these common problems, but in order to save his sanity (he kept
writing the same thing over and over, yet to different people), I was
created.  Hopefully you will not take offence and will fix the problem
in your patch and resubmit it so that it can be accepted into the Linux
kernel tree.

You are receiving this message because of the following common error(s)
as indicated below:

- You sent a patch that has been sent multiple times in the past few
  days, and is identical to ones that has been recently rejected.
  Please always look at the mailing list traffic to determine if you are
  duplicating other people's work.

If you wish to discuss this problem further, or you have questions about
how to resolve this issue, please feel free to respond to this email and
Greg will reply once he has dug out from the pending patches received
from other developers.

thanks,

greg k-h's patch email bot

^ permalink raw reply

* [PATCH] staging: fbtft: fb_ra8875: replace udelays with usleep_range
From: Jose A. Perez de Azpillaga @ 2026-02-25 20:45 UTC (permalink / raw)
  To: andy, gregkh; +Cc: dri-devel, linux-fbdev, linux-staging, linux-kernel, azpijr

The write_reg8_bus8 function uses udelay(100) twice to wait for the
display controller. For delays of this duration in non-atomic context,
usleep_range() is preferred as it avoids busy-waiting.

Update both instances to use usleep_range(100, 120), allowing the
scheduler to utilize the CPU during these wait periods.

Signed-off-by: Jose A. Perez de Azpillaga <azpijr@gmail.com>
---
 drivers/staging/fbtft/fb_ra8875.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/staging/fbtft/fb_ra8875.c b/drivers/staging/fbtft/fb_ra8875.c
index 0ab1de6647d0..6058934e2ca2 100644
--- a/drivers/staging/fbtft/fb_ra8875.c
+++ b/drivers/staging/fbtft/fb_ra8875.c
@@ -210,7 +210,7 @@ static void write_reg8_bus8(struct fbtft_par *par, int len, ...)
 	}
 	len--;
 
-	udelay(100);
+	usleep_range(100, 120);
 
 	if (len) {
 		buf = (u8 *)par->buf;
@@ -231,7 +231,7 @@ static void write_reg8_bus8(struct fbtft_par *par, int len, ...)
 
 	/* restore user spi-speed */
 	par->fbtftops.write = fbtft_write_spi;
-	udelay(100);
+	usleep_range(100, 120);
 }
 
 static int write_vmem16_bus8(struct fbtft_par *par, size_t offset, size_t len)
-- 
2.53.0


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox