Some recent Lenovo and Inspur machines with Zhaoxin CPUs fail to create /sys/class/backlight/acpi_video0 on v6.6 kernels, while the same hardware works correctly on v5.4.
Our analysis shows that the current implementation assumes the presence of a GPU. The backlight registration is only triggered if a GPU is detected, but on these platforms the backlight is handled purely by the EC without any GPU. As a result, the detection path does not create the expected backlight node.
To fix this, move the following logic:
/* Use ACPI video if available, except when native should be preferred. */ if ((video_caps & ACPI_VIDEO_BACKLIGHT) && !(native_available && prefer_native_over_acpi_video())) return acpi_backlight_video;
above the if (auto_detect) *auto_detect = true; statement.
This ensures that the ACPI video backlight node is created even when no GPU is present, restoring the correct behavior observed on older kernels.
Fixes: 78dfc9d1d1ab ("ACPI: video: Add auto_detect arg to __acpi_video_get_backlight_type()") Cc: stable@vger.kernel.org Signed-off-by: Zihuan Zhang zhangzihuan@kylinos.cn --- drivers/acpi/video_detect.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c index d507d5e08435..c1bb22b57f56 100644 --- a/drivers/acpi/video_detect.c +++ b/drivers/acpi/video_detect.c @@ -1011,6 +1011,11 @@ enum acpi_backlight_type __acpi_video_get_backlight_type(bool native, bool *auto if (acpi_backlight_dmi != acpi_backlight_undef) return acpi_backlight_dmi;
+ /* Use ACPI video if available, except when native should be preferred. */ + if ((video_caps & ACPI_VIDEO_BACKLIGHT) && + !(native_available && prefer_native_over_acpi_video())) + return acpi_backlight_video; + if (auto_detect) *auto_detect = true;
@@ -1024,11 +1029,6 @@ enum acpi_backlight_type __acpi_video_get_backlight_type(bool native, bool *auto if (dell_uart_present) return acpi_backlight_dell_uart;
- /* Use ACPI video if available, except when native should be preferred. */ - if ((video_caps & ACPI_VIDEO_BACKLIGHT) && - !(native_available && prefer_native_over_acpi_video())) - return acpi_backlight_video; - /* Use native if available */ if (native_available) return acpi_backlight_native;
Hi Zihuan,
On 10-Sep-25 9:47 AM, Zihuan Zhang wrote:
Some recent Lenovo and Inspur machines with Zhaoxin CPUs fail to create /sys/class/backlight/acpi_video0 on v6.6 kernels, while the same hardware works correctly on v5.4.
Our analysis shows that the current implementation assumes the presence of a GPU. The backlight registration is only triggered if a GPU is detected, but on these platforms the backlight is handled purely by the EC without any GPU. As a result, the detection path does not create the expected backlight node.
To fix this, move the following logic:
/* Use ACPI video if available, except when native should be preferred. */ if ((video_caps & ACPI_VIDEO_BACKLIGHT) && !(native_available && prefer_native_over_acpi_video())) return acpi_backlight_video;
above the if (auto_detect) *auto_detect = true; statement.
This ensures that the ACPI video backlight node is created even when no GPU is present, restoring the correct behavior observed on older kernels.
Fixes: 78dfc9d1d1ab ("ACPI: video: Add auto_detect arg to __acpi_video_get_backlight_type()") Cc: stable@vger.kernel.org Signed-off-by: Zihuan Zhang zhangzihuan@kylinos.cn
Thank you for your patch.
drivers/acpi/video_detect.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c index d507d5e08435..c1bb22b57f56 100644 --- a/drivers/acpi/video_detect.c +++ b/drivers/acpi/video_detect.c @@ -1011,6 +1011,11 @@ enum acpi_backlight_type __acpi_video_get_backlight_type(bool native, bool *auto if (acpi_backlight_dmi != acpi_backlight_undef) return acpi_backlight_dmi;
- /* Use ACPI video if available, except when native should be preferred. */
- if ((video_caps & ACPI_VIDEO_BACKLIGHT) &&
!(native_available && prefer_native_over_acpi_video()))
return acpi_backlight_video;
- if (auto_detect) *auto_detect = true;
@@ -1024,11 +1029,6 @@ enum acpi_backlight_type __acpi_video_get_backlight_type(bool native, bool *auto if (dell_uart_present) return acpi_backlight_dell_uart;
- /* Use ACPI video if available, except when native should be preferred. */
- if ((video_caps & ACPI_VIDEO_BACKLIGHT) &&
!(native_available && prefer_native_over_acpi_video()))
return acpi_backlight_video;
- /* Use native if available */ if (native_available) return acpi_backlight_native;
There is a very specific ordering, as the comment in the function says:
/* * The below heuristics / detection steps are in order of descending * presedence. The commandline takes presedence over anything else. */
You cannot just move one fo the detect steps like this, this will break many many other systems.
NACK for this patch, sorry.
We will need to figure out some other way to fix your issue.
For starters I do not understand how this patch helps.
You are moving the:
/* Use ACPI video if available, except when native should be preferred. */ if ((video_caps & ACPI_VIDEO_BACKLIGHT) && !(native_available && prefer_native_over_acpi_video())) return acpi_backlight_video;
Above the nvidia_wmi_ec_present, apple_gmux_present and dell_uart_present checks, but I would expect all of these to be false on Lenovo and Inspur machines with Zhaoxin CPUs ? So this patch should not make a difference.
Please double check that this patch fixes things for you.
And if it does really fix things then please add printk() calls printing the value of nvidia_wmi_ec_present, apple_gmux_present and dell_uart_present these should all be false, but maybe we get a false-positive and one of them is set to true ?
Regards,
Hans
Hi,
On 10-Sep-25 11:37 AM, Hans de Goede wrote:
Hi Zihuan,
On 10-Sep-25 9:47 AM, Zihuan Zhang wrote:
Some recent Lenovo and Inspur machines with Zhaoxin CPUs fail to create /sys/class/backlight/acpi_video0 on v6.6 kernels, while the same hardware works correctly on v5.4.
Our analysis shows that the current implementation assumes the presence of a GPU. The backlight registration is only triggered if a GPU is detected, but on these platforms the backlight is handled purely by the EC without any GPU. As a result, the detection path does not create the expected backlight node.
To fix this, move the following logic:
/* Use ACPI video if available, except when native should be preferred. */ if ((video_caps & ACPI_VIDEO_BACKLIGHT) && !(native_available && prefer_native_over_acpi_video())) return acpi_backlight_video;
above the if (auto_detect) *auto_detect = true; statement.
This ensures that the ACPI video backlight node is created even when no GPU is present, restoring the correct behavior observed on older kernels.
Fixes: 78dfc9d1d1ab ("ACPI: video: Add auto_detect arg to __acpi_video_get_backlight_type()") Cc: stable@vger.kernel.org Signed-off-by: Zihuan Zhang zhangzihuan@kylinos.cn
Thank you for your patch.
drivers/acpi/video_detect.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c index d507d5e08435..c1bb22b57f56 100644 --- a/drivers/acpi/video_detect.c +++ b/drivers/acpi/video_detect.c @@ -1011,6 +1011,11 @@ enum acpi_backlight_type __acpi_video_get_backlight_type(bool native, bool *auto if (acpi_backlight_dmi != acpi_backlight_undef) return acpi_backlight_dmi;
- /* Use ACPI video if available, except when native should be preferred. */
- if ((video_caps & ACPI_VIDEO_BACKLIGHT) &&
!(native_available && prefer_native_over_acpi_video()))
return acpi_backlight_video;
- if (auto_detect) *auto_detect = true;
@@ -1024,11 +1029,6 @@ enum acpi_backlight_type __acpi_video_get_backlight_type(bool native, bool *auto if (dell_uart_present) return acpi_backlight_dell_uart;
- /* Use ACPI video if available, except when native should be preferred. */
- if ((video_caps & ACPI_VIDEO_BACKLIGHT) &&
!(native_available && prefer_native_over_acpi_video()))
return acpi_backlight_video;
- /* Use native if available */ if (native_available) return acpi_backlight_native;
There is a very specific ordering, as the comment in the function says:
/* * The below heuristics / detection steps are in order of descending * presedence. The commandline takes presedence over anything else. */
You cannot just move one fo the detect steps like this, this will break many many other systems.
NACK for this patch, sorry.
We will need to figure out some other way to fix your issue.
For starters I do not understand how this patch helps.
Oh wait, now I understand the trick is that you now return acpi_backlight_video without setting *auto_detect = true.
Which in turn causes this code in drivers/acpi/acpi_video.c:
/* * If backlight-type auto-detection is used then a native backlight may * show up later and this may change the result from video to native. * Therefor normally the userspace visible /sys/class/backlight device * gets registered separately by the GPU driver calling * acpi_video_register_backlight() when an internal panel is detected. * Register the backlight now when not using auto-detection, so that * when the kernel cmdline or DMI-quirks are used the backlight will * get registered even if acpi_video_register_backlight() is not called. */ acpi_video_run_bcl_for_osi(video); if (__acpi_video_get_backlight_type(false, &auto_detect) == acpi_backlight_video && !auto_detect) acpi_video_bus_register_backlight(video);
To immediately register the backlight rather then waiting for the native GPU driver to call acpi_video_register_backlight() after the native GPU driver has completed probing for native GPU backlight control which is often preferred.
So as you say the issue is that you have no native GPU driver calling acpi_video_register_backlight().
But this patch really is not a good way to fix this and will break things on many other systems. So still NACK.
First of all I assume that there is some sort of builtin GPU on these Lenovo and Inspur machines with Zhaoxin CPUs. Even if the GPU driver is not in the mainline kernel then I assume there is some out of tree driver. Can that driver not call acpi_video_register_backlight() ?
acpi_video_register_backlight() is deliberately EXPORT_SYMBOL() rather then EXPORT_SYMBOL_GPL() so that even proprietary GPU drivers can call it.
Having your out of tree GPU driver call acpi_video_register_backlight() would really be the best solution here as that would be using the video_detect.c / acpi_video.c code as designed.
If this is not possible then we will need to add some quirk based on CPUID matching e.g. something like this:
diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c index d507d5e08435..24dd79ec1b72 100644 --- a/drivers/acpi/video_detect.c +++ b/drivers/acpi/video_detect.c @@ -1011,6 +1011,18 @@ enum acpi_backlight_type __acpi_video_get_backlight_type(bool native, bool *auto if (acpi_backlight_dmi != acpi_backlight_undef) return acpi_backlight_dmi;
+ /* + * ATM Zhaoxin CPU systems have no native GPU driver, instead ACPI video + * should be used to control the backlight. The lack of a GPU driver + * means that acpi_video_register_backlight() will never get called + * causing things to not work. + * This special case for these systems returns acpi_backlight_video + * without setting auto_detect = true, causing acpi_video.c to + * immediately register the backlight, working around this issue. + */ + if ((video_caps & ACPI_VIDEO_BACKLIGHT) && cpu_is_zhaoxin()) + return acpi_backlight_video; + if (auto_detect) *auto_detect = true;
Note you will need to provide a cpu_is_zhaoxin() helper for this.
Regards,
Hans
Oh wait, now I understand the trick is that you now return acpi_backlight_video without setting *auto_detect = true. Which in turn causes this code in drivers/acpi/acpi_video.c: /* * If backlight-type auto-detection is used then a native backlight may * show up later and this may change the result from video to native. * Therefor normally the userspace visible /sys/class/backlight device * gets registered separately by the GPU driver calling * acpi_video_register_backlight() when an internal panel is detected. * Register the backlight now when not using auto-detection, so that * when the kernel cmdline or DMI-quirks are used the backlight will * get registered even if acpi_video_register_backlight() is not called. */ acpi_video_run_bcl_for_osi(video); if (__acpi_video_get_backlight_type(false, &auto_detect) == acpi_backlight_video && !auto_detect) acpi_video_bus_register_backlight(video); To immediately register the backlight rather then waiting for the native GPU driver to call acpi_video_register_backlight() after the native GPU driver has completed probing for native GPU backlight control which is often preferred. So as you say the issue is that you have no native GPU driver calling acpi_video_register_backlight().
I'm very happy that you got it.
First of all I assume that there is some sort of builtin GPU on these Lenovo and Inspur machines with Zhaoxin CPUs. Even if the GPU driver is not in the mainline kernel then I assume there is some out of tree driver. Can that driver not call acpi_video_register_backlight() ?
We are currently working with Zhaoxin on this matter, and we expect to have some results in a few days. I will keep you updated once we have progress.
If this is not possible then we will need to add some quirk based on CPUID matching e.g. something like this:
diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c index d507d5e08435..24dd79ec1b72 100644 --- a/drivers/acpi/video_detect.c +++ b/drivers/acpi/video_detect.c @@ -1011,6 +1011,18 @@ enum acpi_backlight_type __acpi_video_get_backlight_type(bool native, bool *auto if (acpi_backlight_dmi != acpi_backlight_undef) return acpi_backlight_dmi;
- /*
* ATM Zhaoxin CPU systems have no native GPU driver, instead ACPI video
* should be used to control the backlight. The lack of a GPU driver
* means that acpi_video_register_backlight() will never get called
* causing things to not work.
* This special case for these systems returns acpi_backlight_video
* without setting auto_detect = true, causing acpi_video.c to
* immediately register the backlight, working around this issue.
*/
- if ((video_caps & ACPI_VIDEO_BACKLIGHT) && cpu_is_zhaoxin())
return acpi_backlight_video;
- if (auto_detect) *auto_detect = true;
Note you will need to provide a cpu_is_zhaoxin() helper for this.
Thanks a lot for your patch and for looking into this issue.
At the moment, we are still confirming with Zhaoxin whether this behavior is consistent across all their platforms, so we are not sure if the special handling should always apply.
Also, on kernel 5.4 these machines seem to work fine without requiring a native GPU driver, while on 6.6+ the backlight node is missing. Could you please clarify what design change or intention caused this behavioral difference between 5.4 and newer kernels?
Hi Zihuan,
On 11-Sep-25 9:45 AM, Zhang wrote:
...
So as you say the issue is that you have no native GPU driver calling acpi_video_register_backlight().
I'm very happy that you got it.
First of all I assume that there is some sort of builtin GPU on these Lenovo and Inspur machines with Zhaoxin CPUs. Even if the GPU driver is not in the mainline kernel then I assume there is some out of tree driver. Can that driver not call acpi_video_register_backlight() ?
We are currently working with Zhaoxin on this matter, and we expect to have some results in a few days. I will keep you updated once we have progress.
Ok.
...
Thanks a lot for your patch and for looking into this issue.
You're welcome.
At the moment, we are still confirming with Zhaoxin whether this behavior is consistent across all their platforms, so we are not sure if the special handling should always apply.
Also, on kernel 5.4 these machines seem to work fine without requiring a native GPU driver, while on 6.6+ the backlight node is missing. Could you please clarify what design change or intention caused this behavioral difference between 5.4 and newer kernels?
The main problem is that on x86 laptops there are too much different ways to control the backlight:
enum acpi_backlight_type { acpi_backlight_undef = -1, acpi_backlight_none = 0, acpi_backlight_video, acpi_backlight_vendor, acpi_backlight_native, acpi_backlight_nvidia_wmi_ec, acpi_backlight_apple_gmux, acpi_backlight_dell_uart, };
With video, vendor and native all 3 being quite normal to have around on a single laptop.
A long time ago the kernel just used to register all backlight handlers for which there seemed to be support, so "ls /sys/class/backlight" would e.g. output:
acpi_video0 intel_backlight dell_laptop
And then userspace would pick one to use, typically checking for different backlight types (raw/platform/firmware) in descending order of preference and picking the first backlight interface matching the highest preference type.
But even though multiple types may be advertised by the firmware, they do not necessarily actually work.
So the simple userspace pick based on preferred type solution did not work on all laptop models and drivers/acpi/video_detect.c starting growing heuristics + quirks to let the kernel pick one and hide the others.
At first for acpi_video# backlights they would get registered and then later if a native backlight (e.g. intel_backlight) showed up and the heuristics / quirks set that should be preferred then the acpi_video# backlight would be unregistered again.
But this is racy (and ugly) and caused issues for userspace trying to open the already unregistered backlight.
So the code was changed to delay registering the acpi_video backlights till after the GPU driver has loaded so that it is known if native backlight control is supported or not.
Long story short: The design goal is to only register 1 backlight handler, so that userspace does not has to guess and to only register this once and not do a register + unregister dance of a potentially unwanted acpi_video backlight.
Regards,
Hans
在 2025/9/11 18:38, Hans de Goede 写道:
Hi Zihuan,
On 11-Sep-25 9:45 AM, Zhang wrote:
...
So as you say the issue is that you have no native GPU driver calling acpi_video_register_backlight().
I'm very happy that you got it.
First of all I assume that there is some sort of builtin GPU on these Lenovo and Inspur machines with Zhaoxin CPUs. Even if the GPU driver is not in the mainline kernel then I assume there is some out of tree driver. Can that driver not call acpi_video_register_backlight() ?
We are currently working with Zhaoxin on this matter, and we expect to have some results in a few days. I will keep you updated once we have progress.
Ok.
...
Thanks a lot for your patch and for looking into this issue.
You're welcome.
At the moment, we are still confirming with Zhaoxin whether this behavior is consistent across all their platforms, so we are not sure if the special handling should always apply.
Also, on kernel 5.4 these machines seem to work fine without requiring a native GPU driver, while on 6.6+ the backlight node is missing. Could you please clarify what design change or intention caused this behavioral difference between 5.4 and newer kernels?
The main problem is that on x86 laptops there are too much different ways to control the backlight:
enum acpi_backlight_type { acpi_backlight_undef = -1, acpi_backlight_none = 0, acpi_backlight_video, acpi_backlight_vendor, acpi_backlight_native, acpi_backlight_nvidia_wmi_ec, acpi_backlight_apple_gmux, acpi_backlight_dell_uart, };
With video, vendor and native all 3 being quite normal to have around on a single laptop.
A long time ago the kernel just used to register all backlight handlers for which there seemed to be support, so "ls /sys/class/backlight" would e.g. output:
acpi_video0 intel_backlight dell_laptop
And then userspace would pick one to use, typically checking for different backlight types (raw/platform/firmware) in descending order of preference and picking the first backlight interface matching the highest preference type.
But even though multiple types may be advertised by the firmware, they do not necessarily actually work.
So the simple userspace pick based on preferred type solution did not work on all laptop models and drivers/acpi/video_detect.c starting growing heuristics
- quirks to let the kernel pick one and hide the others.
At first for acpi_video# backlights they would get registered and then later if a native backlight (e.g. intel_backlight) showed up and the heuristics / quirks set that should be preferred then the acpi_video# backlight would be unregistered again.
But this is racy (and ugly) and caused issues for userspace trying to open the already unregistered backlight.
So the code was changed to delay registering the acpi_video backlights till after the GPU driver has loaded so that it is known if native backlight control is supported or not.
Long story short: The design goal is to only register 1 backlight handler, so that userspace does not has to guess and to only register this once and not do a register + unregister dance of a potentially unwanted acpi_video backlight.
Thank you for the very detailed explanation!
One concern, however, is that the current approach seems to assume the presence of a GPU driver, which may not always be the case. Would it be possible to consider a more generic fallback?
For example, if no GPU driver is available, we could still register the acpi_video backlight node.
This way we can at least ensure that a backlight device is exposed to userspace instead of leaving the system without any backlight control interface.
Do you think such a fallback could be a reasonable option?
Thanks again for your insights!
Regards,
Hans
Hi,
On 12-Sep-25 3:11 AM, Zihuan Zhang wrote:
在 2025/9/11 18:38, Hans de Goede 写道:
Hi Zihuan,
On 11-Sep-25 9:45 AM, Zhang wrote:
...
Also, on kernel 5.4 these machines seem to work fine without requiring a native GPU driver, while on 6.6+ the backlight node is missing. Could you please clarify what design change or intention caused this behavioral difference between 5.4 and newer kernels?
...
Long story short: The design goal is to only register 1 backlight handler, so that userspace does not has to guess and to only register this once and not do a register + unregister dance of a potentially unwanted acpi_video backlight.
Thank you for the very detailed explanation!
You're welcome.
One concern, however, is that the current approach seems to assume the presence of a GPU driver, which may not always be the case. Would it be possible to consider a more generic fallback?
Well x86/ACPI laptops without a GPU are not really something which exists anymore. A GPU is a must have for a good user experience with modern OS-es.
And now a days we have in kernel drivers for all main GPU vendors.
This new way of doing things has been around for quite a while now without causing problems.
To me it seems the issue here is that GPU driver for the (CPU/chipset integrated?) GPU on these laptops is missing from the mainline kernel.
There are many good reasons to have a GPU driver in the mainline kernel. So ideally this would be fixed by mainlining the GPU driver for these laptops.
For example, if no GPU driver is available, we could still register the acpi_video backlight node.
The problem is how do we know that no GPU driver is available ?
Note that the DMI quirk check happens before setting *auto_detect = true; So besides doing a CPU check another option would be to do a DMI check. DMI checks can use substring matches (they do a strstr match by default) so if there is some common DMI string (part) on the affected laptops which is not found on other laptops then we can also just DMI quirk these.
As long as it does not end up being an ever growing list then adding a bunch of DMI entries for this should be fine.
This way we can at least ensure that a backlight device is exposed to userspace instead of leaving the system without any backlight control interface.
Do you think such a fallback could be a reasonable option?
The problem is the kernel does not know if there is a GPU driver for the GPU. If it is e.g. the nvidia binary driver it may need to first get build by dkms, so even using say a timeout is tricky and a timeout is always racy so I would like to avoid that.
My preferred way of handling this would be:
1. There must be a GPU driver for these laptops somewhere? Even if out of tree using a laptop without a GPU these days just does not give a good user experience. So fix the GPU driver to call acpi_video_register_backlight().
Note acpi_video_register_backlight() is deliberately exported without requiring the consuming out of tree kernel module to be GPL to allow this.
Other options would be:
2. Add some special heuristics for Zhaoxin CPUs, the kernel already has a CPUID match mechanism for things like this. This could potentially be combined with a DMI system-vendor check to only do this special case handling on e.g. Lenovo and Inspur laptops.
3. Instead of adding the CPU-id based special case just outright use DMI quirks. In this case lets try to use substring matches to cover multiple models with a single entry so as to not grow the quirk table too much.
Regards,
Hans
- There must be a GPU driver for these laptops somewhere?
Even if out of tree using a laptop without a GPU these days just does not give a good user experience. So fix the GPU driver to call acpi_video_register_backlight().
Note acpi_video_register_backlight() is deliberately exported without requiring the consuming out of tree kernel module to be GPL to allow this.
Other options would be:
- Add some special heuristics for Zhaoxin CPUs,
the kernel already has a CPUID match mechanism for things like this. This could potentially be combined with a DMI system-vendor check to only do this special case handling on e.g. Lenovo and Inspur laptops.
- Instead of adding the CPU-id based special case
just outright use DMI quirks. In this case lets try to use substring matches to cover multiple models with a single entry so as to not grow the quirk table too much.
Got it, thanks!
In fact, we have tried a few approaches (cmdline option, CPU-ID based quirk, and DMI quirk), and all of them work. I will sync this information with Zhaoxin to see which way they prefer.
linux-stable-mirror@lists.linaro.org