mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH] drm/nouveau/disp: Prevent division-by-zero during DisplayPort link training transitions
@ 2026-07-16 14:55 Arjan Filius
  2026-07-16 20:40 ` lyude
  0 siblings, 1 reply; 3+ messages in thread
From: Arjan Filius @ 2026-07-16 14:55 UTC (permalink / raw)
  To: Lyude Paul, Danilo Krummrich; +Cc: nouveau, dri-devel, linux-kernel

Dear Nouveau Maintainers,
 
Please find below a proposed patch to prevent a division-by-zero kernel oops and subsequent lockup in the Nouveau display supervisor engine when DisplayPort links transition to 0 active lanes. This bug was observed and patched/tested against the mainline kernel version **7.1.3**, but is present in all current upstream code.
 
---
 
### BRIEF EXPLANATION
 
During screen sleep transitions or multi-input display switches (KVM switching), the active lane count of a DisplayPort link can temporarily drop to 0 (`ior->dp.nr == 0`). 
 
When this occurs, the DisplayPort supervisor function `nv50_disp_super_2_2_dp` is invoked via modeset interrupts. Without an early-exit guard, the function attempts to perform symbols/hblank and link rate calculations that divide by `ior->dp.nr`, resulting in a kernel division-by-zero math exception, lockup, and system freeze.
 
This patch adds an early-exit check at the beginning of `nv50_disp_super_2_2_dp` to abort display configuration when the link training lanes count is zero.

*   **Tested Kernel Version:** `7.1.3` (mainline stable branch)

---

### EXTREMELY DETAILED TECHNICAL BREAKDOWN

#### 1. Hardware Context
This bug has been consistently reproduced on a Lenovo ThinkPad T430 (Intel HD 4000 + discrete NVIDIA NVS 5400M / GF108 chipset) connected to a Lenovo ThinkPad Mini Dock Plus Series 3 (Model 4338) with dual external monitors on dock DisplayPorts (`DP-2` and `DP-3`). 

#### 2. Root Cause Analysis (Code Level)
Inside `drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c`, when `ior->dp.nr == 0`, the driver executes the following lines in `nv50_disp_super_2_2_dp()`:

*   **Line 1179:** Calculations for horizontal blank symbols:
    ```c
    h = h - (3 * ior->dp.ef) - (12 / ior->dp.nr);
    ```
*   **Line 1185:** Calculations for vertical blank symbols:
    ```c
    v = v - ((36 / ior->dp.nr) + 3) - 1;
    ```
*   **Line 1190:** Calculations for active link data rate:
    ```c
    link_data_rate = (khz * head->asy.or.depth / 8) / ior->dp.nr;
    ```

In all three instances, the denominator `ior->dp.nr` is `0`, causing an immediate kernel math exception in the display workqueue (`nouveau_display_hpd_work` or `nv50_disp_super`), locking up the graphics pipeline, freezing the screen, and hanging any reboot attempts (requiring a physical hard reset).

#### 3. Daily Workday Trigger Scenario
1.  The T430 (via dock) and a secondary workstation are both connected to different inputs on the same external monitors.
2.  The monitors' input sources are switched to the secondary workstation.
3.  At the end of the day, the secondary workstation goes to sleep or is shut down.
4.  With no active inputs, the external monitors enter power-saving standby mode.
5.  When the user subsequently wakes up or interacts with the T430, the driver attempts a modeset refresh. Since the monitors are asleep and inputs are switched away, the lanes count is read as `0`, triggering the division-by-zero oops.

#### 4. Stack Trace (Oops Log)
```text
[di jul 23 10:28:25 2024] nouveau 0000:01:00.0: DRM: DDC responded, but no EDID for DP-2
[di jul 23 10:28:25 2024] nouveau 0000:01:00.0: DRM: DDC responded, but no EDID for DP-3
[di jul 23 10:28:26 2024] Workqueue: nvkm-disp nv50_disp_super [nouveau]
[di jul 23 10:28:26 2024] RIP: 0010:nv50_disp_super_2_2_dp+0xa7/0x320 [nouveau]
[di jul 23 10:28:26 2024]  ? nv50_disp_super_2_2_dp+0xa7/0x320 [nouveau]
[di jul 23 10:28:26 2024]  nv50_disp_super_2_2+0xf2/0x160 [nouveau]
[di jul 23 10:28:26 2024]  nv50_disp_super+0x139/0x280 [nouveau]
```

#### 5. Verification Proof (Bypass Log)
With the patch applied and running on kernel `7.1.3-custom #2`, the screen standby transition was bypassed cleanly. The driver caught the lane count of 0, bypassed display configuration, and proceeded to put the graphics chip into its low-power runtime suspend state (`suspended`) without locking up the OS:
```text
[45162.232371] nouveau 0000:01:00.0: disp: DP link is inactive (lanes = 0), skipping display configuration.
[45162.232402] nouveau 0000:01:00.0: disp: DP link is inactive (lanes = 0), skipping display configuration.
[45178.605627] nouveau 0000:01:00.0: timeout
[45178.605629] WARNING: nv50_disp_dmac_fini+0x168/0x1c0 [nouveau]
[45180.608524] nouveau 0000:01:00.0: disp: ch 1 fini timeout, 8e061008
[45182.608521] nouveau 0000:01:00.0: timeout
[45182.608523] WARNING: nv50_disp_core_fini+0x143/0x190 [nouveau]
```

---

Signed-off-by: Arjan Filius <iafilius@xs4all.nl>
---

### CHOOSE ONE OF THE PATCH OPTIONS BELOW TO APPEND:

#### OPTION A: The Silent Production Patch (RECOMMENDED FOR UPSTREAM)
*Note: Kernel maintainers generally reject warnings or print spam for expected hardware sleep/disconnect transitions. A silent return is the preferred upstream pattern.*

```diff
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c
index 51c045bdfcbb..ab1bc0898def 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c
@@ -1157,6 +1157,10 @@ nv50_disp_super_2_2_dp(struct nvkm_head *head, struct nvkm_ior *ior)
 {
 	struct nvkm_subdev *subdev = &head->disp->engine.subdev;
 
+	/* If the DisplayPort link is inactive (0 lanes), skip configuration */
+	if (ior->dp.nr == 0)
+		return;
+
 	const u32 khz = head->asy.hz / 1000;
 	const u32 linkKBps = ior->dp.bw * 27000;
 	const u32 symbol = 100000;
```

#### OPTION B: The Warning/Verbose Patch (What was tested locally)
*Note: Prints warning logs to the kernel buffer for validation and troubleshooting.*

```diff
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c
index 51c045bdfcbb..ab1bc0898def 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c
@@ -1157,6 +1157,12 @@ nv50_disp_super_2_2_dp(struct nvkm_head *head, struct nvkm_ior *ior)
 {
 	struct nvkm_subdev *subdev = &head->disp->engine.subdev;
 
+	/* If the DisplayPort link is inactive (0 lanes), skip configuration */
+	if (ior->dp.nr == 0) {
+		nvkm_warn(subdev, "DP link is inactive (lanes = 0), skipping display configuration.\n");
+		return;
+	}
+
 	const u32 khz = head->asy.hz / 1000;
 	const u32 linkKBps = ior->dp.bw * 27000;
 	const u32 symbol = 100000;
```


^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH] drm/nouveau/disp: Prevent division-by-zero during DisplayPort link training transitions
  2026-07-16 14:55 [PATCH] drm/nouveau/disp: Prevent division-by-zero during DisplayPort link training transitions Arjan Filius
@ 2026-07-16 20:40 ` lyude
  2026-07-17  8:15   ` Arjan Filius
  0 siblings, 1 reply; 3+ messages in thread
From: lyude @ 2026-07-16 20:40 UTC (permalink / raw)
  To: Arjan Filius, Danilo Krummrich; +Cc: nouveau, dri-devel, linux-kernel

Hi, can you please clarify whether or not you used generative AI for
this patch series? If so, this needs to be noted as part of the commit
message. Additionally, both of these patches look to be identical
except that one prints a message and the other doesn't. You can just
send a single version, we will figure out how to handle that part
after.

On Thu, 2026-07-16 at 16:55 +0200, Arjan Filius wrote:
> Dear Nouveau Maintainers,
>  
> Please find below a proposed patch to prevent a division-by-zero
> kernel oops and subsequent lockup in the Nouveau display supervisor
> engine when DisplayPort links transition to 0 active lanes. This bug
> was observed and patched/tested against the mainline kernel version
> **7.1.3**, but is present in all current upstream code.
>  
> ---
>  
> ### BRIEF EXPLANATION
>  
> During screen sleep transitions or multi-input display switches (KVM
> switching), the active lane count of a DisplayPort link can
> temporarily drop to 0 (`ior->dp.nr == 0`). 
>  
> When this occurs, the DisplayPort supervisor function
> `nv50_disp_super_2_2_dp` is invoked via modeset interrupts. Without
> an early-exit guard, the function attempts to perform symbols/hblank
> and link rate calculations that divide by `ior->dp.nr`, resulting in
> a kernel division-by-zero math exception, lockup, and system freeze.
>  
> This patch adds an early-exit check at the beginning of
> `nv50_disp_super_2_2_dp` to abort display configuration when the link
> training lanes count is zero.
> 
> *   **Tested Kernel Version:** `7.1.3` (mainline stable branch)
> 
> ---
> 
> ### EXTREMELY DETAILED TECHNICAL BREAKDOWN
> 
> #### 1. Hardware Context
> This bug has been consistently reproduced on a Lenovo ThinkPad T430
> (Intel HD 4000 + discrete NVIDIA NVS 5400M / GF108 chipset) connected
> to a Lenovo ThinkPad Mini Dock Plus Series 3 (Model 4338) with dual
> external monitors on dock DisplayPorts (`DP-2` and `DP-3`). 
> 
> #### 2. Root Cause Analysis (Code Level)
> Inside `drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c`, when `ior-
> >dp.nr == 0`, the driver executes the following lines in
> `nv50_disp_super_2_2_dp()`:
> 
> *   **Line 1179:** Calculations for horizontal blank symbols:
>     ```c
>     h = h - (3 * ior->dp.ef) - (12 / ior->dp.nr);
>     ```
> *   **Line 1185:** Calculations for vertical blank symbols:
>     ```c
>     v = v - ((36 / ior->dp.nr) + 3) - 1;
>     ```
> *   **Line 1190:** Calculations for active link data rate:
>     ```c
>     link_data_rate = (khz * head->asy.or.depth / 8) / ior->dp.nr;
>     ```
> 
> In all three instances, the denominator `ior->dp.nr` is `0`, causing
> an immediate kernel math exception in the display workqueue
> (`nouveau_display_hpd_work` or `nv50_disp_super`), locking up the
> graphics pipeline, freezing the screen, and hanging any reboot
> attempts (requiring a physical hard reset).
> 
> #### 3. Daily Workday Trigger Scenario
> 1.  The T430 (via dock) and a secondary workstation are both
> connected to different inputs on the same external monitors.
> 2.  The monitors' input sources are switched to the secondary
> workstation.
> 3.  At the end of the day, the secondary workstation goes to sleep or
> is shut down.
> 4.  With no active inputs, the external monitors enter power-saving
> standby mode.
> 5.  When the user subsequently wakes up or interacts with the T430,
> the driver attempts a modeset refresh. Since the monitors are asleep
> and inputs are switched away, the lanes count is read as `0`,
> triggering the division-by-zero oops.
> 
> #### 4. Stack Trace (Oops Log)
> ```text
> [di jul 23 10:28:25 2024] nouveau 0000:01:00.0: DRM: DDC responded,
> but no EDID for DP-2
> [di jul 23 10:28:25 2024] nouveau 0000:01:00.0: DRM: DDC responded,
> but no EDID for DP-3
> [di jul 23 10:28:26 2024] Workqueue: nvkm-disp nv50_disp_super
> [nouveau]
> [di jul 23 10:28:26 2024] RIP: 0010:nv50_disp_super_2_2_dp+0xa7/0x320
> [nouveau]
> [di jul 23 10:28:26 2024]  ? nv50_disp_super_2_2_dp+0xa7/0x320
> [nouveau]
> [di jul 23 10:28:26 2024]  nv50_disp_super_2_2+0xf2/0x160 [nouveau]
> [di jul 23 10:28:26 2024]  nv50_disp_super+0x139/0x280 [nouveau]
> ```
> 
> #### 5. Verification Proof (Bypass Log)
> With the patch applied and running on kernel `7.1.3-custom #2`, the
> screen standby transition was bypassed cleanly. The driver caught the
> lane count of 0, bypassed display configuration, and proceeded to put
> the graphics chip into its low-power runtime suspend state
> (`suspended`) without locking up the OS:
> ```text
> [45162.232371] nouveau 0000:01:00.0: disp: DP link is inactive (lanes
> = 0), skipping display configuration.
> [45162.232402] nouveau 0000:01:00.0: disp: DP link is inactive (lanes
> = 0), skipping display configuration.
> [45178.605627] nouveau 0000:01:00.0: timeout
> [45178.605629] WARNING: nv50_disp_dmac_fini+0x168/0x1c0 [nouveau]
> [45180.608524] nouveau 0000:01:00.0: disp: ch 1 fini timeout,
> 8e061008
> [45182.608521] nouveau 0000:01:00.0: timeout
> [45182.608523] WARNING: nv50_disp_core_fini+0x143/0x190 [nouveau]
> ```
> 
> ---
> 
> Signed-off-by: Arjan Filius <iafilius@xs4all.nl>
> ---
> 
> ### CHOOSE ONE OF THE PATCH OPTIONS BELOW TO APPEND:
> 
> #### OPTION A: The Silent Production Patch (RECOMMENDED FOR UPSTREAM)
> *Note: Kernel maintainers generally reject warnings or print spam for
> expected hardware sleep/disconnect transitions. A silent return is
> the preferred upstream pattern.*
> 
> ```diff
> diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c
> b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c
> index 51c045bdfcbb..ab1bc0898def 100644
> --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c
> +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c
> @@ -1157,6 +1157,10 @@ nv50_disp_super_2_2_dp(struct nvkm_head *head,
> struct nvkm_ior *ior)
>  {
>  	struct nvkm_subdev *subdev = &head->disp->engine.subdev;
>  
> +	/* If the DisplayPort link is inactive (0 lanes), skip
> configuration */
> +	if (ior->dp.nr == 0)
> +		return;
> +
>  	const u32 khz = head->asy.hz / 1000;
>  	const u32 linkKBps = ior->dp.bw * 27000;
>  	const u32 symbol = 100000;
> ```
> 
> #### OPTION B: The Warning/Verbose Patch (What was tested locally)
> *Note: Prints warning logs to the kernel buffer for validation and
> troubleshooting.*
> 
> ```diff
> diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c
> b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c
> index 51c045bdfcbb..ab1bc0898def 100644
> --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c
> +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c
> @@ -1157,6 +1157,12 @@ nv50_disp_super_2_2_dp(struct nvkm_head *head,
> struct nvkm_ior *ior)
>  {
>  	struct nvkm_subdev *subdev = &head->disp->engine.subdev;
>  
> +	/* If the DisplayPort link is inactive (0 lanes), skip
> configuration */
> +	if (ior->dp.nr == 0) {
> +		nvkm_warn(subdev, "DP link is inactive (lanes = 0),
> skipping display configuration.\n");
> +		return;
> +	}
> +
>  	const u32 khz = head->asy.hz / 1000;
>  	const u32 linkKBps = ior->dp.bw * 27000;
>  	const u32 symbol = 100000;
> ```


^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH] drm/nouveau/disp: Prevent division-by-zero during DisplayPort link training transitions
  2026-07-16 20:40 ` lyude
@ 2026-07-17  8:15   ` Arjan Filius
  0 siblings, 0 replies; 3+ messages in thread
From: Arjan Filius @ 2026-07-17  8:15 UTC (permalink / raw)
  To: lyude; +Cc: Danilo Krummrich, nouveau, dri-devel, linux-kernel

Hello Lyude,

Yes, I did use generative AI to help refine and structure this (old) patch.
It is completely based on work/debug/fixing I had done manually few years back. 
Generative AI helped me to send the message, but re-used my old patched code, brushed up a bit.
And tested it this week on kernel 7.1.3, but previous tested on 6.8.0.x and 6.9.9 kernels.

In 2024 i submitted a bug report/fix/workaround (to prevent a full lockup every day) on the Freedesktop GitLab under Issue 377:
https://gitlab.freedesktop.org/drm/nouveau/-/issues/377

Back then, my local workaround was a bit less elegant, and had a few extra checks/debug statements.
I had almost forgotten about the issue since my workaround was running fine.
When I recently booted up a clean mainline 7.1.3 kernel and saw the system freeze again within a day and every day, 
and had to fsck my disks due to it, I remembered the fix I once debugged and posted in 2024. 
I wanted to see if I could find a cleaner, more elegant solution and used AI for it, to see if the patch could be in a nicer place, 
but ended up to basically reproduce the fix i had written in 2024 (without AI).


Regarding the two patches (A and B): 
* **Patch B** was the version I compiled and tested locally with the `nvkm_warn()` statement
  so I could verify in `dmesg` that the standby transitions were actually triggering the block and being safely bypassed.
* **Patch A** is the exact same check but silent (without the warning logs).

To avoid any confusion i repeat my patch, which does not produce any logging every time, 
but just avoids the lockup referencing null pointers when external displays goes to sleep.


```diff
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c
index 51c045bdfcbb..ab1bc0898def 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c
@@ -1157,6 +1157,10 @@ nv50_disp_super_2_2_dp(struct nvkm_head *head, struct nvkm_ior *ior)
 {
 	struct nvkm_subdev *subdev = &head->disp->engine.subdev;
 
+	/* If the DisplayPort link is inactive (0 lanes), skip configuration */
+	if (ior->dp.nr == 0)
+		return;
+
 	const u32 khz = head->asy.hz / 1000;
 	const u32 linkKBps = ior->dp.bw * 27000;
 	const u32 symbol = 100000;
```

This completely fixes my lenovo T430(NVIDIA NVS 5400M) + 4338 Dock and 2 external (multi-input) monitors freeze, proven over some years.
At the time the nvidia kernel driver on my T430 became an issue wih newer kernels, and notice nouveau driver did pretty well too.

Hope this claries it.

Best regards,
Arjan Filius


> On 16 Jul 2026, at 22:40, lyude@redhat.com wrote:
> 
> Hi, can you please clarify whether or not you used generative AI for
> this patch series? If so, this needs to be noted as part of the commit
> message. Additionally, both of these patches look to be identical
> except that one prints a message and the other doesn't. You can just
> send a single version, we will figure out how to handle that part
> after.
> 
> On Thu, 2026-07-16 at 16:55 +0200, Arjan Filius wrote:
>> Dear Nouveau Maintainers,
>>  
>> Please find below a proposed patch to prevent a division-by-zero
>> kernel oops and subsequent lockup in the Nouveau display supervisor
>> engine when DisplayPort links transition to 0 active lanes. This bug
>> was observed and patched/tested against the mainline kernel version
>> **7.1.3**, but is present in all current upstream code.
>>  
>> ---
>>  
>> ### BRIEF EXPLANATION
>>  
>> During screen sleep transitions or multi-input display switches (KVM
>> switching), the active lane count of a DisplayPort link can
>> temporarily drop to 0 (`ior->dp.nr == 0`). 
>>  
>> When this occurs, the DisplayPort supervisor function
>> `nv50_disp_super_2_2_dp` is invoked via modeset interrupts. Without
>> an early-exit guard, the function attempts to perform symbols/hblank
>> and link rate calculations that divide by `ior->dp.nr`, resulting in
>> a kernel division-by-zero math exception, lockup, and system freeze.
>>  
>> This patch adds an early-exit check at the beginning of
>> `nv50_disp_super_2_2_dp` to abort display configuration when the link
>> training lanes count is zero.
>> 
>> *   **Tested Kernel Version:** `7.1.3` (mainline stable branch)
>> 
>> ---
>> 
>> ### EXTREMELY DETAILED TECHNICAL BREAKDOWN
>> 
>> #### 1. Hardware Context
>> This bug has been consistently reproduced on a Lenovo ThinkPad T430
>> (Intel HD 4000 + discrete NVIDIA NVS 5400M / GF108 chipset) connected
>> to a Lenovo ThinkPad Mini Dock Plus Series 3 (Model 4338) with dual
>> external monitors on dock DisplayPorts (`DP-2` and `DP-3`). 
>> 
>> #### 2. Root Cause Analysis (Code Level)
>> Inside `drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c`, when `ior-
>>> dp.nr == 0`, the driver executes the following lines in
>> `nv50_disp_super_2_2_dp()`:
>> 
>> *   **Line 1179:** Calculations for horizontal blank symbols:
>>     ```c
>>     h = h - (3 * ior->dp.ef) - (12 / ior->dp.nr);
>>     ```
>> *   **Line 1185:** Calculations for vertical blank symbols:
>>     ```c
>>     v = v - ((36 / ior->dp.nr) + 3) - 1;
>>     ```
>> *   **Line 1190:** Calculations for active link data rate:
>>     ```c
>>     link_data_rate = (khz * head->asy.or.depth / 8) / ior->dp.nr;
>>     ```
>> 
>> In all three instances, the denominator `ior->dp.nr` is `0`, causing
>> an immediate kernel math exception in the display workqueue
>> (`nouveau_display_hpd_work` or `nv50_disp_super`), locking up the
>> graphics pipeline, freezing the screen, and hanging any reboot
>> attempts (requiring a physical hard reset).
>> 
>> #### 3. Daily Workday Trigger Scenario
>> 1.  The T430 (via dock) and a secondary workstation are both
>> connected to different inputs on the same external monitors.
>> 2.  The monitors' input sources are switched to the secondary
>> workstation.
>> 3.  At the end of the day, the secondary workstation goes to sleep or
>> is shut down.
>> 4.  With no active inputs, the external monitors enter power-saving
>> standby mode.
>> 5.  When the user subsequently wakes up or interacts with the T430,
>> the driver attempts a modeset refresh. Since the monitors are asleep
>> and inputs are switched away, the lanes count is read as `0`,
>> triggering the division-by-zero oops.
>> 
>> #### 4. Stack Trace (Oops Log)
>> ```text
>> [di jul 23 10:28:25 2024] nouveau 0000:01:00.0: DRM: DDC responded,
>> but no EDID for DP-2
>> [di jul 23 10:28:25 2024] nouveau 0000:01:00.0: DRM: DDC responded,
>> but no EDID for DP-3
>> [di jul 23 10:28:26 2024] Workqueue: nvkm-disp nv50_disp_super
>> [nouveau]
>> [di jul 23 10:28:26 2024] RIP: 0010:nv50_disp_super_2_2_dp+0xa7/0x320
>> [nouveau]
>> [di jul 23 10:28:26 2024]  ? nv50_disp_super_2_2_dp+0xa7/0x320
>> [nouveau]
>> [di jul 23 10:28:26 2024]  nv50_disp_super_2_2+0xf2/0x160 [nouveau]
>> [di jul 23 10:28:26 2024]  nv50_disp_super+0x139/0x280 [nouveau]
>> ```
>> 
>> #### 5. Verification Proof (Bypass Log)
>> With the patch applied and running on kernel `7.1.3-custom #2`, the
>> screen standby transition was bypassed cleanly. The driver caught the
>> lane count of 0, bypassed display configuration, and proceeded to put
>> the graphics chip into its low-power runtime suspend state
>> (`suspended`) without locking up the OS:
>> ```text
>> [45162.232371] nouveau 0000:01:00.0: disp: DP link is inactive (lanes
>> = 0), skipping display configuration.
>> [45162.232402] nouveau 0000:01:00.0: disp: DP link is inactive (lanes
>> = 0), skipping display configuration.
>> [45178.605627] nouveau 0000:01:00.0: timeout
>> [45178.605629] WARNING: nv50_disp_dmac_fini+0x168/0x1c0 [nouveau]
>> [45180.608524] nouveau 0000:01:00.0: disp: ch 1 fini timeout,
>> 8e061008
>> [45182.608521] nouveau 0000:01:00.0: timeout
>> [45182.608523] WARNING: nv50_disp_core_fini+0x143/0x190 [nouveau]
>> ```
>> 
>> ---
>> 
>> Signed-off-by: Arjan Filius <iafilius@xs4all.nl>
>> ---
>> 
>> ### CHOOSE ONE OF THE PATCH OPTIONS BELOW TO APPEND:
>> 
>> #### OPTION A: The Silent Production Patch (RECOMMENDED FOR UPSTREAM)
>> *Note: Kernel maintainers generally reject warnings or print spam for
>> expected hardware sleep/disconnect transitions. A silent return is
>> the preferred upstream pattern.*
>> 
>> ```diff
>> diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c
>> b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c
>> index 51c045bdfcbb..ab1bc0898def 100644
>> --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c
>> +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c
>> @@ -1157,6 +1157,10 @@ nv50_disp_super_2_2_dp(struct nvkm_head *head,
>> struct nvkm_ior *ior)
>>  {
>>  	struct nvkm_subdev *subdev = &head->disp->engine.subdev;
>>  
>> +	/* If the DisplayPort link is inactive (0 lanes), skip
>> configuration */
>> +	if (ior->dp.nr == 0)
>> +		return;
>> +
>>  	const u32 khz = head->asy.hz / 1000;
>>  	const u32 linkKBps = ior->dp.bw * 27000;
>>  	const u32 symbol = 100000;
>> ```
>> 
>> #### OPTION B: The Warning/Verbose Patch (What was tested locally)
>> *Note: Prints warning logs to the kernel buffer for validation and
>> troubleshooting.*
>> 
>> ```diff
>> diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c
>> b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c
>> index 51c045bdfcbb..ab1bc0898def 100644
>> --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c
>> +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c
>> @@ -1157,6 +1157,12 @@ nv50_disp_super_2_2_dp(struct nvkm_head *head,
>> struct nvkm_ior *ior)
>>  {
>>  	struct nvkm_subdev *subdev = &head->disp->engine.subdev;
>>  
>> +	/* If the DisplayPort link is inactive (0 lanes), skip
>> configuration */
>> +	if (ior->dp.nr == 0) {
>> +		nvkm_warn(subdev, "DP link is inactive (lanes = 0),
>> skipping display configuration.\n");
>> +		return;
>> +	}
>> +
>>  	const u32 khz = head->asy.hz / 1000;
>>  	const u32 linkKBps = ior->dp.bw * 27000;
>>  	const u32 symbol = 100000;
>> ```
> 


^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2026-07-17  8:15 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-07-16 14:55 [PATCH] drm/nouveau/disp: Prevent division-by-zero during DisplayPort link training transitions Arjan Filius
2026-07-16 20:40 ` lyude
2026-07-17  8:15   ` Arjan Filius

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