summaryrefslogtreecommitdiffstats
path: root/system/system76-power/nvme_temp.patch
diff options
context:
space:
mode:
Diffstat (limited to 'system/system76-power/nvme_temp.patch')
-rw-r--r--system/system76-power/nvme_temp.patch135
1 files changed, 135 insertions, 0 deletions
diff --git a/system/system76-power/nvme_temp.patch b/system/system76-power/nvme_temp.patch
new file mode 100644
index 0000000000..c0531cd38a
--- /dev/null
+++ b/system/system76-power/nvme_temp.patch
@@ -0,0 +1,135 @@
+diff --git a/src/fan.rs b/src/fan.rs
+index 03fdadd..4b3db3b 100644
+--- a/src/fan.rs
++++ b/src/fan.rs
+@@ -23,9 +23,11 @@ pub enum FanDaemonError {
+
+ pub struct FanDaemon {
+ curve: FanCurve,
++ curve_nvme: FanCurve,
+ amdgpus: Vec<HwMon>,
+ platforms: Vec<HwMon>,
+ cpus: Vec<HwMon>,
++ nvmes: Vec<HwMon>,
+ nvidia_exists: bool,
+ displayed_warning: Cell<bool>,
+ }
+@@ -41,9 +43,11 @@ impl FanDaemon {
+ "thelio-massive-b1" => FanCurve::xeon(),
+ _ => FanCurve::standard(),
+ },
++ curve_nvme: FanCurve::nvme(),
+ amdgpus: Vec::new(),
+ platforms: Vec::new(),
+ cpus: Vec::new(),
++ nvmes: Vec::new(),
+ nvidia_exists,
+ displayed_warning: Cell::new(false),
+ };
+@@ -60,6 +64,7 @@ impl FanDaemon {
+ self.amdgpus.clear();
+ self.platforms.clear();
+ self.cpus.clear();
++ self.nvmes.clear();
+
+ for hwmon in HwMon::all().map_err(FanDaemonError::HwmonDevices)? {
+ if let Ok(name) = hwmon.name() {
+@@ -70,6 +75,7 @@ impl FanDaemon {
+ "system76" => (), // TODO: Support laptops
+ "system76_io" | "system76_thelio_io" => self.platforms.push(hwmon),
+ "coretemp" | "k10temp" => self.cpus.push(hwmon),
++ "nvme" => self.nvmes.push(hwmon),
+ _ => (),
+ }
+ }
+@@ -83,6 +89,10 @@ impl FanDaemon {
+ return Err(FanDaemonError::CpuHwmonNotFound);
+ }
+
++ if self.nvmes.is_empty() {
++ // No error.
++ }
++
+ Ok(())
+ }
+
+@@ -128,6 +138,25 @@ impl FanDaemon {
+ temp_opt
+ }
+
++ /// Get the maximum measured temperature from any NVME on the system, in thousandths of a
++ /// Celsius. Thousandths celsius is the standard Linux hwmon temperature unit.
++ pub fn get_nvme_temp(&self) -> Option<u32> {
++ self
++ .nvmes
++ .iter()
++ .filter_map(|sensor| sensor.temp(1).ok())
++ .filter_map(|temp| temp.input().ok())
++ .fold(None, |mut temp_opt, input| {
++ // Assume temperatures are always above freezing
++ if temp_opt.map_or(true, |x| input as u32 > x) {
++ log::debug!("highest hwmon nvme temp: {}", input);
++ temp_opt = Some(input as u32);
++ }
++
++ temp_opt
++ })
++ }
++
+ /// Get the correct duty cycle for a temperature in thousandths Celsius, from 0 to 255
+ /// Thousandths celsius is the standard Linux hwmon temperature unit
+ /// 0 to 255 is the standard Linux hwmon pwm unit
+@@ -137,6 +166,15 @@ impl FanDaemon {
+ .map(|duty| (((u32::from(duty)) * 255) / 10_000) as u8)
+ }
+
++ /// Get the correct duty cycle for an NVME temperature in thousandths Celsius, from 0 to 255
++ /// Thousandths celsius is the standard Linux hwmon temperature unit
++ /// 0 to 255 is the standard Linux hwmon pwm unit
++ pub fn get_nvme_duty(&self, temp: u32) -> Option<u8> {
++ self.curve_nvme
++ .get_duty((temp / 10) as i16)
++ .map(|duty| (((u32::from(duty)) * 255) / 10_000) as u8)
++ }
++
+ /// Set the current duty cycle, from 0 to 255
+ /// 0 to 255 is the standard Linux hwmon pwm unit
+ pub fn set_duty(&self, duty_opt: Option<u8>) {
+@@ -159,7 +197,20 @@ impl FanDaemon {
+ /// Calculate the correct duty cycle and apply it to all fans
+ pub fn step(&mut self) {
+ if let Ok(()) = self.discover() {
+- self.set_duty(self.get_temp().and_then(|temp| self.get_duty(temp)));
++ self.set_duty({
++ let cpu_duty = self.get_temp().and_then(|temp| self.get_duty(temp));
++ log::debug!("cpu duty: {:?}", cpu_duty);
++ if self.nvmes.is_empty() {
++ cpu_duty
++ } else {
++ let nvme_duty = self.get_nvme_temp().and_then(|temp| self.get_nvme_duty(temp));
++ log::debug!("nvme duty: {:?}", nvme_duty);
++ match(cpu_duty, nvme_duty) {
++ (Some(cpu_duty), Some(nvme_duty)) => Some(cmp::max(cpu_duty, nvme_duty)),
++ _ => None,
++ }
++ }
++ });
+ }
+ }
+ }
+@@ -282,6 +333,15 @@ impl FanCurve {
+ .append(78_00, 100_00)
+ }
+
++ /// Fan curve for NVME drives
++ pub fn nvme() -> Self {
++ Self::default()
++ .append(00_00, 00_00)
++ .append(60_00, 00_00)
++ .append(65_00, 70_00)
++ .append(68_00, 100_00)
++ }
++
+ pub fn get_duty(&self, temp: i16) -> Option<u16> {
+ // If the temp is less than the first point, return the first point duty
+ if let Some(first) = self.points.first() {