Skip to content

asusd: one firmware-rejected attribute (nv_dynamic_boost=20 on battery) aborts ALL asus-armoury D-Bus registration (break should be continue) #132

Description

@OmerFarukOruc

Issue description

On a fresh boot, rog-control-center shows "The asus-armoury driver is not loaded" and the Armoury settings are unavailable — even though the asus-armoury kernel module is loaded and /sys/class/firmware-attributes/asus-armoury/attributes/ is fully populated.

The real cause is in asusd, not the kernel: start_attributes_zbus() breaks out of the whole attribute loop the moment any single attribute's reload() fails. When asusd boots while the laptop is on battery in the Balanced or Quiet profile, it tries to restore the persisted PPT tuning nv_dynamic_boost = 20, the firmware rejects that write with EINVAL, and the break then prevents every armoury attribute from being registered on D-Bus. The GUI sees no xyz.ljones.AsusArmoury objects and reports the driver as "not loaded".

A systemctl restart asusd while on AC + Performance "fixes" it only because that profile's tuning is nv_dynamic_boost = 5 (accepted), so no attribute errors and the loop completes — i.e. the bug is masked by power/profile state, not actually resolved.

Root cause (code references — still present on main, v6.3.8)

  1. The fatal breakasusd/src/asus_armoury.rs:587 (start_attributes_zbus):

    for attr in attributes.attributes() {
        ...
        if let Err(e) = attr.reload().await {
            error!("Skipping attribute '{}' due to reload error: {e:?}", attr.attr.name());
            break;           // <-- abandons ALL remaining attributes
        }
        ...
        registry.push(registry_attr);
    }

    The log says "Skipping attribute", but break does not skip it — it aborts the entire registration. A single firmware-rejected attribute therefore takes down the whole xyz.ljones.AsusArmoury interface.

  2. Non-deterministic orderingrog-platform/src/asus_armoury.rs (FirmwareAttributes::new) builds the list from read_dir(BASE_DIR), whose order is unsorted/filesystem-dependent. So which attributes happen to register before the offending one varies between boots, making the failure look intermittent.

  3. The trigger valuenv_dynamic_boost is typed Ppt (rog-platform/src/asus_armoury.rs), so on reload asusd writes the active profile's tuning to the firmware. The battery (dc_profile_tunings) Balanced/Quiet groups carried NvDynamicBoost: 20, which the asus-armoury driver rejects with EINVAL even though it advertises max_value = 20 (the effective max is state-dependent / lower on battery; current_value = 5).

Steps to reproduce

  1. Laptop with an Nvidia dGPU exposing nv_dynamic_boost via asus-armoury (here: current=5 / min=5 / max=20 / default=20).
  2. Have a persisted battery PPT tuning of NvDynamicBoost: 20 in /etc/asusd/asusd.ron under dc_profile_tunings (Balanced and/or Quiet) — this is what asusd had saved by default.
  3. Unplug AC, set the Platform Profile to Balanced or Quiet.
  4. Reboot (cold boot, no manual asusd restart).
  5. Open rog-control-center.

What is the current bug behavior?

  • rog-control-center shows "The asus-armoury driver is not loaded" and hides Armoury settings.
  • busctl --system tree xyz.ljones.Asusd shows no /xyz/ljones/asus_armoury/* objects (only aura, Platform, FanCurves).
  • asusd log shows exactly one armoury reload attempt, the EINVAL, and then nothing further.
  • systemctl restart asusd while on AC + Performance makes all attributes appear — proving the kernel/driver is fine and the failure is the break.

What is the expected correct behavior?

A single attribute failing to reload should be skipped (logged), and all other armoury attributes should still register on D-Bus. The Armoury interface should be available regardless of power source or profile at boot time.

Suggested fix: replace break with continue in start_attributes_zbus() so a per-attribute failure is non-fatal (which also matches the existing "Skipping attribute" log wording). Optionally, treat a firmware EINVAL on a PPT restore as a non-fatal warning rather than a hard error.

Relevant logs and/or screenshots

journalctl -b -u asusd at boot (on battery, Balanced/Quiet), redacted to the relevant lines:

asusd[...]: [INFO  asusd::asus_armoury] Reloading nv_dynamic_boost
asusd[...]: [INFO  asusd::asus_armoury] Applying value Integer(20) to attribute nv_dynamic_boost
asusd[...]: [ERROR asusd::asus_armoury] Could not set nv_dynamic_boost value: Io(Os { code: 22, kind: InvalidInput, message: "Invalid argument" })
asusd[...]: [DEBUG rog_platform::asus_armoury] Attribute path "/sys/class/firmware-attributes/asus-armoury/attributes/nv_dynamic_boost" exits? true
asusd[...]: [ERROR asusd::asus_armoury] Skipping attribute 'nv_dynamic_boost' due to reload error: Platform(Io(Os { code: 22, kind: InvalidInput, message: "Invalid argument" }))
asusd[...]: [INFO  asusd] attribute on zbus initialized

D-Bus tree in the failed state (no armoury objects):

$ busctl --system tree xyz.ljones.Asusd
└─ /xyz
  └─ /xyz/ljones
    ├─ (xyz.ljones.Platform, xyz.ljones.FanCurves)
    └─ /xyz/ljones/aura
      └─ /xyz/ljones/aura/<id>

After systemctl restart asusd on AC + Performance (tuning value 5, accepted) — all attributes register:

$ busctl --system tree xyz.ljones.Asusd
  └─ /xyz/ljones
    ├─ /xyz/ljones/asus_armoury
    │ ├─ /xyz/ljones/asus_armoury/boot_sound
    │ ├─ /xyz/ljones/asus_armoury/charge_mode
    │ ├─ /xyz/ljones/asus_armoury/dgpu_disable
    │ ├─ /xyz/ljones/asus_armoury/gpu_mux_mode
    │ ├─ /xyz/ljones/asus_armoury/nv_base_tgp
    │ ├─ /xyz/ljones/asus_armoury/nv_dynamic_boost
    │ ├─ /xyz/ljones/asus_armoury/nv_temp_target
    │ ├─ /xyz/ljones/asus_armoury/nv_tgp
    │ ├─ /xyz/ljones/asus_armoury/panel_overdrive
    │ ├─ /xyz/ljones/asus_armoury/ppt_pl1_spl
    │ ├─ /xyz/ljones/asus_armoury/ppt_pl2_sppt
    │ └─ /xyz/ljones/asus_armoury/ppt_pl3_fppt
    └─ /xyz/ljones/aura/<id>

Workaround that makes it survive any boot state (set the rejected battery value to an accepted one):

sudo sed -i 's/NvDynamicBoost: 20/NvDynamicBoost: 5/g' /etc/asusd/asusd.ron
sudo systemctl restart asusd

Related issues

  • rog-control-center power tuning sliders are not updating on a power state change. #87 (closed) — "rog-control-center power tuning sliders are not updating on a power state change." Documents that PPT min_value/max_value change between AC and DC. This is exactly why writing nv_dynamic_boost = 20 is rejected with EINVAL on battery: the effective max is lower on DC. This issue is the next layer — asusd's break turns that one rejected write into a complete loss of the armoury D-Bus interface.
  • Fix missing asus-armoury driver #67 (closed) — same surface symptom ("asus-armoury driver is not loaded") but a different cause (driver genuinely absent on Debian). Noted to distinguish: in this report the driver is loaded and /sys/class/firmware-attributes/asus-armoury/attributes/ is fully populated.

System details

  • Distro: CachyOS (rolling, up to date)
  • Kernel: 7.0.10-1-cachyos
  • Desktop: KDE Plasma
  • Xorg or wayland: wayland
  • asusctl: 6.3.8 (built from OGC main)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions