Linux Framebuffer Layer development
 help / color / mirror / Atom feed
* Re: [PATCH 0/3] fbdev: Request memory regions in platform drivers
From: Geert Uytterhoeven @ 2026-04-23  7:22 UTC (permalink / raw)
  To: Amit Barzilai; +Cc: deller, thomas.zimmermann, linux-fbdev, dri-devel
In-Reply-To: <20260420134424.77494-1-amit.barzilai22@gmail.com>

Hi Amit,

On Mon, 20 Apr 2026 at 17:23, Amit Barzilai <amit.barzilai22@gmail.com> wrote:
> Several fbdev platform drivers call ioremap() on their hardware MMIO
> without first claiming the range via request_mem_region(). This leaves
> the kernel resource tree (/proc/iomem) with no record of the mapping,
> allowing another driver to silently map the same registers.
>
> This series fixes three platform_device drivers by switching to helpers
> that combine resource claiming and ioremap in a single managed call.
> cobalt_lcdfb and clps711x-fb are converted to
> devm_platform_get_and_ioremap_resource(); goldfishfb is converted to
> devm_ioremap_resource(), which also lets us drop the manual iounmap()
> calls from the error path and remove function.
>
> For clps711x-fb, resource 1 (the framebuffer range) already used
> devm_platform_get_and_ioremap_resource() correctly; this series makes
> resource 0 (the MMIO control registers) consistent with it.
>
> This is part of the ongoing effort described in
> Documentation/drm/todo.rst ("Request memory regions in all fbdev
> drivers").

This file does not seem to exist?
Was it hallucinated by Claude:claude-sonnet-4-6?

> Amit Barzilai (3):
>   fbdev: cobalt_lcdfb: Request memory region
>   fbdev: clps711x-fb: Request memory region for MMIO
>   fbdev: goldfishfb: Request memory region

Thanks for your series, which is now commit d2386d9e3eb4c12f ("fbdev:
cobalt_lcdfb: Request memory region") and a40c0e815962b1f6 ("fbdev:
clps711x-fb: Request memory region for MMIO") in fbdev/for-next.

Have you tested this series?  I have to ask, because adding
seemingly-innocent request_mem_region() calls without testing the
result is a recurring source of broken drivers.

Thanks!

Gr{oetje,eeting}s,

                        Geert


--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

^ permalink raw reply

* Re: [PATCH 1/3] fbdev: cobalt_lcdfb: Request memory region
From: Amit Barzilai @ 2026-04-22 15:29 UTC (permalink / raw)
  To: deller; +Cc: amit.barzilai22, dri-devel, linux-fbdev, thomas.zimmermann
In-Reply-To: <404ec984-0486-442e-a108-4c5bad700248@gmx.de>

Hi Helge,

Yes, I wrote all three patches and I am OK with the added Signed-off-by line.
Sorry for the oversight, I'll make sure to include it in future submissions.

Thanks,
Amit

^ permalink raw reply

* Re: [PATCH 1/3] fbdev: cobalt_lcdfb: Request memory region
From: Helge Deller @ 2026-04-22 14:50 UTC (permalink / raw)
  To: Amit Barzilai; +Cc: thomas.zimmermann, linux-fbdev, dri-devel
In-Reply-To: <20260420134424.77494-2-amit.barzilai22@gmail.com>

Hi Amit,

On 4/20/26 15:44, Amit Barzilai wrote:
> Use devm_platform_get_and_ioremap_resource() instead of open-coding
> platform_get_resource() and devm_ioremap() separately. The helper
> requests the memory region before mapping it, which registers the range
> in /proc/iomem and prevents another driver from mapping the same
> registers.
> 
> Assisted-by: Claude:claude-sonnet-4-6

You missed your signed-off line, which I added while applying patches #1 and #2:
Signed-off-by: Amit Barzilai <amit.barzilai22@gmail.com>

Amit, please confirm that you wrote patches #2 and #3 and that you
are OK with the added Signed-off-by line, otherwise I need to drop the patches.

Helge

> ---
>   drivers/video/fbdev/cobalt_lcdfb.c | 12 +++---------
>   1 file changed, 3 insertions(+), 9 deletions(-)


^ permalink raw reply

* Re: [PATCH 3/3] fbdev: goldfishfb: Request memory region
From: Helge Deller @ 2026-04-22 14:43 UTC (permalink / raw)
  To: Amit Barzilai; +Cc: thomas.zimmermann, linux-fbdev, dri-devel
In-Reply-To: <20260420134424.77494-4-amit.barzilai22@gmail.com>

On 4/20/26 15:44, Amit Barzilai wrote:
> Use devm_ioremap_resource() instead of plain ioremap(). The helper
> requests the memory region before mapping it, which registers the range
> in /proc/iomem and prevents another driver from mapping the same
> registers. As it is device-managed, remove the corresponding iounmap()
> calls from the error unwind path and the remove function.
> 
> Assisted-by: Claude:claude-sonnet-4-6
> ---
>   drivers/video/fbdev/goldfishfb.c | 8 +++-----
>   1 file changed, 3 insertions(+), 5 deletions(-)

It was alreads fixed by another patch upstream...

Helge

^ permalink raw reply

* Re: [PATCH] fbdev: omapfb: fix reference leak on failed device registration
From: Helge Deller @ 2026-04-22 14:30 UTC (permalink / raw)
  To: Guangshuo Li, Thomas Zimmermann, Kees Cook, Dan Carpenter,
	Tomi Valkeinen, linux-fbdev, linux-omap, dri-devel, linux-kernel
In-Reply-To: <20260415191747.3845525-1-lgs201920130244@gmail.com>

Hello Guanghshuo,

On 4/15/26 21:17, Guangshuo Li wrote:
> When platform_device_register() fails in omapfb_probe(), the embedded
> struct device in omapdss_device has already been initialized by
> device_initialize(), but the failure path only reports the error and
> returns without dropping the device reference for the current platform
> device:
> 
>    omapfb_probe()
>      -> platform_device_register(&omapdss_device)
>         -> device_initialize(&omapdss_device.dev)
>         -> setup_pdev_dma_masks(&omapdss_device)
>         -> platform_device_add(&omapdss_device)
> 
> This leads to a reference leak when platform_device_register() fails.
> Fix this by calling platform_device_put() before returning the error.

I see you submitted quite some patches, all about the same issue.
I did not yet fully checked if there is really a reference leak, but even if
it would be, I think it's wrong that all the callers in the whole Linux kernel source
would now need to use platform_device_put(). To me it then seems as if everyone got it wrong.
IMHO if platform_device_register() fails it should put the device itself before
returning.
Just looking at generic code, see platform_add_devices() in drivers/base/platform.c
which seem to have it wrong too then...

Helge


> The issue was identified by a static analysis tool I developed and
> confirmed by manual review.
> 
> Fixes: f778a12dd3320 ("OMAP: OMAPFB: fix clk_get for RFBI")
> Cc: stable@vger.kernel.org
> Signed-off-by: Guangshuo Li <lgs201920130244@gmail.com>
> ---
>   drivers/video/fbdev/omap/omapfb_main.c | 1 +
>   1 file changed, 1 insertion(+)
> 
> diff --git a/drivers/video/fbdev/omap/omapfb_main.c b/drivers/video/fbdev/omap/omapfb_main.c
> index cafe859d6e5a..0d47a8aec5c5 100644
> --- a/drivers/video/fbdev/omap/omapfb_main.c
> +++ b/drivers/video/fbdev/omap/omapfb_main.c
> @@ -1768,6 +1768,7 @@ static int omapfb_probe(struct platform_device *pdev)
>   	r = platform_device_register(&omapdss_device);
>   	if (r) {
>   		dev_err(&pdev->dev, "can't register omapdss device\n");
> +		platform_device_put(&omapdss_device);
>   		return r;
>   	}
>   


^ permalink raw reply

* Re: [PATCH] video: fbdev: aty: Fix spelling mistake "enfore" -> "enforce"
From: Helge Deller @ 2026-04-22 13:57 UTC (permalink / raw)
  To: Ethan Carter Edwards
  Cc: linux-fbdev, dri-devel, linux-kernel, kernel-janitors
In-Reply-To: <20260418-radeon-typo-v1-1-8e075365089b@ethancedwards.com>

On 4/19/26 02:45, Ethan Carter Edwards wrote:
> There is a spelling mistake in a comment. Fix it.
> 
> Signed-off-by: Ethan Carter Edwards <ethan@ethancedwards.com>
> ---
>   drivers/video/fbdev/aty/radeon_monitor.c | 2 +-

applied.
Thanks!
Helge

^ permalink raw reply

* Re: [PATCH v11 02/20] gpu: nova-core: gsp: Extract usable FB region from GSP
From: John Hubbard @ 2026-04-21 21:41 UTC (permalink / raw)
  To: David Airlie, Joel Fernandes
  Cc: linux-kernel, Miguel Ojeda, Boqun Feng, Gary Guo, Bjorn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Danilo Krummrich, Daniel Almeida, Koen Koning, dri-devel,
	rust-for-linux, Nikola Djukic, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Simona Vetter, Jonathan Corbet,
	Alex Deucher, Christian Koenig, Jani Nikula, Joonas Lahtinen,
	Rodrigo Vivi, Tvrtko Ursulin, Huang Rui, Matthew Auld,
	Lucas De Marchi, Thomas Hellstrom, Helge Deller, Alex Gaynor,
	Boqun Feng, 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: <CAMwc25o2qmaYnfsh-cW4M4PEbmpYb_1x4qg1_2155P0orzCnOQ@mail.gmail.com>

On 4/21/26 1:05 PM, David Airlie wrote:
...
>>>> +            usable_fb_region: msg.first_usable_fb_region().ok_or(ENODEV)?,
>>>
>>> OK, failing out is correct here. But in addition, we should also
>>> log this at dev_err!() level. This is rare, surprising, and actionable,
>>> so perfect for that level of logging.
>>
>> Sure, that works for me. Will add it in for v12.
> 
> Just fyi when we get to spark later this will not matter, we will have
> no usable_fb_region, though maybe it could just return 0s in that
> case.
> 

Hi Dave,

The "no FB on this SKU" is a separate case, at least as I recall from
specifically looking into that during the patch review. We already have
cases like that (in Open RM) and those are not error cases.

This one here is a real error, though: "expected an FB and got nothing
useful".

thanks,
-- 
John Hubbard


^ permalink raw reply

* Re: [PATCH v11 02/20] gpu: nova-core: gsp: Extract usable FB region from GSP
From: David Airlie @ 2026-04-21 20:05 UTC (permalink / raw)
  To: Joel Fernandes
  Cc: John Hubbard, linux-kernel, Miguel Ojeda, Boqun Feng, Gary Guo,
	Bjorn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
	Trevor Gross, Danilo Krummrich, Daniel Almeida, Koen Koning,
	dri-devel, rust-for-linux, Nikola Djukic, Maarten Lankhorst,
	Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
	Jonathan Corbet, Alex Deucher, Christian Koenig, Jani Nikula,
	Joonas Lahtinen, Rodrigo Vivi, Tvrtko Ursulin, Huang Rui,
	Matthew Auld, Lucas De Marchi, Thomas Hellstrom, Helge Deller,
	Alex Gaynor, Boqun Feng, 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: <20260421145521.GA51176@joelbox2>

On Wed, Apr 22, 2026 at 12:55 AM Joel Fernandes <joelagnelf@nvidia.com> wrote:
>
> On Thu, Apr 16, 2026 at 04:26:48PM -0700, John Hubbard wrote:
> > On 4/15/26 2:05 PM, Joel Fernandes wrote:
> > ...
> >
> > Apologies, I found one more minor thing, while looking at a
> > subsequent patch in this series:
> >
> > >  impl MessageFromGsp for GetGspStaticInfoReply {
> > >      const FUNCTION: MsgFunction = MsgFunction::GetGspStaticInfo;
> > >      type Message = GspStaticConfigInfo;
> > > -    type InitError = Infallible;
> > > +    type InitError = Error;
> > >
> > >      fn read(
> > >          msg: &Self::Message,
> > > @@ -205,6 +209,7 @@ fn read(
> > >      ) -> Result<Self, Self::InitError> {
> > >          Ok(GetGspStaticInfoReply {
> > >              gpu_name: msg.gpu_name_str(),
> > > +            usable_fb_region: msg.first_usable_fb_region().ok_or(ENODEV)?,
> >
> > OK, failing out is correct here. But in addition, we should also
> > log this at dev_err!() level. This is rare, surprising, and actionable,
> > so perfect for that level of logging.
>
> Sure, that works for me. Will add it in for v12.

Just fyi when we get to spark later this will not matter, we will have
no usable_fb_region, though maybe it could just return 0s in that
case.

Dave.


^ permalink raw reply

* Re: [PATCH v11 07/20] gpu: nova-core: mm: Add TLB flush support
From: Joel Fernandes @ 2026-04-21 17:23 UTC (permalink / raw)
  To: Danilo Krummrich
  Cc: linux-kernel, Miguel Ojeda, Boqun Feng, Gary Guo, Bjorn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Dave Airlie, Daniel Almeida, Koen Koning, dri-devel,
	rust-for-linux, Nikola Djukic, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Simona Vetter, Jonathan Corbet,
	Alex Deucher, Christian Koenig, Jani Nikula, Joonas Lahtinen,
	Rodrigo Vivi, Tvrtko Ursulin, Huang Rui, Matthew Auld,
	Lucas De Marchi, Thomas Hellstrom, 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: <9f30b572-04be-4adc-b5f0-a286ea601996@nvidia.com>

On Tue, Apr 21, 2026 at 09:47:39AM -0400, Joel Fernandes wrote:
> 
> 
> On 4/16/2026 6:53 PM, Danilo Krummrich wrote:
> > On Fri Apr 17, 2026 at 12:18 AM CEST, Joel Fernandes wrote:
> >> On 4/16/2026 5:45 PM, Danilo Krummrich wrote:
> >>> Why do we need the try_access() dance in the first place? I assume this ends up
> >>> being called from the BarAccess destructor?
> >>
> >> BarAccess is different. The try_access() calls here are in tlb.rs and
> >> pramin.rs for Bar0.
> > 
> > Yes, and we shouldn't need them in the first place; we should have a
> > &Device<Bound> in all call paths this is called from.

So it causes a bit more threading of the device, but agreed it is an improvement.
Here is a preview, let me know if this is not what you had in mind, thanks!

---8<-----------------------

diff --git a/drivers/gpu/nova-core/gpu.rs b/drivers/gpu/nova-core/gpu.rs
index 6ea9ab7647ced..c2756525dffad 100644
--- a/drivers/gpu/nova-core/gpu.rs
+++ b/drivers/gpu/nova-core/gpu.rs
@@ -322,7 +322,7 @@ pub(crate) fn new<'a>(
                 // PRAMIN covers all physical VRAM (including GSP-reserved areas
                 // above the usable region, e.g. the BAR1 page directory).
                 let pramin_vram_region = 0..gsp_static_info.total_fb_end;
-                GpuMm::new(devres_bar.clone(), spec.chipset, GpuBuddyParams {
+                GpuMm::new(devres_bar.clone(), pdev.as_ref(), spec.chipset, GpuBuddyParams {
                     base_offset: usable_vram.start,
                     size: usable_vram.end - usable_vram.start,
                     chunk_size: Alignment::new::<SZ_4K>(),
diff --git a/drivers/gpu/nova-core/mm.rs b/drivers/gpu/nova-core/mm.rs
index 2583e32fb5dc1..1c0d076a785d5 100644
--- a/drivers/gpu/nova-core/mm.rs
+++ b/drivers/gpu/nova-core/mm.rs
@@ -32,6 +32,7 @@ fn from(pfn: Pfn) -> Self {
 
 use kernel::{
     bitfield,
+    device,
     devres::Devres,
     gpu::buddy::{
         GpuBuddy,
@@ -75,13 +76,14 @@ impl GpuMm {
     /// areas). PRAMIN window accesses are validated against this range.
     pub(crate) fn new(
         bar: Arc<Devres<Bar0>>,
+        dev: &device::Device<device::Bound>,
         chipset: Chipset,
         buddy_params: GpuBuddyParams,
         pramin_vram_region: core::ops::Range<u64>,
     ) -> Result<impl PinInit<Self>> {
         let buddy = GpuBuddy::new(buddy_params)?;
         let tlb_init = Tlb::new(bar.clone());
-        let pramin_init = pramin::Pramin::new(bar, chipset, pramin_vram_region)?;
+        let pramin_init = pramin::Pramin::new(bar, dev, chipset, pramin_vram_region)?;
 
         Ok(pin_init!(Self {
             buddy,
diff --git a/drivers/gpu/nova-core/mm/bar_user.rs b/drivers/gpu/nova-core/mm/bar_user.rs
index 086d33776c48a..172f9c0f5b4d8 100644
--- a/drivers/gpu/nova-core/mm/bar_user.rs
+++ b/drivers/gpu/nova-core/mm/bar_user.rs
@@ -4,6 +4,7 @@
 //! for GPU work submission, and applications to access GPU buffers via mmap().
 
 use kernel::{
+    device,
     io::Io,
     prelude::*, //
 };
@@ -45,6 +46,7 @@ pub(crate) fn new(pdb_addr: VramAddress, chipset: Chipset, va_size: u64) -> Resu
     /// Map physical pages to a contiguous BAR1 virtual range.
     pub(crate) fn map<'a>(
         &'a mut self,
+        dev: &'a device::Device<device::Bound>,
         mm: &'a GpuMm,
         bar: &'a Bar1,
         pfns: &[Pfn],
@@ -54,10 +56,11 @@ pub(crate) fn map<'a>(
             return Err(EINVAL);
         }
 
-        let mapped = self.vmm.map_pages(mm, pfns, None, writable)?;
+        let mapped = self.vmm.map_pages(dev, mm, pfns, None, writable)?;
 
         Ok(BarUserAccess {
             vmm: &mut self.vmm,
+            dev,
             mm,
             bar,
             mapped: Some(mapped),
@@ -72,6 +75,7 @@ pub(crate) fn map<'a>(
 /// [`Vmm::unmap_pages()`], which consumes it).
 pub(crate) struct BarUserAccess<'a> {
     vmm: &'a mut Vmm,
+    dev: &'a device::Device<device::Bound>,
     mm: &'a GpuMm,
     bar: &'a Bar1,
     /// Needs to be an `Option` so that we can `take()` it and call `Drop`
@@ -144,7 +148,7 @@ pub(crate) fn try_write64(&self, value: u64, offset: usize) -> Result {
 impl Drop for BarUserAccess<'_> {
     fn drop(&mut self) {
         if let Some(mapped) = self.mapped.take() {
-            if self.vmm.unmap_pages(self.mm, mapped).is_err() {
+            if self.vmm.unmap_pages(self.dev, self.mm, mapped).is_err() {
                 kernel::pr_warn_once!("BarUserAccess: unmap_pages failed.\n");
             }
         }
@@ -158,7 +162,7 @@ fn drop(&mut self) {
 /// and test pages as needed.
 #[cfg(CONFIG_NOVA_MM_SELFTESTS)]
 pub(crate) fn run_self_test(
-    dev: &kernel::device::Device,
+    pdev: &device::Device<device::Bound>,
     mm: &GpuMm,
     bar1: &Bar1,
     bar1_pdb: u64,
@@ -180,12 +184,13 @@ pub(crate) fn run_self_test(
     const PATTERN_PRAMIN: u32 = 0xDEAD_BEEF;
     const PATTERN_BAR1: u32 = 0xCAFE_BABE;
 
+    let dev = pdev.as_ref();
     dev_info!(dev, "MM: Starting self-test...\n");
 
     let pdb_addr = VramAddress::new(bar1_pdb);
 
     // Check if initial page tables are in VRAM.
-    if crate::mm::pagetable::check_pdb_valid(mm.pramin(), pdb_addr, chipset).is_err() {
+    if crate::mm::pagetable::check_pdb_valid(pdev, mm.pramin(), pdb_addr, chipset).is_err() {
         dev_info!(dev, "MM: Self-test SKIPPED - no valid VRAM page tables\n");
         return Ok(());
     }
@@ -208,7 +213,7 @@ pub(crate) fn run_self_test(
     let mut vmm = Vmm::new(pdb_addr, chipset.mmu_version(), SZ_64K.into_safe_cast())?;
 
     // Create a test mapping.
-    let mapped = vmm.map_pages(mm, &[test_pfn], None, true)?;
+    let mapped = vmm.map_pages(pdev, mm, &[test_pfn], None, true)?;
     let test_vfn = mapped.vfn_start;
 
     // Pre-compute test addresses for the PRAMIN to BAR1 read test.
@@ -219,7 +224,7 @@ pub(crate) fn run_self_test(
 
     // Test 1: Write via PRAMIN, read via BAR1.
     {
-        let mut window = mm.pramin().get_window()?;
+        let mut window = mm.pramin().get_window(pdev)?;
         window.try_write32(vram_read_addr, PATTERN_PRAMIN)?;
     }
 
@@ -239,19 +244,19 @@ pub(crate) fn run_self_test(
     };
 
     // Cleanup - invalidate PTE.
-    vmm.unmap_pages(mm, mapped)?;
+    vmm.unmap_pages(pdev, mm, mapped)?;
 
     // Test 2: Two-phase prepare/execute API.
-    let prepared = vmm.prepare_map(mm, 1, None)?;
-    let mapped2 = vmm.execute_map(mm, prepared, &[test_pfn], true)?;
-    let readback = vmm.read_mapping(mm, mapped2.vfn_start)?;
+    let prepared = vmm.prepare_map(pdev, mm, 1, None)?;
+    let mapped2 = vmm.execute_map(pdev, mm, prepared, &[test_pfn], true)?;
+    let readback = vmm.read_mapping(pdev, mm, mapped2.vfn_start)?;
     let test2_passed = if readback == Some(test_pfn) {
         true
     } else {
         dev_err!(dev, "MM: Test 2 FAILED - Two-phase map readback mismatch\n");
         false
     };
-    vmm.unmap_pages(mm, mapped2)?;
+    vmm.unmap_pages(pdev, mm, mapped2)?;
 
     // Test 3: Range-constrained allocation with a hole — exercises block.size()-driven
     // BAR1 mapping. A 4K hole is punched at base+16K, then a single 32K allocation
@@ -311,7 +316,7 @@ pub(crate) fn run_self_test(
             )?;
         }
 
-        let mapped = vmm.map_pages(mm, &pfns, None, true)?;
+        let mapped = vmm.map_pages(pdev, mm, &pfns, None, true)?;
         let bar1_base_vfn: usize = mapped.vfn_start.raw().into_safe_cast();
         let bar1_base = bar1_base_vfn.checked_mul(PAGE_SIZE).ok_or(EOVERFLOW)?;
 
@@ -326,7 +331,7 @@ pub(crate) fn run_self_test(
             bar1.try_write32(PATTERN_BAR1, page_bar1_off)?;
 
             let pramin_val = {
-                let mut window = mm.pramin().get_window()?;
+                let mut window = mm.pramin().get_window(pdev)?;
                 window.try_read32(page_phys.into_safe_cast())?
             };
 
@@ -342,7 +347,7 @@ pub(crate) fn run_self_test(
             }
         }
 
-        vmm.unmap_pages(mm, mapped)?;
+        vmm.unmap_pages(pdev, mm, mapped)?;
     }
 
     // Verify aggregate: all returned block sizes must sum to allocation size.
@@ -363,11 +368,11 @@ pub(crate) fn run_self_test(
     // Test 4: Exercise `BarUser::map()` end-to-end.
     let mut bar_user = BarUser::new(pdb_addr, chipset, SZ_64K.into_safe_cast())?;
     let test4_passed = {
-        let access = bar_user.map(mm, bar1, &[test_pfn], true)?;
+        let access = bar_user.map(pdev, mm, bar1, &[test_pfn], true)?;
 
         // Write pattern via PRAMIN, read via BarUserAccess.
         {
-            let mut window = mm.pramin().get_window()?;
+            let mut window = mm.pramin().get_window(pdev)?;
             window.try_write32(test_vram.raw(), PATTERN_BAR1)?;
         }
 
diff --git a/drivers/gpu/nova-core/mm/pagetable.rs b/drivers/gpu/nova-core/mm/pagetable.rs
index 922ff8bd4f0fd..b267dcf4dd8ba 100644
--- a/drivers/gpu/nova-core/mm/pagetable.rs
+++ b/drivers/gpu/nova-core/mm/pagetable.rs
@@ -22,7 +22,10 @@
     VirtualAddress,
     VramAddress, //
 };
-use kernel::prelude::*;
+use kernel::{
+    device,
+    prelude::*, //
+};
 
 /// Extracts the page table index at a given level from a virtual address.
 pub(super) trait VaLevelIndex {
@@ -386,10 +389,11 @@ fn from(val: AperturePde) -> Self {
 /// Check if the PDB has valid, VRAM-backed page tables.
 #[cfg(CONFIG_NOVA_MM_SELFTESTS)]
 fn check_pdb_inner<M: MmuConfig>(
+    dev: &device::Device<device::Bound>,
     pramin: &pramin::Pramin,
     pdb_addr: VramAddress,
 ) -> Result {
-    let mut window = pramin.get_window()?;
+    let mut window = pramin.get_window(dev)?;
     let raw = window.try_read64(pdb_addr.raw())?;
 
     if !M::Pde::new(raw).is_valid_vram() {
@@ -401,12 +405,13 @@ fn check_pdb_inner<M: MmuConfig>(
 /// Check if the PDB has valid, VRAM-backed page tables, dispatching by MMU version.
 #[cfg(CONFIG_NOVA_MM_SELFTESTS)]
 pub(super) fn check_pdb_valid(
+    dev: &device::Device<device::Bound>,
     pramin: &pramin::Pramin,
     pdb_addr: VramAddress,
     chipset: crate::gpu::Chipset,
 ) -> Result {
     match MmuVersion::from(chipset.arch()) {
-        MmuVersion::V2 => check_pdb_inner::<MmuV2>(pramin, pdb_addr),
-        MmuVersion::V3 => check_pdb_inner::<MmuV3>(pramin, pdb_addr),
+        MmuVersion::V2 => check_pdb_inner::<MmuV2>(dev, pramin, pdb_addr),
+        MmuVersion::V3 => check_pdb_inner::<MmuV3>(dev, pramin, pdb_addr),
     }
 }
diff --git a/drivers/gpu/nova-core/mm/pagetable/map.rs b/drivers/gpu/nova-core/mm/pagetable/map.rs
index a9719580143e1..16af491472dbc 100644
--- a/drivers/gpu/nova-core/mm/pagetable/map.rs
+++ b/drivers/gpu/nova-core/mm/pagetable/map.rs
@@ -5,6 +5,7 @@
 use core::marker::PhantomData;
 
 use kernel::{
+    device,
     gpu::buddy::{
         AllocatedBlocks,
         GpuBuddyAllocFlags,
@@ -73,7 +74,11 @@ pub(super) fn new(pdb_addr: VramAddress) -> Self {
     }
 
     /// Allocate and zero a physical page table page.
-    fn alloc_and_zero_page(mm: &GpuMm, level: PageTableLevel) -> Result<PreparedPtPage> {
+    fn alloc_and_zero_page(
+        dev: &device::Device<device::Bound>,
+        mm: &GpuMm,
+        level: PageTableLevel,
+    ) -> Result<PreparedPtPage> {
         let blocks = KBox::pin_init(
             mm.buddy().alloc_blocks(
                 GpuBuddyAllocMode::Simple,
@@ -87,7 +92,7 @@ fn alloc_and_zero_page(mm: &GpuMm, level: PageTableLevel) -> Result<PreparedPtPa
         let page_vram = VramAddress::new(blocks.iter().next().ok_or(ENOMEM)?.offset());
 
         // Zero via PRAMIN.
-        let mut window = mm.pramin().get_window()?;
+        let mut window = mm.pramin().get_window(dev)?;
         let base = page_vram.raw();
         for off in (0..PAGE_SIZE).step_by(8) {
             window.try_write64(base + off, 0)?;
@@ -106,6 +111,7 @@ fn alloc_and_zero_page(mm: &GpuMm, level: PageTableLevel) -> Result<PreparedPtPa
     /// the fence signalling critical path.
     fn ensure_single_pte_path(
         &self,
+        dev: &device::Device<device::Bound>,
         mm: &GpuMm,
         vfn: Vfn,
         pt_pages: &mut RBTree<VramAddress, PreparedPtPage>,
@@ -113,7 +119,7 @@ fn ensure_single_pte_path(
         let max_iter = 2 * M::PDE_LEVELS.len();
 
         for _ in 0..max_iter {
-            let mut window = mm.pramin().get_window()?;
+            let mut window = mm.pramin().get_window(dev)?;
 
             let result = self
                 .walker
@@ -133,7 +139,7 @@ fn ensure_single_pte_path(
                 } => {
                     // Drop PRAMIN before allocation.
                     drop(window);
-                    let page = Self::alloc_and_zero_page(mm, level)?;
+                    let page = Self::alloc_and_zero_page(dev, mm, level)?;
                     let node = RBTreeNode::new(install_addr, page, GFP_KERNEL)?;
                     let old = pt_pages.insert(node);
                     if old.is_some() {
@@ -160,6 +166,7 @@ fn ensure_single_pte_path(
     /// per-VFN to prepare pages for all missing PDEs.
     pub(super) fn prepare_map(
         &self,
+        dev: &device::Device<device::Bound>,
         mm: &GpuMm,
         vfn_start: Vfn,
         num_pages: usize,
@@ -175,7 +182,7 @@ pub(super) fn prepare_map(
         for i in 0..num_pages {
             let i_u64: u64 = i.into_safe_cast();
             let vfn = Vfn::new(vfn_start.raw() + i_u64);
-            self.ensure_single_pte_path(mm, vfn, pt_pages)?;
+            self.ensure_single_pte_path(dev, mm, vfn, pt_pages)?;
         }
         Ok(())
     }
@@ -185,6 +192,7 @@ pub(super) fn prepare_map(
     /// Drains `pt_pages` and moves allocations into `page_table_allocs`.
     pub(super) fn install_mappings(
         &self,
+        dev: &device::Device<device::Bound>,
         mm: &GpuMm,
         pt_pages: &mut RBTree<VramAddress, PreparedPtPage>,
         page_table_allocs: &mut KVec<Pin<KBox<AllocatedBlocks>>>,
@@ -192,7 +200,7 @@ pub(super) fn install_mappings(
         pfns: &[Pfn],
         writable: bool,
     ) -> Result {
-        let mut window = mm.pramin().get_window()?;
+        let mut window = mm.pramin().get_window(dev)?;
 
         // Drain prepared PT pages, install all pending PDEs.
         let mut cursor = pt_pages.cursor_front_mut();
@@ -239,14 +247,20 @@ pub(super) fn install_mappings(
         drop(window);
 
         // Flush TLB.
-        mm.tlb().flush(self.pdb_addr)
+        mm.tlb().flush(dev, self.pdb_addr)
     }
 
     /// Invalidate PTEs for a range and flush TLB.
-    pub(super) fn invalidate_ptes(&self, mm: &GpuMm, vfn_start: Vfn, num_pages: usize) -> Result {
+    pub(super) fn invalidate_ptes(
+        &self,
+        dev: &device::Device<device::Bound>,
+        mm: &GpuMm,
+        vfn_start: Vfn,
+        num_pages: usize,
+    ) -> Result {
         let invalid_pte = M::Pte::invalid();
 
-        let mut window = mm.pramin().get_window()?;
+        let mut window = mm.pramin().get_window(dev)?;
         for i in 0..num_pages {
             let i_u64: u64 = i.into_safe_cast();
             let vfn = Vfn::new(vfn_start.raw() + i_u64);
@@ -265,7 +279,7 @@ pub(super) fn invalidate_ptes(&self, mm: &GpuMm, vfn_start: Vfn, num_pages: usiz
         }
         drop(window);
 
-        mm.tlb().flush(self.pdb_addr)
+        mm.tlb().flush(dev, self.pdb_addr)
     }
 }
 
@@ -298,6 +312,7 @@ pub(in crate::mm) fn new(pdb_addr: VramAddress, version: MmuVersion) -> Self {
     /// Prepare page table resources for a mapping.
     pub(in crate::mm) fn prepare_map(
         &self,
+        dev: &device::Device<device::Bound>,
         mm: &GpuMm,
         vfn_start: Vfn,
         num_pages: usize,
@@ -306,13 +321,14 @@ pub(in crate::mm) fn prepare_map(
     ) -> Result {
         pt_map_dispatch!(
             self,
-            prepare_map(mm, vfn_start, num_pages, page_table_allocs, pt_pages)
+            prepare_map(dev, mm, vfn_start, num_pages, page_table_allocs, pt_pages)
         )
     }
 
     /// Install prepared PDEs and write PTEs, then flush TLB.
     pub(in crate::mm) fn install_mappings(
         &self,
+        dev: &device::Device<device::Bound>,
         mm: &GpuMm,
         pt_pages: &mut RBTree<VramAddress, PreparedPtPage>,
         page_table_allocs: &mut KVec<Pin<KBox<AllocatedBlocks>>>,
@@ -322,17 +338,18 @@ pub(in crate::mm) fn install_mappings(
     ) -> Result {
         pt_map_dispatch!(
             self,
-            install_mappings(mm, pt_pages, page_table_allocs, vfn_start, pfns, writable)
+            install_mappings(dev, mm, pt_pages, page_table_allocs, vfn_start, pfns, writable)
         )
     }
 
     /// Invalidate PTEs for a range and flush TLB.
     pub(in crate::mm) fn invalidate_ptes(
         &self,
+        dev: &device::Device<device::Bound>,
         mm: &GpuMm,
         vfn_start: Vfn,
         num_pages: usize,
     ) -> Result {
-        pt_map_dispatch!(self, invalidate_ptes(mm, vfn_start, num_pages))
+        pt_map_dispatch!(self, invalidate_ptes(dev, mm, vfn_start, num_pages))
     }
 }
diff --git a/drivers/gpu/nova-core/mm/pagetable/walk.rs b/drivers/gpu/nova-core/mm/pagetable/walk.rs
index 89d4426bcf144..fedb8b4f33e58 100644
--- a/drivers/gpu/nova-core/mm/pagetable/walk.rs
+++ b/drivers/gpu/nova-core/mm/pagetable/walk.rs
@@ -36,7 +36,10 @@
 
 use core::marker::PhantomData;
 
-use kernel::prelude::*;
+use kernel::{
+    device,
+    prelude::*, //
+};
 
 use super::{
     DualPdeOps,
@@ -168,8 +171,13 @@ pub(super) fn walk_pde_levels(
     /// Walk to PTE for lookup only (no allocation).
     ///
     /// Returns [`WalkResult::PageTableMissing`] if intermediate tables don't exist.
-    pub(super) fn walk_to_pte_lookup(&self, mm: &GpuMm, vfn: Vfn) -> Result<WalkResult> {
-        let mut window = mm.pramin().get_window()?;
+    pub(super) fn walk_to_pte_lookup(
+        &self,
+        dev: &device::Device<device::Bound>,
+        mm: &GpuMm,
+        vfn: Vfn,
+    ) -> Result<WalkResult> {
+        let mut window = mm.pramin().get_window(dev)?;
         self.walk_to_pte_lookup_with_window(&mut window, vfn)
     }
 
@@ -236,7 +244,12 @@ pub(in crate::mm) fn new(pdb_addr: VramAddress, version: MmuVersion) -> Self {
     }
 
     /// Walk to PTE for lookup.
-    pub(in crate::mm) fn walk_to_pte(&self, mm: &GpuMm, vfn: Vfn) -> Result<WalkResult> {
-        pt_walk_dispatch!(self, walk_to_pte_lookup(mm, vfn))
+    pub(in crate::mm) fn walk_to_pte(
+        &self,
+        dev: &device::Device<device::Bound>,
+        mm: &GpuMm,
+        vfn: Vfn,
+    ) -> Result<WalkResult> {
+        pt_walk_dispatch!(self, walk_to_pte_lookup(dev, mm, vfn))
     }
 }
diff --git a/drivers/gpu/nova-core/mm/pramin.rs b/drivers/gpu/nova-core/mm/pramin.rs
index f56d6c3d4e255..c16717a73ecba 100644
--- a/drivers/gpu/nova-core/mm/pramin.rs
+++ b/drivers/gpu/nova-core/mm/pramin.rs
@@ -75,11 +75,11 @@
 };
 
 use kernel::{
+    device,
     devres::Devres,
     io::Io,
     new_mutex,
     prelude::*,
-    revocable::RevocableGuard,
     sizes::{
         SZ_1M,
         SZ_64K, //
@@ -117,7 +117,7 @@ pub(crate) fn $name(&mut self, vram_offset: usize) -> Result<$ty> {
                 self.compute_window(vram_offset, ::core::mem::size_of::<$ty>())?;
 
             if let Some(base) = new_base {
-                regs::pramin_window_write_base(self.chipset.arch(), &self.bar, base)?;
+                regs::pramin_window_write_base(self.chipset.arch(), self.bar, base)?;
                 *self.state = base;
             }
             self.bar.$name(bar_offset)
@@ -134,7 +134,7 @@ pub(crate) fn $name(&mut self, vram_offset: usize, value: $ty) -> Result {
                 self.compute_window(vram_offset, ::core::mem::size_of::<$ty>())?;
 
             if let Some(base) = new_base {
-                regs::pramin_window_write_base(self.chipset.arch(), &self.bar, base)?;
+                regs::pramin_window_write_base(self.chipset.arch(), self.bar, base)?;
                 *self.state = base;
             }
             self.bar.$name(value, bar_offset)
@@ -169,11 +169,12 @@ impl Pramin {
     /// `vram_region` specifies the valid VRAM address range.
     pub(crate) fn new(
         bar: Arc<Devres<Bar0>>,
+        dev: &device::Device<device::Bound>,
         chipset: Chipset,
         vram_region: Range<u64>,
     ) -> Result<impl PinInit<Self>> {
-        let bar_access = bar.try_access().ok_or(ENODEV)?;
-        let current_base = regs::pramin_window_read_base(chipset.arch(), &bar_access);
+        let bar_access = bar.access(dev)?;
+        let current_base = regs::pramin_window_read_base(chipset.arch(), bar_access);
 
         Ok(pin_init!(Self {
             bar,
@@ -192,8 +193,11 @@ fn vram_region(&self) -> &Range<u64> {
     ///
     /// Returns a [`PraminWindow`] guard that provides VRAM read/write accessors.
     /// The [`PraminWindow`] is exclusive and only one can exist at a time.
-    pub(crate) fn get_window(&self) -> Result<PraminWindow<'_>> {
-        let bar = self.bar.try_access().ok_or(ENODEV)?;
+    pub(crate) fn get_window<'a>(
+        &'a self,
+        dev: &'a device::Device<device::Bound>,
+    ) -> Result<PraminWindow<'a>> {
+        let bar = self.bar.access(dev)?;
         let state = self.state.lock();
         Ok(PraminWindow {
             bar,
@@ -212,7 +216,7 @@ pub(crate) fn get_window(&self) -> Result<PraminWindow<'_>> {
 /// Only one [`PraminWindow`] can exist at a time per [`Pramin`] instance (enforced by the
 /// internal `MutexGuard`).
 pub(crate) struct PraminWindow<'a> {
-    bar: RevocableGuard<'a, Bar0>,
+    bar: &'a Bar0,
     chipset: Chipset,
     vram_region: Range<u64>,
     state: MutexGuard<'a, u64>,
@@ -433,14 +437,15 @@ fn test_misaligned_access(
 
 /// Run PRAMIN self-tests during boot if self-tests are enabled.
 #[cfg(CONFIG_NOVA_MM_SELFTESTS)]
-pub(crate) fn run_self_test(dev: &kernel::device::Device, pramin: &Pramin) -> Result {
+pub(crate) fn run_self_test(pdev: &device::Device<device::Bound>, pramin: &Pramin) -> Result {
+    let dev = pdev.as_ref();
     dev_info!(dev, "PRAMIN: Starting self-test...\n");
 
     let vram_region = pramin.vram_region();
     let base: usize = vram_region.start.into_safe_cast();
     let base = base + SELFTEST_REGION_OFFSET;
     let vram_end = vram_region.end;
-    let mut win = pramin.get_window()?;
+    let mut win = pramin.get_window(pdev)?;
 
     test_byte_readwrite(dev, &mut win, base)?;
     test_u32_as_bytes(dev, &mut win, base)?;
diff --git a/drivers/gpu/nova-core/mm/tlb.rs b/drivers/gpu/nova-core/mm/tlb.rs
index 8d36e1552792d..53c6fe6084b81 100644
--- a/drivers/gpu/nova-core/mm/tlb.rs
+++ b/drivers/gpu/nova-core/mm/tlb.rs
@@ -11,17 +11,22 @@
 //! ```ignore
 //! use crate::mm::tlb::Tlb;
 //!
-//! fn page_table_update(tlb: &Tlb, pdb_addr: VramAddress) -> Result<()> {
+//! fn page_table_update(
+//!     dev: &device::Device<device::Bound>,
+//!     tlb: &Tlb,
+//!     pdb_addr: VramAddress,
+//! ) -> Result<()> {
 //!     // ... modify page tables ...
 //!
 //!     // Flush TLB to make changes visible (polls for completion).
-//!     tlb.flush(pdb_addr)?;
+//!     tlb.flush(dev, pdb_addr)?;
 //!
 //!     Ok(())
 //! }
 //! ```
 
 use kernel::{
+    device,
     devres::Devres,
     io::poll::read_poll_timeout,
     io::Io,
@@ -92,39 +97,29 @@ pub(super) fn new(bar: Arc<Devres<Bar0>>) -> impl PinInit<Self> {
     /// This invalidates all TLB entries associated with the given PDB address.
     /// Must be called after modifying page table entries to ensure the GPU sees
     /// the updated mappings.
-    pub(super) fn flush(&self, pdb_addr: VramAddress) -> Result {
+    pub(super) fn flush(
+        &self,
+        dev: &device::Device<device::Bound>,
+        pdb_addr: VramAddress,
+    ) -> Result {
         let _guard = self.lock.lock();
+        let bar = self.bar.access(dev)?;
 
-        // Broken into 2 phases with scopes (Write and Poll) to avoid holding
-        // RevecablableGuard (and hence RCU read-side critical section) across
-        // the read_poll_timeout() call that can sleep.
+        // Write PDB address.
+        bar.write_reg(regs::NV_TLB_FLUSH_PDB_LO::from_pdb_addr(pdb_addr.raw_u64()));
+        bar.write_reg(regs::NV_TLB_FLUSH_PDB_HI::from_pdb_addr(pdb_addr.raw_u64()));
 
-        // Write phase — hold bar access briefly for register writes only.
-        {
-            let bar = self.bar.try_access().ok_or(ENODEV)?;
+        // Trigger flush.
+        bar.write_reg(
+            regs::NV_TLB_FLUSH_CTRL::zeroed()
+                .with_all_va(true)
+                .with_ack(TlbAckMode::None)
+                .with_trigger(true),
+        );
 
-            // Write PDB address.
-            bar.write_reg(regs::NV_TLB_FLUSH_PDB_LO::from_pdb_addr(pdb_addr.raw_u64()));
-            bar.write_reg(regs::NV_TLB_FLUSH_PDB_HI::from_pdb_addr(pdb_addr.raw_u64()));
-
-            // Trigger flush: invalidate all virtual addresses, require global
-            // acknowledgment from all engines before completion. See
-            // [`TlbAckMode::Globally`] for why this scope is used unconditionally.
-            bar.write_reg(
-                regs::NV_TLB_FLUSH_CTRL::zeroed()
-                    .with_all_va(true)
-                    .with_ack(TlbAckMode::None)
-                    .with_trigger(true),
-            );
-        }
-
-        // Poll for completion — re-acquire bar access each iteration to avoid
-        // holding the RCU read-side lock (via RevocableGuard) across sleep.
+        // Poll for completion.
         read_poll_timeout(
-            || {
-                let bar = self.bar.try_access().ok_or(ENODEV)?;
-                Ok(bar.read(regs::NV_TLB_FLUSH_CTRL))
-            },
+            || Ok(bar.read(regs::NV_TLB_FLUSH_CTRL)),
             |ctrl: &regs::NV_TLB_FLUSH_CTRL| !ctrl.trigger(),
             Delta::ZERO,
             Delta::from_secs(2),
diff --git a/drivers/gpu/nova-core/mm/vmm.rs b/drivers/gpu/nova-core/mm/vmm.rs
index 45da443211583..35caaed56007e 100644
--- a/drivers/gpu/nova-core/mm/vmm.rs
+++ b/drivers/gpu/nova-core/mm/vmm.rs
@@ -6,6 +6,7 @@
 //! virtual address spaces (Channels, BAR1, BAR2).
 
 use kernel::{
+    device,
     gpu::buddy::AllocatedBlocks,
     maple_tree::MapleTreeAlloc,
     prelude::*,
@@ -207,8 +208,13 @@ fn free_vfn(&self, vfn: Vfn) {
     }
 
     /// Read the [`Pfn`] for a mapped [`Vfn`] if one is mapped.
-    pub(super) fn read_mapping(&self, mm: &GpuMm, vfn: Vfn) -> Result<Option<Pfn>> {
-        match self.pt_walk.walk_to_pte(mm, vfn)? {
+    pub(super) fn read_mapping(
+        &self,
+        dev: &device::Device<device::Bound>,
+        mm: &GpuMm,
+        vfn: Vfn,
+    ) -> Result<Option<Pfn>> {
+        match self.pt_walk.walk_to_pte(dev, mm, vfn)? {
             WalkResult::Mapped { pfn, .. } => Ok(Some(pfn)),
             WalkResult::Unmapped { .. } | WalkResult::PageTableMissing => Ok(None),
         }
@@ -223,6 +229,7 @@ pub(super) fn read_mapping(&self, mm: &GpuMm, vfn: Vfn) -> Result<Option<Pfn>> {
     /// to call outside the fence signalling critical path.
     pub(crate) fn prepare_map(
         &mut self,
+        dev: &device::Device<device::Bound>,
         mm: &GpuMm,
         num_pages: usize,
         va_range: Option<Range<u64>>,
@@ -235,6 +242,7 @@ pub(crate) fn prepare_map(
         let vfn_start = self.alloc_vfn_range(num_pages, va_range)?;
 
         if let Err(e) = self.pt_map.prepare_map(
+            dev,
             mm,
             vfn_start,
             num_pages,
@@ -257,6 +265,7 @@ pub(crate) fn prepare_map(
     /// Installs all prepared PDEs and writes PTEs into the page table, then flushes TLB.
     pub(crate) fn execute_map(
         &mut self,
+        dev: &device::Device<device::Bound>,
         mm: &GpuMm,
         prepared: PreparedMapping,
         pfns: &[Pfn],
@@ -275,6 +284,7 @@ pub(crate) fn execute_map(
         _drop_guard.disarm();
 
         if let Err(e) = self.pt_map.install_mappings(
+            dev,
             mm,
             &mut self.pt_pages,
             &mut self.page_table_allocs,
@@ -300,6 +310,7 @@ pub(crate) fn execute_map(
     /// [`Vmm::execute_map()`] will be called separately.
     pub(crate) fn map_pages(
         &mut self,
+        dev: &device::Device<device::Bound>,
         mm: &GpuMm,
         pfns: &[Pfn],
         va_range: Option<Range<u64>>,
@@ -322,15 +333,20 @@ pub(crate) fn map_pages(
             }
         }
 
-        let prepared = self.prepare_map(mm, pfns.len(), va_range)?;
-        self.execute_map(mm, prepared, pfns, writable)
+        let prepared = self.prepare_map(dev, mm, pfns.len(), va_range)?;
+        self.execute_map(dev, mm, prepared, pfns, writable)
     }
 
     /// Unmap all pages in a [`MappedRange`] with a single TLB flush.
-    pub(crate) fn unmap_pages(&mut self, mm: &GpuMm, range: MappedRange) -> Result {
+    pub(crate) fn unmap_pages(
+        &mut self,
+        dev: &device::Device<device::Bound>,
+        mm: &GpuMm,
+        range: MappedRange,
+    ) -> Result {
         let result = self
             .pt_map
-            .invalidate_ptes(mm, range.vfn_start, range.num_pages);
+            .invalidate_ptes(dev, mm, range.vfn_start, range.num_pages);
 
         // TODO: Internal page table pages (PDE, PTE pages) are still kept around.
         // This is by design as repeated maps/unmaps will be fast. As a future TODO,
-- 
2.34.1


^ permalink raw reply related

* Re: [PATCH v11 02/20] gpu: nova-core: gsp: Extract usable FB region from GSP
From: Joel Fernandes @ 2026-04-21 14:55 UTC (permalink / raw)
  To: John Hubbard
  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, rust-for-linux, Nikola Djukic, Maarten Lankhorst,
	Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
	Jonathan Corbet, Alex Deucher, Christian Koenig, Jani Nikula,
	Joonas Lahtinen, Rodrigo Vivi, Tvrtko Ursulin, Huang Rui,
	Matthew Auld, Lucas De Marchi, Thomas Hellstrom, Helge Deller,
	Alex Gaynor, Boqun Feng, 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: <b0c5267d-ea77-41c5-94d4-39c651761b3c@nvidia.com>

On Thu, Apr 16, 2026 at 04:26:48PM -0700, John Hubbard wrote:
> On 4/15/26 2:05 PM, Joel Fernandes wrote:
> ...
> 
> Apologies, I found one more minor thing, while looking at a
> subsequent patch in this series:
> 
> >  impl MessageFromGsp for GetGspStaticInfoReply {
> >      const FUNCTION: MsgFunction = MsgFunction::GetGspStaticInfo;
> >      type Message = GspStaticConfigInfo;
> > -    type InitError = Infallible;
> > +    type InitError = Error;
> >  
> >      fn read(
> >          msg: &Self::Message,
> > @@ -205,6 +209,7 @@ fn read(
> >      ) -> Result<Self, Self::InitError> {
> >          Ok(GetGspStaticInfoReply {
> >              gpu_name: msg.gpu_name_str(),
> > +            usable_fb_region: msg.first_usable_fb_region().ok_or(ENODEV)?,
> 
> OK, failing out is correct here. But in addition, we should also
> log this at dev_err!() level. This is rare, surprising, and actionable,
> so perfect for that level of logging.

Sure, that works for me. Will add it in for v12.

thanks,

--
Joel Fernandes


^ permalink raw reply

* Re: [PATCH v11 07/20] gpu: nova-core: mm: Add TLB flush support
From: Joel Fernandes @ 2026-04-21 14:28 UTC (permalink / raw)
  To: Danilo Krummrich
  Cc: linux-kernel, Miguel Ojeda, Boqun Feng, Gary Guo, Bjorn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Dave Airlie, Daniel Almeida, Koen Koning, dri-devel,
	rust-for-linux, Nikola Djukic, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Simona Vetter, Jonathan Corbet,
	Alex Deucher, Christian Koenig, Jani Nikula, Joonas Lahtinen,
	Rodrigo Vivi, Tvrtko Ursulin, Huang Rui, Matthew Auld,
	Lucas De Marchi, Thomas Hellstrom, 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: <DHUY5IGHGE49.Z2UVYJ23KX2Y@kernel.org>



On 4/16/2026 6:53 PM, Danilo Krummrich wrote:
> On Fri Apr 17, 2026 at 12:18 AM CEST, Joel Fernandes wrote:
>> On 4/16/2026 5:45 PM, Danilo Krummrich wrote:
>>> Why do we need the try_access() dance in the first place? I assume this ends up
>>> being called from the BarAccess destructor?
>>
>> BarAccess is different. The try_access() calls here are in tlb.rs and
>> pramin.rs for Bar0.
> 
> Yes, and we shouldn't need them in the first place; we should have a
> &Device<Bound> in all call paths this is called from.
> 
>>> If so, I think this is solvable. Gary and me are currently working on
>>> higher-ranked types and a chained Devres type.
>>
>> Hmm, the issue here is we cannot hold revocable guard while sleeping, but
>> we have read the bar as a condition in the body of the poll.
> 
> No, you should just require a &Device<Bound>; or maybe we can utilize the
> mentioned higher-ranked types and DevresChain once we have it. But in any case
> you shouldn't need try_access() here.
> 
>>> With that, such use-cases should be cleanly solvable without the need for
>>> try_access().
>>>
>>> Besides that, I can't find where BarAccess is ever constructed.
>>
>> BarUser::map() constructs it.
> 
> I'm well aware, but absolutely nothing calls BarUser::map(). :)
> 
>>> It already has a lifetime 'a for &'a Bar1, so I don't see why you can't do the
>>> same for Bar0.>
>>> But again, I don't see this being constructed and I'm not sure the whole
>>> construct works in the first place.
>>
>> BarAccess uses &'a Bar1 because it's a short-lived scoped object. In long
>> lived objects I am trying to avoid this.
> 
> Don't get me wrong, if a lifetime is sufficient -- that's great! But I'm
> suspicious whether it actually is, since BarAccess is never actually constructed
> and hence I can't see how it would be used.

Doing some more research, the BAR1 read is required for vGPU bootload,
which happens from Driver initialization. The BarAccess (which I should
probably rename to `BarUserAccess`) is created, accessed and destroyed
before probe ends. So it appears for the moment (and for other scarcity
related points made above), I think keep Bar1 as a lifetime makes sense.

For the TLB and mm objects, I was trying to avoid using lifetimes. But as
you sort of indicated, Device<Bound> and hence Bar1 should outlive the MM
objects, so that sounds like the right approach. I will plan to have that
for v12.



^ permalink raw reply

* Re: [PATCH v11 07/20] gpu: nova-core: mm: Add TLB flush support
From: Joel Fernandes @ 2026-04-21 13:47 UTC (permalink / raw)
  To: Danilo Krummrich
  Cc: linux-kernel, Miguel Ojeda, Boqun Feng, Gary Guo, Bjorn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Dave Airlie, Daniel Almeida, Koen Koning, dri-devel,
	rust-for-linux, Nikola Djukic, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Simona Vetter, Jonathan Corbet,
	Alex Deucher, Christian Koenig, Jani Nikula, Joonas Lahtinen,
	Rodrigo Vivi, Tvrtko Ursulin, Huang Rui, Matthew Auld,
	Lucas De Marchi, Thomas Hellstrom, 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: <DHUY5IGHGE49.Z2UVYJ23KX2Y@kernel.org>



On 4/16/2026 6:53 PM, Danilo Krummrich wrote:
> On Fri Apr 17, 2026 at 12:18 AM CEST, Joel Fernandes wrote:
>> On 4/16/2026 5:45 PM, Danilo Krummrich wrote:
>>> Why do we need the try_access() dance in the first place? I assume this ends up
>>> being called from the BarAccess destructor?
>>
>> BarAccess is different. The try_access() calls here are in tlb.rs and
>> pramin.rs for Bar0.
> 
> Yes, and we shouldn't need them in the first place; we should have a
> &Device<Bound> in all call paths this is called from.
> 
>>> If so, I think this is solvable. Gary and me are currently working on
>>> higher-ranked types and a chained Devres type.
>>
>> Hmm, the issue here is we cannot hold revocable guard while sleeping, but
>> we have read the bar as a condition in the body of the poll.
> 
> No, you should just require a &Device<Bound>; or maybe we can utilize the
> mentioned higher-ranked types and DevresChain once we have it. But in any case
> you shouldn't need try_access() here.
> 
>>> With that, such use-cases should be cleanly solvable without the need for
>>> try_access().
>>>
>>> Besides that, I can't find where BarAccess is ever constructed.
>>
>> BarUser::map() constructs it.
> 
> I'm well aware, but absolutely nothing calls BarUser::map(). :)
> 
>>> It already has a lifetime 'a for &'a Bar1, so I don't see why you can't do the
>>> same for Bar0.>
>>> But again, I don't see this being constructed and I'm not sure the whole
>>> construct works in the first place.
>>
>> BarAccess uses &'a Bar1 because it's a short-lived scoped object. In long
>> lived objects I am trying to avoid this.
> 
> Don't get me wrong, if a lifetime is sufficient -- that's great! But I'm
> suspicious whether it actually is, since BarAccess is never actually constructed
> and hence I can't see how it would be used.

Actually, it is constructed in the self-test. Maybe you missed the
self-test patch?

    #[cfg(CONFIG_NOVA_MM_SELFTESTS)]
    fn run_mm_selftests(self: Pin<&mut Self>, pdev:
&pci::Device<device::Bound>) -> Result {
        // PRAMIN aperture self-tests.
        crate::mm::pramin::run_self_test(pdev.as_ref(), self.mm.pramin())?;

        // BAR1 self-tests.
        let bar1 = Arc::pin_init(pdev.iomap_region(1, c"nova-core/bar1"),
GFP_KERNEL)?;
        let bar1_access = bar1.access(pdev.as_ref())?;

        crate::mm::bar_user::run_self_test(
            pdev.as_ref(),
            &self.mm,
            bar1_access,
            self.gsp_static_info.bar1_pde_base,
            self.spec.chipset,
        )?;

        Ok(())
    }

However, you do raise a good point -- may we cannot assume that BAR1
reference is short lived. One thing though is typically BAR1 size is
limited, so we should not allow anyone to use it for long-lived usecases to
prevent filling up the small BAR1 aperture into VRAM.

The user of the bar1 code is vGPU at the moment, I am sure in the future we
will have other uses of the CPU directly accessing VRAM. Zhi, can you share
any thoughts here? Is BAR1 for vGPU expected to be held long-lived?

I agree with your points about Device<Bound> and I will explore that as well.

^ permalink raw reply

* Re: [patch 33/38] powerpc: Select ARCH_HAS_RANDOM_ENTROPY
From: Mukesh Kumar Chaurasiya @ 2026-04-21 11:22 UTC (permalink / raw)
  To: Thomas Gleixner
  Cc: LKML, Michael Ellerman, linuxppc-dev, Arnd Bergmann, x86,
	Lu Baolu, iommu, Michael Grzeschik, netdev, linux-wireless,
	Herbert Xu, linux-crypto, Vlastimil Babka, linux-mm,
	David Woodhouse, Bernie Thompson, linux-fbdev, Theodore Tso,
	linux-ext4, Andrew Morton, Uladzislau Rezki, Marco Elver,
	Dmitry Vyukov, kasan-dev, Andrey Ryabinin, Thomas Sailer,
	linux-hams, Jason A. Donenfeld, Richard Henderson, linux-alpha,
	Russell King, linux-arm-kernel, Catalin Marinas, Huacai Chen,
	loongarch, Geert Uytterhoeven, linux-m68k, Dinh Nguyen,
	Jonas Bonn, linux-openrisc, Helge Deller, linux-parisc,
	Paul Walmsley, linux-riscv, Heiko Carstens, linux-s390,
	David S. Miller, sparclinux
In-Reply-To: <20260410120319.789114053@kernel.org>

On Fri, Apr 10, 2026 at 02:21:09PM +0200, Thomas Gleixner wrote:
> The only remaining usage of get_cycles() is to provide random_get_entropy().
> 
> Switch powerpc over to the new scheme of selecting ARCH_HAS_RANDOM_ENTROPY
> and providing random_get_entropy() in asm/random.h.
> 
> Remove asm/timex.h as it has no functionality anymore.
> 
> Signed-off-by: Thomas Gleixner <tglx@kernel.org>
> Cc: Michael Ellerman <mpe@ellerman.id.au>
> Cc: linuxppc-dev@lists.ozlabs.org
> ---
>  arch/powerpc/Kconfig              |    1 +
>  arch/powerpc/include/asm/random.h |   13 +++++++++++++
>  arch/powerpc/include/asm/timex.h  |   21 ---------------------
>  3 files changed, 14 insertions(+), 21 deletions(-)
> 
> --- a/arch/powerpc/Kconfig
> +++ b/arch/powerpc/Kconfig
> @@ -150,6 +150,7 @@ config PPC
>  	select ARCH_HAS_PREEMPT_LAZY
>  	select ARCH_HAS_PTDUMP
>  	select ARCH_HAS_PTE_SPECIAL
> +	select ARCH_HAS_RANDOM_ENTROPY
>  	select ARCH_HAS_SCALED_CPUTIME		if VIRT_CPU_ACCOUNTING_NATIVE && PPC_BOOK3S_64
>  	select ARCH_HAS_SET_MEMORY
>  	select ARCH_HAS_STRICT_KERNEL_RWX	if (PPC_BOOK3S || PPC_8xx) && !HIBERNATION
> --- /dev/null
> +++ b/arch/powerpc/include/asm/random.h
> @@ -0,0 +1,13 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +#ifndef _ASM_POWERPC_RANDOM_H
> +#define _ASM_POWERPC_RANDOM_H
> +
> +#include <asm/cputable.h>
> +#include <asm/vdso/timebase.h>
> +
> +static inline unsigned long random_get_entropy(void)
> +{
> +	return mftb();
> +}
> +
> +#endif	/* _ASM_POWERPC_RANDOM_H */
> --- a/arch/powerpc/include/asm/timex.h
> +++ b/arch/powerpc/include/asm/timex.h
> @@ -1,21 +0,0 @@
> -/* SPDX-License-Identifier: GPL-2.0 */
> -#ifndef _ASM_POWERPC_TIMEX_H
> -#define _ASM_POWERPC_TIMEX_H
> -
> -#ifdef __KERNEL__
> -
> -/*
> - * PowerPC architecture timex specifications
> - */
> -
> -#include <asm/cputable.h>
> -#include <asm/vdso/timebase.h>
> -
> -ostatic inline cycles_t get_cycles(void)
> -{
R> -	return mftb();
> -}
> -#define get_cycles get_cycles
> -
> -#endif	/* __KERNEL__ */
> -#endif	/* _ASM_POWERPC_TIMEX_H */
> 
Build tested for this series with allmodconfig and allyesconfig on ppc64le
machine for ppc64le.
tree: git://git.kernel.org/pub/scm/linux/kernel/git/tglx/devel.git getcycles-v1

Boot tested for this series on powernv9 qemu, powernv10 qemu and pSeries
power11 hardware.

Tested-by: Mukesh Kumar Chaurasiya (IBM) <mkchauras@gmail.com>
Reviewed-by: Mukesh Kumar Chaurasiya (IBM) <mkchauras@gmail.com>


^ permalink raw reply

* Re: [patch 32/38] powerpc/spufs: Use mftb() directly
From: Mukesh Kumar Chaurasiya @ 2026-04-21  6:48 UTC (permalink / raw)
  To: Thomas Gleixner
  Cc: LKML, Michael Ellerman, linuxppc-dev, Arnd Bergmann, x86,
	Lu Baolu, iommu, Michael Grzeschik, netdev, linux-wireless,
	Herbert Xu, linux-crypto, Vlastimil Babka, linux-mm,
	David Woodhouse, Bernie Thompson, linux-fbdev, Theodore Tso,
	linux-ext4, Andrew Morton, Uladzislau Rezki, Marco Elver,
	Dmitry Vyukov, kasan-dev, Andrey Ryabinin, Thomas Sailer,
	linux-hams, Jason A. Donenfeld, Richard Henderson, linux-alpha,
	Russell King, linux-arm-kernel, Catalin Marinas, Huacai Chen,
	loongarch, Geert Uytterhoeven, linux-m68k, Dinh Nguyen,
	Jonas Bonn, linux-openrisc, Helge Deller, linux-parisc,
	Paul Walmsley, linux-riscv, Heiko Carstens, linux-s390,
	David S. Miller, sparclinux
In-Reply-To: <20260410120319.723429844@kernel.org>

On Fri, Apr 10, 2026 at 02:21:04PM +0200, Thomas Gleixner wrote:
> There is no reason to indirect via get_cycles(), which is about to be
> removed.
> 
> Use mftb() directly.
> 
> Signed-off-by: Thomas Gleixner <tglx@kernel.org>
> Cc: Michael Ellerman <mpe@ellerman.id.au>
> Cc: linuxppc-dev@lists.ozlabs.org
> ---
>  arch/powerpc/platforms/cell/spufs/switch.c |    5 +++--
>  1 file changed, 3 insertions(+), 2 deletions(-)
> 
> --- a/arch/powerpc/platforms/cell/spufs/switch.c
> +++ b/arch/powerpc/platforms/cell/spufs/switch.c
> @@ -34,6 +34,7 @@
>  #include <asm/spu_priv1.h>
>  #include <asm/spu_csa.h>
>  #include <asm/mmu_context.h>
> +#include <asm/time.h>
>  
>  #include "spufs.h"
>  
> @@ -279,7 +280,7 @@ static inline void save_timebase(struct
>  	 *    Read PPE Timebase High and Timebase low registers
>  	 *    and save in CSA.  TBD.
>  	 */
> -	csa->suspend_time = get_cycles();
> +	csa->suspend_time = mftb();
>  }
>  
>  static inline void remove_other_spu_access(struct spu_state *csa,
> @@ -1261,7 +1262,7 @@ static inline void setup_decr(struct spu
>  	 *     in LSCSA.
>  	 */
>  	if (csa->priv2.mfc_control_RW & MFC_CNTL_DECREMENTER_RUNNING) {
> -		cycles_t resume_time = get_cycles();
> +		cycles_t resume_time = mftb();
>  		cycles_t delta_time = resume_time - csa->suspend_time;
>  
>  		csa->lscsa->decr_status.slot[0] = SPU_DECR_STATUS_RUNNING;
> 
Reviewed-by: Mukesh Kumar Chaurasiya (IBM) <mkchauras@gmail.com>

^ permalink raw reply

* [PATCH 3/3] fbdev: goldfishfb: Request memory region
From: Amit Barzilai @ 2026-04-20 13:44 UTC (permalink / raw)
  To: deller; +Cc: thomas.zimmermann, linux-fbdev, dri-devel, Amit Barzilai
In-Reply-To: <20260420134424.77494-1-amit.barzilai22@gmail.com>

Use devm_ioremap_resource() instead of plain ioremap(). The helper
requests the memory region before mapping it, which registers the range
in /proc/iomem and prevents another driver from mapping the same
registers. As it is device-managed, remove the corresponding iounmap()
calls from the error unwind path and the remove function.

Assisted-by: Claude:claude-sonnet-4-6
---
 drivers/video/fbdev/goldfishfb.c | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/drivers/video/fbdev/goldfishfb.c b/drivers/video/fbdev/goldfishfb.c
index ffe33a36b944..14a7cb0a7a1c 100644
--- a/drivers/video/fbdev/goldfishfb.c
+++ b/drivers/video/fbdev/goldfishfb.c
@@ -194,9 +194,9 @@ static int goldfish_fb_probe(struct platform_device *pdev)
 		ret = -ENODEV;
 		goto err_no_io_base;
 	}
-	fb->reg_base = ioremap(r->start, PAGE_SIZE);
-	if (fb->reg_base == NULL) {
-		ret = -ENOMEM;
+	fb->reg_base = devm_ioremap_resource(&pdev->dev, r);
+	if (IS_ERR(fb->reg_base)) {
+		ret = PTR_ERR(fb->reg_base);
 		goto err_no_io_base;
 	}
 
@@ -273,7 +273,6 @@ static int goldfish_fb_probe(struct platform_device *pdev)
 				fb->fb.fix.smem_start);
 err_alloc_screen_base_failed:
 err_no_irq:
-	iounmap(fb->reg_base);
 err_no_io_base:
 	kfree(fb);
 err_fb_alloc_failed:
@@ -291,7 +290,6 @@ static void goldfish_fb_remove(struct platform_device *pdev)
 
 	dma_free_coherent(&pdev->dev, framesize, (void *)fb->fb.screen_base,
 						fb->fb.fix.smem_start);
-	iounmap(fb->reg_base);
 	kfree(fb);
 }
 
-- 
2.53.0


^ permalink raw reply related

* [PATCH 2/3] fbdev: clps711x-fb: Request memory region for MMIO
From: Amit Barzilai @ 2026-04-20 13:44 UTC (permalink / raw)
  To: deller; +Cc: thomas.zimmermann, linux-fbdev, dri-devel, Amit Barzilai
In-Reply-To: <20260420134424.77494-1-amit.barzilai22@gmail.com>

Use devm_platform_get_and_ioremap_resource() for resource 0 (the MMIO
control register range) instead of open-coding platform_get_resource()
and devm_ioremap() separately. The helper requests the memory region
before mapping it, which registers the range in /proc/iomem and prevents
another driver from mapping the same registers.

This makes resource 0 consistent with resource 1 (the framebuffer),
which already uses devm_platform_get_and_ioremap_resource().

Assisted-by: Claude:claude-sonnet-4-6
---
 drivers/video/fbdev/clps711x-fb.c | 9 +++------
 1 file changed, 3 insertions(+), 6 deletions(-)

diff --git a/drivers/video/fbdev/clps711x-fb.c b/drivers/video/fbdev/clps711x-fb.c
index 5e61a349a4ab..7a7db7100499 100644
--- a/drivers/video/fbdev/clps711x-fb.c
+++ b/drivers/video/fbdev/clps711x-fb.c
@@ -216,12 +216,9 @@ static int clps711x_fb_probe(struct platform_device *pdev)
 	cfb = info->par;
 	platform_set_drvdata(pdev, info);
 
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!res)
-		goto out_fb_release;
-	cfb->base = devm_ioremap(dev, res->start, resource_size(res));
-	if (!cfb->base) {
-		ret = -ENOMEM;
+	cfb->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
+	if (IS_ERR(cfb->base)) {
+		ret = PTR_ERR(cfb->base);
 		goto out_fb_release;
 	}
 
-- 
2.53.0


^ permalink raw reply related

* [PATCH 1/3] fbdev: cobalt_lcdfb: Request memory region
From: Amit Barzilai @ 2026-04-20 13:44 UTC (permalink / raw)
  To: deller; +Cc: thomas.zimmermann, linux-fbdev, dri-devel, Amit Barzilai
In-Reply-To: <20260420134424.77494-1-amit.barzilai22@gmail.com>

Use devm_platform_get_and_ioremap_resource() instead of open-coding
platform_get_resource() and devm_ioremap() separately. The helper
requests the memory region before mapping it, which registers the range
in /proc/iomem and prevents another driver from mapping the same
registers.

Assisted-by: Claude:claude-sonnet-4-6
---
 drivers/video/fbdev/cobalt_lcdfb.c | 12 +++---------
 1 file changed, 3 insertions(+), 9 deletions(-)

diff --git a/drivers/video/fbdev/cobalt_lcdfb.c b/drivers/video/fbdev/cobalt_lcdfb.c
index 308967b5096a..f7faa95fefd3 100644
--- a/drivers/video/fbdev/cobalt_lcdfb.c
+++ b/drivers/video/fbdev/cobalt_lcdfb.c
@@ -295,19 +295,13 @@ static int cobalt_lcdfb_probe(struct platform_device *dev)
 	if (!info)
 		return -ENOMEM;
 
-	res = platform_get_resource(dev, IORESOURCE_MEM, 0);
-	if (!res) {
+	info->screen_base = devm_platform_get_and_ioremap_resource(dev, 0, &res);
+	if (IS_ERR(info->screen_base)) {
 		framebuffer_release(info);
-		return -EBUSY;
+		return PTR_ERR(info->screen_base);
 	}
 
 	info->screen_size = resource_size(res);
-	info->screen_base = devm_ioremap(&dev->dev, res->start,
-					 info->screen_size);
-	if (!info->screen_base) {
-		framebuffer_release(info);
-		return -ENOMEM;
-	}
 
 	info->fbops = &cobalt_lcd_fbops;
 	info->fix = cobalt_lcdfb_fix;
-- 
2.53.0


^ permalink raw reply related

* [PATCH 0/3] fbdev: Request memory regions in platform drivers
From: Amit Barzilai @ 2026-04-20 13:44 UTC (permalink / raw)
  To: deller; +Cc: thomas.zimmermann, linux-fbdev, dri-devel, Amit Barzilai

Several fbdev platform drivers call ioremap() on their hardware MMIO
without first claiming the range via request_mem_region(). This leaves
the kernel resource tree (/proc/iomem) with no record of the mapping,
allowing another driver to silently map the same registers.

This series fixes three platform_device drivers by switching to helpers
that combine resource claiming and ioremap in a single managed call.
cobalt_lcdfb and clps711x-fb are converted to
devm_platform_get_and_ioremap_resource(); goldfishfb is converted to
devm_ioremap_resource(), which also lets us drop the manual iounmap()
calls from the error path and remove function.

For clps711x-fb, resource 1 (the framebuffer range) already used
devm_platform_get_and_ioremap_resource() correctly; this series makes
resource 0 (the MMIO control registers) consistent with it.

This is part of the ongoing effort described in
Documentation/drm/todo.rst ("Request memory regions in all fbdev
drivers").

Amit Barzilai (3):
  fbdev: cobalt_lcdfb: Request memory region
  fbdev: clps711x-fb: Request memory region for MMIO
  fbdev: goldfishfb: Request memory region

 drivers/video/fbdev/clps711x-fb.c  |  9 +++------
 drivers/video/fbdev/cobalt_lcdfb.c | 12 +++---------
 drivers/video/fbdev/goldfishfb.c   |  8 +++-----
 3 files changed, 9 insertions(+), 20 deletions(-)


base-commit: 3f9357c30a44734d45e3093c521d52b2aefb09f5
-- 
2.53.0


^ permalink raw reply

* [PATCH AUTOSEL 7.0-5.10] fbdev: omap2: fix inconsistent lock returns in omapfb_mmap
From: Sasha Levin @ 2026-04-20 13:21 UTC (permalink / raw)
  To: patches, stable
  Cc: Hongling Zeng, kernel test robot, Helge Deller, Sasha Levin,
	linux-omap, linux-fbdev, dri-devel, linux-kernel
In-Reply-To: <20260420132314.1023554-1-sashal@kernel.org>

From: Hongling Zeng <zenghongling@kylinos.cn>

[ Upstream commit 98cf7df6e0844f7076df1db690c1ede9d69b61ff ]

Fix the warning about inconsistent returns for '&rg->lock' in
omapfb_mmap() function. The warning arises because the error path
uses 'ofbi->region' while the normal path uses 'rg'.

smatch warnings:
drivers/video/fbdev/omap2/omapfb/omapfb-main.c:1126 omapfb_mmap()
warn: inconsistent returns '&rg->lock'.

Reported-by: kernel test robot <lkp@intel.com>
Signed-off-by: Hongling Zeng <zenghongling@kylinos.cn>
Signed-off-by: Helge Deller <deller@gmx.de>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---

LLM Generated explanations, may be completely bogus:

Good - line 1122 in v6.6 also has `omapfb_put_mem_region(ofbi->region)`
on the error path, confirming the bug exists in stable trees. Now let me
compile the full analysis.

---

## PHASE 1: COMMIT MESSAGE FORENSICS

**Step 1.1: Subject Line**
- Subsystem: `fbdev: omap2`
- Action verb: "fix"
- Summary: Fix inconsistent lock returns in `omapfb_mmap`

**Step 1.2: Tags**
- Reported-by: kernel test robot `<lkp@intel.com>` — automated static
  analysis (smatch)
- Signed-off-by: Hongling Zeng (author), Helge Deller (fbdev maintainer)
- No Fixes: tag (expected)
- No Cc: stable (expected)

**Step 1.3: Commit Body**
- Bug: smatch warns about inconsistent returns for `&rg->lock` because
  the error path uses `ofbi->region` while the success path uses `rg`
- Symptom: smatch warning (not a runtime crash report)
- Root cause: The error path re-reads `ofbi->region` instead of using
  the captured local `rg`

**Step 1.4: Hidden Bug Fix?**
Yes. While described as a "warning fix," this is actually a real locking
correctness bug, as I'll demonstrate below.

## PHASE 2: DIFF ANALYSIS

**Step 2.1: Inventory**
- Single file: `drivers/video/fbdev/omap2/omapfb/omapfb-main.c`
- 1 line changed: `ofbi->region` → `rg`
- Function: `omapfb_mmap`
- Scope: single-file surgical fix

**Step 2.2: Code Flow Change**
- BEFORE: Error path calls `omapfb_put_mem_region(ofbi->region)` — re-
  reads the `ofbi->region` pointer
- AFTER: Error path calls `omapfb_put_mem_region(rg)` — uses the locally
  captured pointer

**Step 2.3: Bug Mechanism**
This is a **synchronization/lock correctness** bug. Key details:

1. `omapfb_get_mem_region()` acquires `down_read_nested(&rg->lock)` and
   returns its argument (line 183-188 of omapfb.h)
2. At line 1100: `rg = omapfb_get_mem_region(ofbi->region)` acquires the
   read lock and stores the pointer locally
3. Success path (line 1119) correctly releases via `rg`
4. Error path (line 1124, the bug) releases via `ofbi->region`

Critically, `ofbi->region` **can be changed** by another thread — in
`omapfb-ioctl.c` line 98: `ofbi->region = new_rg` during
`omapfb_setup_plane()`. If this happens between get and put:
- `up_read()` is called on a semaphore **not held** by this thread →
  undefined behavior / corruption
- The **actual** locked semaphore is **never released** → deadlock

**Step 2.4: Fix Quality**
- Obviously correct: use the already-captured local variable
- Minimal: 1-line change
- Zero regression risk: the fix is strictly safer than the original code
- Pattern matches `omapfb-sysfs.c` line 73, which correctly uses `rg` on
  its error path

## PHASE 3: GIT HISTORY INVESTIGATION

**Step 3.1: Blame**
The buggy line was introduced in commit `3ed37d9aba486d` ("Revert
'OMAPFB: simplify locking'") by Tomi Valkeinen on 2012-12-13. This code
has been present since ~v3.8, meaning all active stable trees contain
it.

**Step 3.2: Fixes tag**
No Fixes: tag present. However, the buggy commit is `3ed37d9aba486d`
which reverted simplified locking and reintroduced per-region locking.
The error path was incorrectly written using `ofbi->region` instead of
`rg` at that time.

**Step 3.3: File History**
The file hasn't had many recent changes — last meaningful changes were
build system/boilerplate updates. No prerequisites needed.

**Step 3.4: Author**
Hongling Zeng is not the subsystem maintainer but has contributed other
small fixes (USB quirks, sysfs fixes). The commit was signed off by
Helge Deller, the fbdev maintainer.

**Step 3.5: Dependencies**
None. This is a standalone one-line fix.

## PHASE 4: MAILING LIST RESEARCH

**Step 4.1-4.2:** b4 dig could not find the original submission. Lore is
protected by anti-scraping measures. The commit was signed off by the
fbdev maintainer (Helge Deller), confirming proper review.

**Step 4.3:** The bug was reported by kernel test robot (smatch static
analysis), not a runtime bug report.

**Step 4.4-4.5:** No related series; standalone patch.

## PHASE 5: CODE SEMANTIC ANALYSIS

**Step 5.1-5.2:** The function `omapfb_mmap` is registered as the
`.fb_mmap` callback in the framebuffer ops structure, called when
userspace mmaps the framebuffer device (`/dev/fb*`). This is a standard
userspace-reachable path.

**Step 5.3:** `omapfb_get_mem_region` → `down_read_nested` (acquires
rw_semaphore read lock). `omapfb_put_mem_region` → `up_read` (releases
read lock). These must operate on the same object.

**Step 5.4:** Reachable from userspace via `mmap()` on `/dev/fbX`. The
error path triggers when `vm_iomap_memory()` fails.

**Step 5.5:** In `omapfb-sysfs.c:59-73`, the identical pattern (`rg =
omapfb_get_mem_region(ofbi->region)` followed by
`omapfb_put_mem_region(rg)`) is used correctly. The bug in `omapfb_mmap`
is the sole instance of the incorrect pattern.

## PHASE 6: STABLE TREE ANALYSIS

**Step 6.1:** The buggy code exists in v6.6 stable tree (verified: line
1122 has `omapfb_put_mem_region(ofbi->region)`). Present since v3.8
(~2012). All active stable trees are affected.

**Step 6.2:** The fix is a trivial 1-line change. Will apply cleanly to
all stable trees.

**Step 6.3:** No related fixes already in stable.

## PHASE 7: SUBSYSTEM CONTEXT

**Step 7.1:** Subsystem: `drivers/video/fbdev/omap2` — OMAP2 framebuffer
driver. Criticality: PERIPHERAL (legacy ARM platform, but real users
exist in embedded systems).

**Step 7.2:** Low activity — the file hasn't changed meaningfully in
years. Mature/stable code.

## PHASE 8: IMPACT AND RISK ASSESSMENT

**Step 8.1:** Affected users: users of OMAP2 SoC framebuffer
(embedded/ARM platforms).

**Step 8.2:** Trigger conditions: Requires concurrent `mmap()` and
region-changing ioctl on the same framebuffer, plus `vm_iomap_memory()`
failure. The race window is narrow, making this unlikely to trigger in
practice.

**Step 8.3:** Failure mode: If triggered, results in **lock state
corruption** (releasing wrong lock) and potential **deadlock** (held
lock never released). Severity: HIGH (deadlock), though likelihood is
LOW.

**Step 8.4:** Risk-benefit ratio:
- BENEFIT: Fixes a genuine lock correctness bug reachable from
  userspace, prevents potential deadlock
- RISK: Essentially zero — replacing one expression with an equivalent
  one in the normal case, and a correct one in the race case. 1-line
  change. Obviously correct.

## PHASE 9: FINAL SYNTHESIS

**Step 9.1: Evidence Summary**

FOR backporting:
- Fixes a real locking correctness bug (inconsistent lock/unlock
  objects)
- `ofbi->region` can be changed concurrently via ioctl (verified in
  `omapfb-ioctl.c:98`)
- 1-line fix, trivially correct, zero regression risk
- Matches the correct pattern used elsewhere in the same codebase
  (`omapfb-sysfs.c`)
- Accepted by fbdev maintainer (Helge Deller SOB)
- Bug exists in all stable trees (since v3.8, ~2012)
- Clean apply expected

AGAINST backporting:
- OMAP2 fbdev is legacy peripheral hardware
- Race window is extremely narrow and unlikely to trigger in practice
- Only detected by static analysis, not runtime
- Low real-world impact

**Step 9.2: Stable Rules Checklist**
1. Obviously correct and tested? **YES** — trivially verifiable
2. Fixes a real bug? **YES** — inconsistent lock/unlock on potentially
   different objects
3. Important issue? **MEDIUM** — potential deadlock, but unlikely
   trigger
4. Small and contained? **YES** — 1-line change
5. No new features? **YES**
6. Can apply to stable? **YES** — clean apply

**Step 9.3: Exception Categories**
Not an exception category, but meets standard criteria as a small bug
fix.

**Step 9.4: Decision**
The fix is a 1-line change that is obviously correct, with zero
regression risk. It fixes a real (if unlikely to trigger) locking
correctness bug that could lead to deadlock. The cost of inclusion is
negligible, and it makes the code genuinely correct.

## Verification

- [Phase 1] Parsed tags: Reported-by kernel test robot, SOB from fbdev
  maintainer Helge Deller
- [Phase 2] Diff analysis: 1 line changed in error path of
  `omapfb_mmap()`, replacing `ofbi->region` with `rg`
- [Phase 2] Verified `omapfb_get_mem_region()` returns its argument and
  acquires `down_read_nested` (omapfb.h:183-188)
- [Phase 2] Verified `ofbi->region` can be changed concurrently (omapfb-
  ioctl.c:98: `ofbi->region = new_rg`)
- [Phase 3] git blame: buggy line introduced by commit 3ed37d9aba486d
  (2012-12-13, "Revert 'OMAPFB: simplify locking'"), present since ~v3.8
- [Phase 3] File history: no prerequisites needed, standalone fix
- [Phase 4] b4 dig: could not find original submission thread
- [Phase 5] Correct pattern exists in omapfb-sysfs.c:59-73 (uses `rg`
  not `ofbi->region`)
- [Phase 6] Verified buggy code exists in v6.6 stable tree (line 1122)
- [Phase 6] Fix will apply cleanly (1-line change, no surrounding churn)
- [Phase 8] Failure mode: lock corruption + potential deadlock (severity
  HIGH, likelihood LOW)

**YES**

 drivers/video/fbdev/omap2/omapfb/omapfb-main.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/video/fbdev/omap2/omapfb/omapfb-main.c b/drivers/video/fbdev/omap2/omapfb/omapfb-main.c
index a8b2930290e1f..d70deb6a91508 100644
--- a/drivers/video/fbdev/omap2/omapfb/omapfb-main.c
+++ b/drivers/video/fbdev/omap2/omapfb/omapfb-main.c
@@ -1121,7 +1121,7 @@ static int omapfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma)
 	return 0;
 
 error:
-	omapfb_put_mem_region(ofbi->region);
+	omapfb_put_mem_region(rg);
 
 	return r;
 }
-- 
2.53.0


^ permalink raw reply related

* [PATCH AUTOSEL 7.0-5.10] fbdev: viafb: check ioremap return value in viafb_lcd_get_mobile_state
From: Sasha Levin @ 2026-04-20 13:08 UTC (permalink / raw)
  To: patches, stable
  Cc: Wang Jun, Helge Deller, Sasha Levin, FlorianSchandinat,
	linux-fbdev, dri-devel, linux-kernel
In-Reply-To: <20260420131539.986432-1-sashal@kernel.org>

From: Wang Jun <1742789905@qq.com>

[ Upstream commit f044788088ef55e9855b17b7984ffe522c40c093 ]

The function viafb_lcd_get_mobile_state() calls ioremap() without
checking the return value. If ioremap() fails (returns NULL), the
subsequent readw() will cause a NULL pointer dereference.

Signed-off-by: Wang Jun <1742789905@qq.com>
Signed-off-by: Helge Deller <deller@gmx.de>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---

LLM Generated explanations, may be completely bogus:

Now I have all the information needed for the full analysis. Let me
compile it.

---

## PHASE 1: COMMIT MESSAGE FORENSICS

**Step 1.1: Subject Line**
- Subsystem: `fbdev: viafb`
- Action verb: "check" (adding a missing safety check)
- Summary: Adds NULL check for `ioremap()` return value in
  `viafb_lcd_get_mobile_state()`
Record: [fbdev: viafb] [check] [Add missing ioremap NULL check to
prevent NULL deref]

**Step 1.2: Tags**
- Signed-off-by: Wang Jun <1742789905@qq.com> (author)
- Signed-off-by: Helge Deller <deller@gmx.de> (fbdev maintainer,
  committer)
- No Fixes:, Reported-by:, Tested-by:, Link:, or Cc: stable tags
Record: Only author and maintainer SOBs. No Fixes: tag or Reported-by —
this appears to be a code-review/static-analysis finding, not a user-
reported bug.

**Step 1.3: Body Text**
- Bug: `viafb_lcd_get_mobile_state()` calls `ioremap()` without checking
  the return value.
- Symptom: If `ioremap()` returns NULL, the subsequent `readw()` causes
  a NULL pointer dereference.
- Root cause: Missing NULL check.
Record: [NULL pointer dereference if ioremap fails] [kernel oops/crash]
[No version info] [Straightforward missing check]

**Step 1.4: Hidden Bug Fix?**
Yes — this is a genuine bug fix. A missing NULL check before pointer
dereference is a real code defect.
Record: [Yes, this is a missing NULL check for a function that can fail]

---

## PHASE 2: DIFF ANALYSIS

**Step 2.1: Inventory**
- 1 file changed: `drivers/video/fbdev/via/lcd.c`
- +3 lines added (NULL check, `return false`, blank line), 0 removed
- Function modified: `viafb_lcd_get_mobile_state()`
Record: [lcd.c +3/-0] [viafb_lcd_get_mobile_state] [Single-file surgical
fix]

**Step 2.2: Code Flow Change**
- Before: `ioremap()` → immediate `readw(biosptr)` — if biosptr is NULL,
  kernel oops
- After: `ioremap()` → NULL check → return `false` if NULL; otherwise
  proceed normally
Record: [Before: unchecked ioremap -> readw on potential NULL. After:
NULL check added, returns false on failure]

**Step 2.3: Bug Mechanism**
- Category: NULL pointer dereference / memory safety
- The ioremap() call can fail and return NULL. Without a check,
  `readw(biosptr)` dereferences NULL.
Record: [NULL pointer dereference] [Missing ioremap NULL check → readw
on NULL crashes kernel]

**Step 2.4: Fix Quality**
- Obviously correct — standard ioremap error-checking pattern used
  across the kernel
- Minimal — 2 lines of logic
- Return value of `false` is appropriate: the caller in `via_utility.c`
  simply won't set `LCD_Device` in the connect state, which is the
  correct degraded behavior
- Zero regression risk
Record: [Obviously correct, minimal fix, no regression risk]

---

## PHASE 3: GIT HISTORY INVESTIGATION

**Step 3.1: Blame**
The buggy code was introduced in commit `ac6c97e20f1bef` by Joseph Chan
on 2008-10-15 — the original viafb driver submission. This code has
existed since approximately v2.6.28.
Record: [Buggy code from ac6c97e20f1bef (Oct 2008), present since
~v2.6.28]

**Step 3.2: Fixes: Tag**
No Fixes: tag present. Expected for autosel candidates.
Record: [N/A — no Fixes: tag]

**Step 3.3: File History**
Only cosmetic changes in recent years (spelling fix, I2C terminology,
fallthrough macro). The function is completely unchanged since 2011
(`b65d6040e3a7cd` by Stephen Hemminger was the last substantive touch).
Record: [No prerequisites. Completely standalone fix. No series.]

**Step 3.4: Author**
Wang Jun has only 2 commits in the tree. Helge Deller is the fbdev
subsystem maintainer who signed off.
Record: [Author is not a subsystem regular; maintainer (Helge Deller)
signed off]

**Step 3.5: Dependencies**
None — the fix is completely self-contained.
Record: [No dependencies. Applies standalone.]

---

## PHASE 4: MAILING LIST RESEARCH

**Step 4.1-4.5:**
b4 dig failed to find the original patch submission. Lore.kernel.org is
behind Anubis anti-bot protection and could not be fetched. No mailing
list discussion could be reviewed.
Record: [b4 dig: no match found] [Lore: blocked by Anubis] [UNVERIFIED:
Could not review mailing list discussion]

---

## PHASE 5: CODE SEMANTIC ANALYSIS

**Step 5.1: Functions Modified**
`viafb_lcd_get_mobile_state()` — the only function touched.

**Step 5.2: Callers**
- `viafb_lcd_get_mobile_state()` is called from
  `viafb_get_device_connect_state()` in `via_utility.c` (line 31)
- `viafb_get_device_connect_state()` is called from the ioctl handler
  `VIAFB_GET_DEVICE_CONNECT` in `viafbdev.c` (line 558)
- This makes the buggy path **reachable from userspace** via ioctl.
Record: [Call chain: ioctl(VIAFB_GET_DEVICE_CONNECT) →
viafb_get_device_connect_state() → viafb_lcd_get_mobile_state() →
ioremap → readw(NULL)]

**Step 5.3-5.4: Callees/Call Chain**
The function calls `ioremap()`, `readw()`, `readb()`, `iounmap()`. It
maps the VGA BIOS ROM at physical address 0xC0000 to check if the system
is mobile (laptop) hardware.
Record: [ioremap maps VGA BIOS ROM; readw/readb parse BIOS tables]

**Step 5.5: Similar Patterns**
Missing ioremap checks are a common class of bug across the kernel. Many
similar fixes have been applied.
Record: [Common bug pattern - missing ioremap NULL check]

---

## PHASE 6: STABLE TREE ANALYSIS

**Step 6.1: Buggy Code in Stable?**
Yes. The buggy code was introduced in 2008 and is present in ALL active
stable trees. Only cosmetic changes since v5.15 (spelling fix, I2C
terminology).
Record: [Present in all stable trees: 5.10, 5.15, 6.1, 6.6, etc.]

**Step 6.2: Backport Complications**
None. The file has barely changed. The patch should apply cleanly to all
stable trees.
Record: [Clean apply expected in all stable trees]

**Step 6.3: Related Fixes in Stable**
None found. This bug has never been fixed before.
Record: [No related fixes in stable]

---

## PHASE 7: SUBSYSTEM CONTEXT

**Step 7.1: Subsystem Criticality**
- Subsystem: `drivers/video/fbdev` (framebuffer device drivers)
- Sub-subsystem: VIA framebuffer (viafb) — legacy VIA chipset graphics
- Criticality: **PERIPHERAL** — very niche, legacy hardware from
  mid-2000s
Record: [fbdev/viafb, PERIPHERAL criticality]

**Step 7.2: Subsystem Activity**
Very low activity. Last substantive changes to this file were years ago.
The driver is effectively in maintenance-only mode.
Record: [Very low activity — maintenance only]

---

## PHASE 8: IMPACT AND RISK ASSESSMENT

**Step 8.1: Affected Users**
Only users of VIA framebuffer hardware with this specific ioctl call
path.
Record: [Driver-specific, very niche hardware]

**Step 8.2: Trigger Conditions**
- Requires `ioremap(0xC0000, 0x10000)` to fail
- This maps the standard VGA BIOS ROM — on VIA hardware this should
  almost always succeed
- Could theoretically fail under extreme memory pressure
- Reachable from userspace ioctl (unprivileged user could trigger it if
  they have access to the fbdev device)
Record: [Extremely unlikely trigger; ioremap of BIOS ROM address rarely
fails on real hardware]

**Step 8.3: Failure Mode Severity**
- If triggered: NULL pointer dereference → kernel oops/crash
- Severity: **HIGH** if triggered (kernel crash), but probability is
  very low
Record: [Kernel oops, HIGH severity, VERY LOW probability]

**Step 8.4: Risk-Benefit**
- Benefit: LOW-MEDIUM — prevents a theoretical NULL deref on niche
  hardware
- Risk: VERY LOW — 2 lines, obviously correct, zero regression potential
- Ratio: favorable — essentially zero cost to include
Record: [Low benefit, very low risk, favorable ratio]

---

## PHASE 9: FINAL SYNTHESIS

**Step 9.1: Evidence**

FOR backporting:
- Fixes a genuine NULL pointer dereference (kernel crash)
- Extremely small (2 lines of logic) and obviously correct
- Zero regression risk
- Present in all stable trees, applies cleanly
- Code is reachable from userspace via ioctl
- Standard defensive fix pattern used across the kernel

AGAINST backporting:
- Bug has existed since 2008 (~17 years) without any reports
- Target hardware (VIA framebuffer) is extremely niche/legacy
- ioremap(0xC0000) failure on real VIA hardware is near-impossible
- No Reported-by, no syzbot finding, no user complaints
- Appears to be static analysis / code review finding, not a real-world
  bug

**Step 9.2: Stable Rules Checklist**
1. Obviously correct and tested? **YES** — standard ioremap check
   pattern
2. Fixes a real bug? **YES** — missing NULL check is a real code defect,
   though theoretical
3. Important issue? **BORDERLINE** — crash if triggered, but trigger is
   extremely unlikely
4. Small and contained? **YES** — 2 lines, single function
5. No new features or APIs? **YES** — purely defensive
6. Can apply to stable? **YES** — clean apply expected

**Step 9.3: Exception Categories**
None apply.

**Step 9.4: Decision**
This is a borderline case. The fix prevents a genuine NULL pointer
dereference but on a near-impossible code path for niche hardware that
no one has reported in 17 years. However, the fix is so small (2 lines)
and so obviously correct that it carries essentially zero regression
risk. The cost of including it is nil, while it does improve code
correctness and prevents a theoretical kernel crash reachable from
userspace.

---

## Verification

- [Phase 1] Parsed subject: "fbdev: viafb: check ioremap return value" —
  adding missing NULL check
- [Phase 1] Parsed tags: only author SOB and maintainer SOB, no
  Fixes/Reported-by/Cc:stable
- [Phase 2] Diff analysis: +3 lines in viafb_lcd_get_mobile_state(),
  adds NULL check after ioremap(), returns false on failure
- [Phase 2] Verified: readw(biosptr) immediately follows ioremap()
  without check — confirmed NULL deref risk
- [Phase 3] git blame: buggy code introduced in ac6c97e20f1bef (Joseph
  Chan, 2008-10-15), present since ~v2.6.28
- [Phase 3] git log -20: confirmed only cosmetic changes to lcd.c since
  2008
- [Phase 3] git tag --contains: confirmed ac6c97e20f1bef present in
  p-5.10, p-5.15 (all stable trees)
- [Phase 4] b4 dig -c: failed to find matching patch — no lore URL
  available
- [Phase 4] UNVERIFIED: Could not review mailing list discussion due to
  b4 failure and Anubis blocking lore
- [Phase 5] Grep viafb_lcd_get_mobile_state: confirmed call chain ioctl
  → viafb_get_device_connect_state → viafb_lcd_get_mobile_state
- [Phase 5] Verified: VIAFB_GET_DEVICE_CONNECT ioctl at
  viafbdev.c:557-561 makes path reachable from userspace
- [Phase 5] Verified: on ioremap failure, returning false causes caller
  to skip LCD_Device — safe degradation
- [Phase 6] git log v6.6.. and v5.15..: confirmed minimal changes (only
  cosmetic), clean apply expected
- [Phase 8] Trigger analysis: ioremap(0xC0000, 0x10000) maps standard
  VGA BIOS ROM; failure is extremely unlikely on real VIA hardware

**YES**

 drivers/video/fbdev/via/lcd.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/video/fbdev/via/lcd.c b/drivers/video/fbdev/via/lcd.c
index 8673fced87492..3fa2304fbda7e 100644
--- a/drivers/video/fbdev/via/lcd.c
+++ b/drivers/video/fbdev/via/lcd.c
@@ -954,6 +954,9 @@ bool viafb_lcd_get_mobile_state(bool *mobile)
 	u16 start_pattern;
 
 	biosptr = ioremap(romaddr, 0x10000);
+	if (!biosptr)
+		return false;
+
 	start_pattern = readw(biosptr);
 
 	/* Compare pattern */
-- 
2.53.0


^ permalink raw reply related

* Re: [PATCH] staging: fbtft: fix coding style issue in fbtft-bus.c
From: Greg KH @ 2026-04-20  9:29 UTC (permalink / raw)
  To: Baker; +Cc: andy, dri-devel, linux-fbdev, linux-staging, linux-kernel
In-Reply-To: <20260412172147.2817-1-mzndmzn@gmail.com>

On Sun, Apr 12, 2026 at 12:21:46PM -0500, Baker wrote:
> Remove trailing space and comma before closing parenthesis ')' in
> define_fbtft_write_reg macro as reported by checkpatch.pl.
> 
> Signed-off-by: Baker <mzndmzn@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 30e436ff19e4..409770891c54 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.47.3
> 
> 

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 multiple patches, yet no indication of which ones should be
  applied in which order.  Greg could just guess, but if you are
  receiving this email, he guessed wrong and the patches didn't apply.
  Please read the section entitled "The canonical patch format" in the
  kernel file, Documentation/process/submitting-patches.rst for a
  description of how to do this so that Greg has a chance to apply these
  correctly.

- It looks like you did not use your "real" name for the patch on either
  the Signed-off-by: line, or the From: line (both of which have to
  match).  Please read the kernel file,
  Documentation/process/submitting-patches.rst for how to do this
  correctly.

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

* Re: [PATCH v3] staging: fbtft: replace empty macro args with identity converter
From: Greg KH @ 2026-04-20  9:29 UTC (permalink / raw)
  To: Baker; +Cc: andy, dri-devel, linux-fbdev, linux-staging, linux-kernel
In-Reply-To: <20260412173317.3329-2-mzndmzn@gmail.com>

On Sun, Apr 12, 2026 at 12:33:17PM -0500, Baker wrote:
> The define_fbtft_write_reg macro calls 'modifier' as a function.
> Passing an empty token as modifier is undefined behavior in C for
> fixed-arity macros. Introduce fbtft_no_conv() as an identity
> function to replace the empty args in the no-conversion cases.
> 
> Signed-off-by: Baker <mzndmzn@gmail.com>
> ---
>  drivers/staging/fbtft/fbtft-bus.c | 6 ++++--
>  1 file changed, 4 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/staging/fbtft/fbtft-bus.c b/drivers/staging/fbtft/fbtft-bus.c
> index 30e436ff19e4..7f3fd30576ab 100644
> --- a/drivers/staging/fbtft/fbtft-bus.c
> +++ b/drivers/staging/fbtft/fbtft-bus.c
> @@ -11,6 +11,8 @@
>   *
>   *****************************************************************************/
>  
> +#define fbtft_no_conv(x) (x)
> +
>  #define define_fbtft_write_reg(func, buffer_type, data_type, modifier)        \
>  void func(struct fbtft_par *par, int len, ...)                                \
>  {                                                                             \
> @@ -62,9 +64,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, fbtft_no_conv)
>  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, fbtft_no_conv)
>  
>  void fbtft_write_reg8_bus9(struct fbtft_par *par, int len, ...)
>  {
> -- 
> 2.47.3
> 
> 

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:

- It looks like you did not use your "real" name for the patch on either
  the Signed-off-by: line, or the From: line (both of which have to
  match).  Please read the kernel file,
  Documentation/process/submitting-patches.rst for how to do this
  correctly.

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

* [syzbot] Monthly fbdev report (Apr 2026)
From: syzbot @ 2026-04-20  7:05 UTC (permalink / raw)
  To: deller, dri-devel, linux-fbdev, linux-kernel, syzkaller-bugs

Hello fbdev maintainers/developers,

This is a 31-day syzbot report for the fbdev subsystem.
All related reports/information can be found at:
https://syzkaller.appspot.com/upstream/s/fbdev

During the period, 0 new issues were detected and 0 were fixed.
In total, 5 issues are still open and 29 have already been fixed.

Some of the still happening issues:

Ref Crashes Repro Title
<1> 3325    Yes   KASAN: vmalloc-out-of-bounds Write in imageblit (6)
                  https://syzkaller.appspot.com/bug?extid=5a40432dfe8f86ee657a
<2> 1534    Yes   KASAN: slab-out-of-bounds Read in fbcon_prepare_logo
                  https://syzkaller.appspot.com/bug?extid=0c815b25cdb3678e7083
<3> 229     No    KASAN: vmalloc-out-of-bounds Write in fillrect
                  https://syzkaller.appspot.com/bug?extid=7a63ce155648954e749b
<4> 1       Yes   memory leak in fbcon_set_font (3)
                  https://syzkaller.appspot.com/bug?extid=6fda7f092994bd03fad1

---
This report is generated by a bot. It may contain errors.
See https://goo.gl/tpsmEJ for more information about syzbot.
syzbot engineers can be reached at syzkaller@googlegroups.com.

To disable reminders for individual bugs, reply with the following command:
#syz set <Ref> no-reminders

To change bug's subsystems, reply with:
#syz set <Ref> subsystems: new-subsystem

You may send multiple commands in a single email message.

^ permalink raw reply

* [PATCH v1] fbdev: savage: fix probe-path EDID cleanup leaks
From: Yuho Choi @ 2026-04-20  5:19 UTC (permalink / raw)
  To: Antonino Daplas, Helge Deller, linux-fbdev
  Cc: dri-devel, linux-kernel, Myeonghun Pak, Ijae Kim, Taegyu Kim,
	Yuho Choi

When CONFIG_FB_SAVAGE_I2C is enabled, savagefb_probe() can build both an
EDID-derived monspecs.modedb and a modelist from it before later
failing.

The normal success path frees monspecs.modedb after the initial mode
selection, but the probe error path only deletes the I2C busses and
misses the EDID-derived allocations.

Free both the modelist and monspecs.modedb on the failed: unwind path.

Co-developed-by: Myeonghun Pak <mhun512@gmail.com>
Signed-off-by: Myeonghun Pak <mhun512@gmail.com>
Co-developed-by: Ijae Kim <ae878000@gmail.com>
Signed-off-by: Ijae Kim <ae878000@gmail.com>
Co-developed-by: Taegyu Kim <tmk5904@psu.edu>
Signed-off-by: Taegyu Kim <tmk5904@psu.edu>
Signed-off-by: Yuho Choi <dbgh9129@gmail.com>
---
 drivers/video/fbdev/savage/savagefb_driver.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/video/fbdev/savage/savagefb_driver.c b/drivers/video/fbdev/savage/savagefb_driver.c
index ac41f8f37589f..c2f79357c8da0 100644
--- a/drivers/video/fbdev/savage/savagefb_driver.c
+++ b/drivers/video/fbdev/savage/savagefb_driver.c
@@ -2322,6 +2322,8 @@ static int savagefb_probe(struct pci_dev *dev, const struct pci_device_id *id)
  failed:
 #ifdef CONFIG_FB_SAVAGE_I2C
 	savagefb_delete_i2c_busses(info);
+	fb_destroy_modelist(&info->modelist);
+	fb_destroy_modedb(info->monspecs.modedb);
 #endif
 	fb_alloc_cmap(&info->cmap, 0, 0);
 	savage_unmap_video(info);
-- 
2.50.1 (Apple Git-155)


^ permalink raw reply related

* [PATCH v1] fbdev/offb: fix PCI device reference leak on probe failure
From: Yuho Choi @ 2026-04-20  1:01 UTC (permalink / raw)
  To: Helge Deller, Jason Donenfeld, linux-fbdev
  Cc: dri-devel, linux-kernel, Myeonghun Pak, Ijae Kim, Taegyu Kim,
	Yuho Choi

offb_init_nodriver() gets a referenced PCI device with
pci_get_device(). If pci_enable_device() fails, the function returns
without dropping that reference.

Release the PCI device reference before returning from the
pci_enable_device() failure path.

Fixes: 5bda8f7b5468 ("video: fbdev: offb: Call pci_enable_device() before using the PCI VGA device")
Co-developed-by: Myeonghun Pak <mhun512@gmail.com>
Signed-off-by: Myeonghun Pak <mhun512@gmail.com>
Co-developed-by: Ijae Kim <ae878000@gmail.com>
Signed-off-by: Ijae Kim <ae878000@gmail.com>
Co-developed-by: Taegyu Kim <tmk5904@psu.edu>
Signed-off-by: Taegyu Kim <tmk5904@psu.edu>
Signed-off-by: Yuho Choi <dbgh9129@gmail.com>
---
 drivers/video/fbdev/offb.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/drivers/video/fbdev/offb.c b/drivers/video/fbdev/offb.c
index f85428e13996b..166b2dff36f59 100644
--- a/drivers/video/fbdev/offb.c
+++ b/drivers/video/fbdev/offb.c
@@ -640,8 +640,13 @@ static void offb_init_nodriver(struct platform_device *parent, struct device_nod
 			vid = be32_to_cpup(vidp);
 			did = be32_to_cpup(didp);
 			pdev = pci_get_device(vid, did, NULL);
-			if (!pdev || pci_enable_device(pdev))
+			if (!pdev)
 				return;
+
+			if (pci_enable_device(pdev)) {
+				pci_dev_put(pdev);
+				return;
+			}
 		}
 #endif
 		/* kludge for valkyrie */
-- 
2.50.1 (Apple Git-155)


^ 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