Re: [REGRESSION] Display freeze on VT switch back to X11 since v6.16
From: Thorsten Leemhuis
Date: Mon Feb 23 2026 - 03:27:19 EST
On 2/23/26 09:10, Ricardo Ribalda wrote:
> Hi Andrés
>
> Thanks for doing the bisecting
>
> On Sun, 22 Feb 2026 at 22:56, Andrés Pérez <andres.f.perez@xxxxxxxxx> wrote:
>>
>> # OVERVIEW
>>
>> Since kernel v6.16.1, switching from an X11 session to a text VT and back
>> freezes the display on a ThinkPad P15 Gen 2. The system remains responsive
>> over SSH; only the display is frozen. Bisecting identified commit
>> d1b618e7954802fe ("media: uvcvideo: Do not turn on the camera for some
>> ioctls") as the trigger. Reverting the logic change in that commit
>> fixes VT switching
>> on v6.16.1, v6.17.9, and v6.18.9, but that is not an actual solution. Wayland
>> compositors (e.g., river and sway) are not affected.
>>
>> Last good: v6.15.9
>> First bad: v6.16.1
>> Bisect result: d1b618e7954802fe media: uvcvideo: Do not turn on the
>> camera for some ioctls
>>
>> ## Hardware: Lenovo ThinkPad P15 Gen 2i (20YQ0031US)
>> CPU: Intel Core i7-11800H (Tiger Lake-H)
>> iGPU: Intel UHD Graphics (TGL GT1)
>> dGPU: NVIDIA T1200 (not involved in eDP output; driver: nvidia-open)
Could this be caused by nvidia's own driver, even if it is not supposed
to be involved? Might be worth ruling out with a proper vanilla kernel,
ideally really fresh, so 7.0-rc1.
Ciao, Thorsten
>> Display: 15.6" 1920x1080 eDP, 10 bpc capable (EDID 1.4)
>> Webcam: Integrated Camera on PCH xHCI (Bus 003 Port 004)
>> Firmware: LENOVO N37ET61W (1.97)
>> OS: Arch Linux, Nix home-manager, X11 + xmonad, no display manager
>>
>> ## Symptoms and reproduction steps:
>> 1. Boot, start X11 on tty1 (startx).
>> 2. Switch to tty2 (Ctrl+Alt+F2): works.
>> 3. Switch back to tty1 (Ctrl+Alt+F1): display freezes.
>> - Frozen on the last frame shown before switching away.
>> - System is fully responsive over SSH.
>> - Other VTs switch normally between each other as long as X11 is
>> not active on them.
>> - Killing X does not recover the display. A reboot is required.
>>
>> # DEBUG ANALYSIS
>>
>> On v6.16.1, the VT switch back to X triggers a full modeset due to pipe
>> configuration mismatches detected by intel_pipe_config_compare:
>>
>> [drm:intel_pipe_config_compare] fastset requirement not met in pipe_bpp
>> (expected 30, found 24)
>> [drm:intel_pipe_config_compare] fastset requirement not met in dp_m_n
>> (expected link 269484/524288, found link 336855/524288)
>> [drm:intel_pipe_config_compare] fastset requirement not met in dpll_hw_state
>> (expected cfgcr0: 0xe001a5, found cfgcr0: 0x1c2)
>> [drm:intel_pipe_config_compare] fastset requirement not met in port_clock
>> (expected 270000, found 216000)
>> [drm:intel_atomic_check] forcing full modeset
>>
>> On v6.15.9, the same VT switch shows no such messages.
>> no pipe_config_compare runs, no modeset, no freeze.
>>
>> # BISECT AND VERIFICATION
>>
>> The bisect converged on d1b618e7954802fe in the uvcvideo driver. This
>> commit adds a switch statement to uvc_v4l2_unlocked_ioctl that allows
>> certain V4L2 IOCTLS to call video_ioctl2 directly without first calling
>> uvc_pm_get/uvc_pm_put. Prior to this commit, all ioctls called uvc_pm_get
>> before video_ioctl2.
>>
>> ## VT switching verification across kernel versions:
>>
>> v6.12.74 arch pkg: WORKS
>> v6.15.9 arch pkg: WORKS
>> v6.15.9 from source: WORKS
>> v6.16.1 with d1b618e reverted: WORKS
>> v6.17.9 with PM wrapping restored: WORKS
>> v6.18.9 with PM wrapping restored: WORKS
>>
>> v6.16.1 from source: FREEZES
>> v6.16.1 arch pkg: FREEZES
>> v6.17.9 arch pkg: FREEZES
>> v6.18.9 from source: FREEZES
>> v6.18.9 arch pkg: FREEZES
>>
>> ## Things that do not eliminate the freeze
>>
>> - module_blacklist=uvcvideo on boot
>> - CONFIG_USB_VIDEO_CLASS=n (compiled out)
>
> This is puzzling me a bit... You are saying that if you do not build
> the uvc driver, the freeze is still happening?
>
> Am I understanding this correctly?
>
>> - i915.enable_psr=0
>> - Bypassing intel_vrr_transcoder_enable/disable (no-op)
>> - xrandr --output eDP-1 --set "max bpc" 10
>> - Xorg config FBDepth 30 (No effect on pipe_bpp)
>>
>> ## Workaround patch
>>
>> Reverting the optimization from d1b618e to restore the unconditional
>> uvc_pm_get/put wrapping for all ioctls. This is not a proper fix.
>>
>> diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c
>> index 9e4a251eca88..15057b47ec4f 100644
>> --- a/drivers/media/usb/uvc/uvc_v4l2.c
>> +++ b/drivers/media/usb/uvc/uvc_v4l2.c
>> @@ -1199,33 +1199,12 @@ static long uvc_v4l2_unlocked_ioctl(struct file *file,
>> unsigned int converted_cmd = v4l2_translate_cmd(cmd);
>> int ret;
>>
>> - /* The following IOCTLs need to turn on the camera. */
>> - switch (converted_cmd) {
>> - case UVCIOC_CTRL_MAP:
>> - case UVCIOC_CTRL_QUERY:
>> - case VIDIOC_G_CTRL:
>> - case VIDIOC_G_EXT_CTRLS:
>> - case VIDIOC_G_INPUT:
>> - case VIDIOC_QUERYCTRL:
>> - case VIDIOC_QUERYMENU:
>> - case VIDIOC_QUERY_EXT_CTRL:
>> - case VIDIOC_S_CTRL:
>> - case VIDIOC_S_EXT_CTRLS:
>> - case VIDIOC_S_FMT:
>> - case VIDIOC_S_INPUT:
>> - case VIDIOC_S_PARM:
>> - case VIDIOC_TRY_EXT_CTRLS:
>> - case VIDIOC_TRY_FMT:
>> - ret = uvc_pm_get(handle->stream->dev);
>> - if (ret)
>> - return ret;
>> - ret = video_ioctl2(file, cmd, arg);
>> - uvc_pm_put(handle->stream->dev);
>> + ret = uvc_pm_get(handle->stream->dev);
>> + if (ret)
>> return ret;
>> - }
>> -
>> - /* The other IOCTLs can run with the camera off. */
>> - return video_ioctl2(file, cmd, arg);
>> + ret = video_ioctl2(file, cmd, arg);
>> + uvc_pm_put(handle->stream->dev);
>> + return ret;
>> }
>>
>> const struct v4l2_ioctl_ops uvc_ioctl_ops = {
>>
>> Andrés
>>
>
>