power_controller: leds: support latest dts changes
authorSven Rademakers <sven.rademakers@gmail.com>
Fri, 16 Feb 2024 09:01:10 +0000 (09:01 +0000)
committerSven Rademakers <sven.rademakers@gmail.com>
Fri, 16 Feb 2024 09:01:10 +0000 (09:01 +0000)
A fallback is implemented to support both old and new definitions of the
status and power sysfs paths

src/api/legacy.rs
src/app/bmc_application.rs
src/app/event_application.rs
src/hal/power_controller.rs

index 4bef15f3168c48100a7e89042156b41df5947147..24533220cf4d5a31c87658ac530cfdf7966abfa4 100644 (file)
@@ -171,7 +171,7 @@ async fn api_entry(
         ("other", false) => get_system_information().await.into(),
         ("power", true) => set_node_power(bmc, query).await,
         ("power", false) => get_node_power(bmc).await.into(),
-        ("reboot", true) => reboot(query).await.into(),
+        ("reboot", true) => reboot(bmc, query).await.into(),
         ("reload", true) => reload_self().into(),
         ("reset", true) => reset_node(bmc, query).await.into(),
         ("sdcard", true) => format_sdcard().into(),
@@ -240,8 +240,8 @@ async fn get_info() -> impl Into<LegacyResponse> {
     )
 }
 
-async fn reboot(query: Query) -> LegacyResult<()> {
-    BmcApplication::reboot(query.contains_key("fel"))
+async fn reboot(bmc: &BmcApplication, query: Query) -> LegacyResult<()> {
+    bmc.reboot(query.contains_key("fel"))
         .await
         .map_err(Into::into)
 }
index 0648a0d793ac91fbec9e20af9cbc6a3ac48a457b..90197bb1c72c53a7cfa1c2efa0d0fe29b935c714 100644 (file)
@@ -168,9 +168,10 @@ impl BmcApplication {
         debug!("node activated bits updated:{:#06b}.", new_state);
 
         let led = new_state != 0;
-        if let Err(e) = self.power_controller.power_led(led).await {
-            log::warn!("power LED error: {}", e);
-        }
+        self.power_controller
+            .power_led(led)
+            .await
+            .unwrap_or_else(|e| log::warn!("power LED error: {:#}", e));
 
         // also update the actual power state accordingly
         self.power_controller
@@ -292,13 +293,17 @@ impl BmcApplication {
             .context("error clearing usbboot")
     }
 
-    pub async fn reboot(fel: bool) -> anyhow::Result<()> {
+    pub async fn reboot(&self, fel: bool) -> anyhow::Result<()> {
         if fel {
             peekpoke::write(0x0709_0108, 0x5AA5_A55A);
             log::warn!("system reboot into FEL");
         }
 
-        tokio::fs::write("/sys/class/leds/fp:reset/brightness", b"1").await?;
+        self.power_controller
+            .status_led(true)
+            .await
+            .unwrap_or_else(|e| log::warn!("status_led: {:#}", e));
+
         Command::new("shutdown").args(["-r", "now"]).spawn()?;
         Ok(())
     }
index 4283f619430748d570e3389839327a317bd9c20d..c122cc129390c4270b74889d412fe042cc4ec7ad 100644 (file)
@@ -42,8 +42,9 @@ pub fn run_event_listener(instance: Arc<BmcApplication>) -> anyhow::Result<()> {
         let bmc = app.clone();
         tokio::spawn(async move { bmc.toggle_power_states(false).await });
     })
-    .add_action(Key::KEY_RESTART, 1, |_| {
-        tokio::spawn(BmcApplication::reboot(false));
+    .add_action(Key::KEY_RESTART, 1, |(app, _)| {
+        let bmc = app.clone();
+        tokio::spawn(async move { bmc.reboot(false).await });
     })
     .run()
     .context("event_listener error")
index 5475466f4d82296c08025e1d2505ce800b8be1c4..e1812348642b24f1962d5f196c17a9f5c6e60a84 100644 (file)
@@ -19,9 +19,14 @@ use crate::gpio_output_array;
 use anyhow::Context;
 use gpiod::{Chip, Lines, Output};
 use log::{debug, trace};
-use std::time::Duration;
+use std::path::PathBuf;
+use std::{str::FromStr, time::Duration};
 use tokio::time::sleep;
 
+const SYS_LED: &str = "/sys/class/leds/fp::power/brightness";
+const SYS_LED_2_0_5: &str = "/sys/class/leds/fp:sys/brightness";
+const STATUS_LED: &str = "/sys/class/leds/fp::status/brightness";
+const STATUS_LED_2_0_5: &str = "/sys/class/leds/fp:reset/brightness";
 const PORT1_EN: &str = "node1-en";
 const PORT2_EN: &str = "node2-en";
 const PORT3_EN: &str = "node3-en";
@@ -31,6 +36,8 @@ const PORT4_EN: &str = "node4-en";
 // with Linux's power subsystem.
 pub struct PowerController {
     enable: [Lines<Output>; 4],
+    sysfs_power: PathBuf,
+    sysfs_reset: PathBuf,
 }
 
 impl PowerController {
@@ -52,7 +59,14 @@ impl PowerController {
 
         let enable = gpio_output_array!(chip1, port1, port2, port3, port4);
 
-        Ok(PowerController { enable })
+        let sysfs_power = fallback_when_not_exists(SYS_LED, SYS_LED_2_0_5);
+        let sysfs_reset = fallback_when_not_exists(STATUS_LED, STATUS_LED_2_0_5);
+
+        Ok(PowerController {
+            enable,
+            sysfs_power,
+            sysfs_reset,
+        })
     }
 
     /// Function to power on/off given nodes. Powering of the nodes is controlled by
@@ -94,11 +108,16 @@ impl PowerController {
     }
 
     pub async fn power_led(&self, on: bool) -> anyhow::Result<()> {
-        const SYS_LED: &str = "/sys/class/leds/fp:sys/brightness";
-        tokio::fs::write(SYS_LED, if on { "1" } else { "0" })
+        tokio::fs::write(&self.sysfs_power, if on { "1" } else { "0" })
             .await
             .context(SYS_LED)
     }
+
+    pub async fn status_led(&self, on: bool) -> anyhow::Result<()> {
+        tokio::fs::write(&self.sysfs_reset, if on { "1" } else { "0" })
+            .await
+            .context(STATUS_LED)
+    }
 }
 
 impl std::fmt::Debug for PowerController {
@@ -117,3 +136,12 @@ async fn set_mode(node_id: usize, node_state: u8) -> std::io::Result<()> {
     let sys_path = format!("/sys/bus/platform/devices/node{}-power/state", node_id);
     tokio::fs::write(sys_path, node_value).await
 }
+
+fn fallback_when_not_exists(sysfs: &str, fallback: &str) -> PathBuf {
+    let mut sysfs = PathBuf::from_str(sysfs).expect("valid utf8 path");
+    if !sysfs.exists() {
+        sysfs = PathBuf::from_str(fallback).expect("valid utf8 path");
+        log::info!("power led: falling back to {}", fallback);
+    }
+    sysfs
+}