<html><head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  </head>
  <body>
    <div class="moz-cite-prefix">On 5/20/22 16:41, Daniel Dadap wrote:<br>
    </div>
    <blockquote type="cite" cite="mid:80fa1ee5-6204-6178-e7e2-ac98038cd8d8@nvidia.com">
      <br>
      On 5/17/22 10:23, Hans de Goede wrote:
      <br>
      <blockquote type="cite">On x86/ACPI boards the acpi_video driver
        will usually initializing before
        <br>
        the kms driver (except i915). This causes
        /sys/class/backlight/acpi_video0
        <br>
        to show up and then the kms driver registers its own native
        backlight
        <br>
        device after which the drivers/acpi/video_detect.c code
        unregisters
        <br>
        the acpi_video0 device (when
        acpi_video_get_backlight_type()==native).
        <br>
        <br>
        This means that userspace briefly sees 2 devices and the
        disappearing of
        <br>
        acpi_video0 after a brief time confuses the systemd backlight
        level
        <br>
        save/restore code, see e.g.:
        <br>
        <a class="moz-txt-link-freetext" href="https://bbs.archlinux.org/viewtopic.php?id=269920">https://bbs.archlinux.org/viewtopic.php?id=269920</a>
        <br>
        <br>
        To fix this make backlight class device registration a separate
        step
        <br>
        done by a new acpi_video_register_backlight() function. The
        intend is for
        <br>
        this to be called by the drm/kms driver *after* it is done
        setting up its
        <br>
        own native backlight device. So that
        acpi_video_get_backlight_type() knows
        <br>
        if a native backlight will be available or not at acpi_video
        backlight
        <br>
        registration time, avoiding the add + remove dance.
        <br>
      </blockquote>
      <br>
      <br>
      If I'm understanding this correctly, it seems we will want to call
      acpi_video_register_backlight() from the NVIDIA proprietary driver
      in a fallback path in case the driver's own GPU-controlled
      backlight handler either should not be used, or fails to register.
      That sounds reasonable enough, but I'm not sure what should be
      done about drivers like nvidia-wmi-ec-backlight, which are
      independent of the GPU hardware, and wouldn't be part of the
      acpi_video driver, either. There are a number of other similar
      vendor-y/platform-y type backlight drivers in
      drivers/video/backlight and drivers/platform/x86 that I think
      would be in a similar situation.
      <br>
      <br>
      From a quick skim of the ACPI video driver, it seems that perhaps
      nvidia-wmi-ec-backlight is missing a call to
      acpi_video_set_dmi_backlight_type(), perhaps with the
      acpi_backlight_vendor value? But I'm not familiar enough with this
      code to be sure that nobody will be checking
      acpi_video_get_backlight_type() before nvidia-wmi-ec-backlight
      loads. I'll take a closer look to try to convince myself that it
      makes sense.
      <br>
      <br>
      <br>
      <blockquote type="cite">Note the new
        acpi_video_register_backlight() function is also called from
        <br>
        a delayed work to ensure that the acpi_video backlight devices
        does get
        <br>
        registered if necessary even if there is no drm/kms driver or
        when it is
        <br>
        disabled.
        <br>
      </blockquote>
      <br>
      <br>
      It sounds like maybe everything should be fine as long as
      nvidia-wmi-ec-backlight (and other vendor-y/platform-y type
      drivers) gets everything set up before the delayed work which
      calls acpi_video_register_backlight()? But then is it really
      necessary to explicitly call acpi_video_register_backlight() from
      the DRM drivers if it's going to be called later if no GPU driver
      registered a backlight handler, anyway? Then we'd just need to
      make sure that the iGPU and dGPU drivers won't attempt to register
      a backlight handler on systems where a vendor-y/platform-y driver
      is supposed to handle the backlight instead, which sounds like it
      has the potential to be quite messy.
      <br>
      <br>
    </blockquote>
    <p><br>
    </p>
    <p>Ah, I see you addressed this concern in your RFC (sorry for
      missing that, earlier):<br>
      <br>
    </p>
    <p>
      <blockquote type="cite">
        <pre id="b">The above only takes native vs acpi_video backlight issues into
account, there are also a couple of other scenarios which may
lead to multiple backlight-devices getting registered:

1) Apple laptops using the apple_gmux driver
2) Nvidia laptops using the (new) nvidia-wmi-ec-backlight driver
3) drivers/platform/x86 drivers calling acpi_video_set_dmi_backlight_type()
   to override the normal acpi_video_get_backlight_type() heuristics after
   the native/acpi_video drivers have already loaded

The plan for 1) + 2) is to extend the acpi_backlight_type enum with
acpi_backlight_gmux and acpi_backlight_nvidia_wmi_ec values and to add
detection of these 2 to acpi_video_get_backlight_type().</pre>
      </blockquote>
      <br>
      Is there a reason these shouldn't have the same, generic, type,
      rather than separate, driver-specific ones? I don't foresee any
      situation where a system would need to use these two particular
      drivers simultaneously. Multiple DRM drivers can coexist on the
      same system, and even though the goal here is to remove the
      existing "multiple backlight interfaces for the same panel"
      situation, there shouldn't be any reason why more than one DRM
      driver couldn't register backlight handlers at the same time, so
      long as they are driving distinct panels. If we don't need
      separate backlight types for individual DRM drivers, why should we
      have them for apple_gmux and nvidia_wmi_ec_backlight?<br>
      <br>
      I still think that relying on the GPU drivers to correctly know
      whether they should register their backlight handlers when a
      platform-level device is supposed to register one instead might be
      easier said than done, especially on systems where the same panel
      could potentially be driven by more than one GPU (but not at the
      same time).<br>
      <br>
    </p>
    <blockquote type="cite" cite="mid:80fa1ee5-6204-6178-e7e2-ac98038cd8d8@nvidia.com">Recall
      that on at least one system, both amdgpu and the NVIDIA
      proprietary driver registered a handler even when it shouldn't:
<a class="moz-txt-link-freetext" href="https://patchwork.kernel.org/project/platform-driver-x86/patch/20220316203325.2242536-1-ddadap@nvidia.com/">https://patchwork.kernel.org/project/platform-driver-x86/patch/20220316203325.2242536-1-ddadap@nvidia.com/</a>
      - I didn't have direct access to this system, but the fact that
      the NVIDIA driver registered a handler was almost certainly a bug
      in either the driver or the system's firmware (on other systems
      with the same type of backlight hardware, NVIDIA does not register
      a handler), and I imagine the same is true of the amdgpu driver.
      In all likelihood nouveau would have probably tried to register
      one too; I am not certain whether the person who reported the
      issue to me had tested with nouveau. I'm not convinced that the
      GPU drivers can reliably determine whether or not they are
      supposed to register, but maybe cases where they aren't, such as
      the system mentioned above, are supposed to be handled in a quirks
      table somewhere.
      <br>
      <br>
      <br>
      <blockquote type="cite">Signed-off-by: Hans de Goede
        <a class="moz-txt-link-rfc2396E" href="mailto:hdegoede@redhat.com"><hdegoede@redhat.com></a>
        <br>
        ---
        <br>
          drivers/acpi/acpi_video.c | 45
        ++++++++++++++++++++++++++++++++++++---
        <br>
          include/acpi/video.h      |  2 ++
        <br>
          2 files changed, 44 insertions(+), 3 deletions(-)
        <br>
        <br>
        diff --git a/drivers/acpi/acpi_video.c
        b/drivers/acpi/acpi_video.c
        <br>
        index 95d4868f6a8c..79e75dc86243 100644
        <br>
        --- a/drivers/acpi/acpi_video.c
        <br>
        +++ b/drivers/acpi/acpi_video.c
        <br>
        @@ -31,6 +31,12 @@
        <br>
          #define ACPI_VIDEO_BUS_NAME        "Video Bus"
        <br>
          #define ACPI_VIDEO_DEVICE_NAME        "Video Device"
        <br>
          +/*
        <br>
        + * Display probing is known to take up to 5 seconds, so delay
        the fallback
        <br>
        + * backlight registration by 5 seconds + 3 seconds for some
        extra margin.
        <br>
        + */
        <br>
        +#define ACPI_VIDEO_REGISTER_BACKLIGHT_DELAY    (8 * HZ)
        <br>
        +
        <br>
          #define MAX_NAME_LEN    20
        <br>
            MODULE_AUTHOR("Bruno Ducrot");
        <br>
        @@ -80,6 +86,9 @@ static LIST_HEAD(video_bus_head);
        <br>
          static int acpi_video_bus_add(struct acpi_device *device);
        <br>
          static int acpi_video_bus_remove(struct acpi_device *device);
        <br>
          static void acpi_video_bus_notify(struct acpi_device *device,
        u32 event);
        <br>
        +static void acpi_video_bus_register_backlight_work(struct
        work_struct *ignored);
        <br>
        +static DECLARE_DELAYED_WORK(video_bus_register_backlight_work,
        <br>
        +                acpi_video_bus_register_backlight_work);
        <br>
          void acpi_video_detect_exit(void);
        <br>
            /*
        <br>
        @@ -1862,8 +1871,6 @@ static int
        acpi_video_bus_register_backlight(struct acpi_video_bus *video)
        <br>
              if (video->backlight_registered)
        <br>
                  return 0;
        <br>
          -    acpi_video_run_bcl_for_osi(video);
        <br>
        -
        <br>
              if (acpi_video_get_backlight_type(false) !=
        acpi_backlight_video)
        <br>
                  return 0;
        <br>
          @@ -2089,7 +2096,11 @@ static int acpi_video_bus_add(struct
        acpi_device *device)
        <br>
              list_add_tail(&video->entry, &video_bus_head);
        <br>
              mutex_unlock(&video_list_lock);
        <br>
          -    acpi_video_bus_register_backlight(video);
        <br>
        +    /*
        <br>
        +     * The userspace visible backlight_device gets registered
        separately
        <br>
        +     * from acpi_video_register_backlight().
        <br>
        +     */
        <br>
        +    acpi_video_run_bcl_for_osi(video);
        <br>
              acpi_video_bus_add_notify_handler(video);
        <br>
                return 0;
        <br>
        @@ -2128,6 +2139,11 @@ static int acpi_video_bus_remove(struct
        acpi_device *device)
        <br>
              return 0;
        <br>
          }
        <br>
          +static void acpi_video_bus_register_backlight_work(struct
        work_struct *ignored)
        <br>
        +{
        <br>
        +    acpi_video_register_backlight();
        <br>
        +}
        <br>
        +
        <br>
          static int __init is_i740(struct pci_dev *dev)
        <br>
          {
        <br>
              if (dev->device == 0x00D1)
        <br>
        @@ -2238,6 +2254,17 @@ int acpi_video_register(void)
        <br>
               */
        <br>
              register_count = 1;
        <br>
          +    /*
        <br>
        +     * acpi_video_bus_add() skips registering the userspace
        visible
        <br>
        +     * backlight_device. The intend is for this to be
        registered by the
        <br>
        +     * drm/kms driver calling acpi_video_register_backlight()
        *after* it is
        <br>
        +     * done setting up its own native backlight device. The
        delayed work
        <br>
        +     * ensures that acpi_video_register_backlight() always gets
        called
        <br>
        +     * eventually, in case there is no drm/kms driver or it is
        disabled.
        <br>
        +     */
        <br>
        +   
        schedule_delayed_work(&video_bus_register_backlight_work,
        <br>
        +                  ACPI_VIDEO_REGISTER_BACKLIGHT_DELAY);
        <br>
        +
        <br>
          leave:
        <br>
              mutex_unlock(&register_count_mutex);
        <br>
              return ret;
        <br>
        @@ -2248,6 +2275,7 @@ void acpi_video_unregister(void)
        <br>
          {
        <br>
              mutex_lock(&register_count_mutex);
        <br>
              if (register_count) {
        <br>
        +       
        cancel_delayed_work_sync(&video_bus_register_backlight_work);
        <br>
                  acpi_bus_unregister_driver(&acpi_video_bus);
        <br>
                  register_count = 0;
        <br>
              }
        <br>
        @@ -2255,6 +2283,17 @@ void acpi_video_unregister(void)
        <br>
          }
        <br>
          EXPORT_SYMBOL(acpi_video_unregister);
        <br>
          +void acpi_video_register_backlight(void)
        <br>
        +{
        <br>
        +    struct acpi_video_bus *video;
        <br>
        +
        <br>
        +    mutex_lock(&video_list_lock);
        <br>
        +    list_for_each_entry(video, &video_bus_head, entry)
        <br>
        +        acpi_video_bus_register_backlight(video);
        <br>
        +    mutex_unlock(&video_list_lock);
        <br>
        +}
        <br>
        +EXPORT_SYMBOL(acpi_video_register_backlight);
        <br>
        +
        <br>
          void acpi_video_unregister_backlight(void)
        <br>
          {
        <br>
              struct acpi_video_bus *video;
        <br>
        diff --git a/include/acpi/video.h b/include/acpi/video.h
        <br>
        index e31afb93379a..b2f7dc1f354a 100644
        <br>
        --- a/include/acpi/video.h
        <br>
        +++ b/include/acpi/video.h
        <br>
        @@ -53,6 +53,7 @@ enum acpi_backlight_type {
        <br>
          #if IS_ENABLED(CONFIG_ACPI_VIDEO)
        <br>
          extern int acpi_video_register(void);
        <br>
          extern void acpi_video_unregister(void);
        <br>
        +extern void acpi_video_register_backlight(void);
        <br>
          extern int acpi_video_get_edid(struct acpi_device *device, int
        type,
        <br>
                             int device_id, void **edid);
        <br>
          extern enum acpi_backlight_type
        acpi_video_get_backlight_type(bool native);
        <br>
        @@ -68,6 +69,7 @@ extern int acpi_video_get_levels(struct
        acpi_device *device,
        <br>
          #else
        <br>
          static inline int acpi_video_register(void) { return -ENODEV;
        }
        <br>
          static inline void acpi_video_unregister(void) { return; }
        <br>
        +static inline void acpi_video_register_backlight(void) {
        return; }
        <br>
          static inline int acpi_video_get_edid(struct acpi_device
        *device, int type,
        <br>
                                int device_id, void **edid)
        <br>
          {
        <br>
      </blockquote>
    </blockquote>
  </body>
</html>