^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Windfarm PowerMac thermal control.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Control loops for RackMack3,1 (Xserve G5)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Copyright (C) 2012 Benjamin Herrenschmidt, IBM Corp.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/reboot.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <asm/prom.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <asm/smu.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include "windfarm.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include "windfarm_pid.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include "windfarm_mpu.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #define VERSION "1.0"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #undef DEBUG
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #undef LOTSA_DEBUG
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #ifdef DEBUG
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #define DBG(args...) printk(args)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #define DBG(args...) do { } while(0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #ifdef LOTSA_DEBUG
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #define DBG_LOTS(args...) printk(args)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #define DBG_LOTS(args...) do { } while(0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) /* define this to force CPU overtemp to 60 degree, useful for testing
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) * the overtemp code
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) #undef HACKED_OVERTEMP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) /* We currently only handle 2 chips */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) #define NR_CHIPS 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) #define NR_CPU_FANS 3 * NR_CHIPS
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) /* Controls and sensors */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) static struct wf_sensor *sens_cpu_temp[NR_CHIPS];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) static struct wf_sensor *sens_cpu_volts[NR_CHIPS];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) static struct wf_sensor *sens_cpu_amps[NR_CHIPS];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) static struct wf_sensor *backside_temp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) static struct wf_sensor *slots_temp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) static struct wf_sensor *dimms_temp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) static struct wf_control *cpu_fans[NR_CHIPS][3];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) static struct wf_control *backside_fan;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) static struct wf_control *slots_fan;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) static struct wf_control *cpufreq_clamp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) /* We keep a temperature history for average calculation of 180s */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) #define CPU_TEMP_HIST_SIZE 180
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) /* PID loop state */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) static const struct mpu_data *cpu_mpu_data[NR_CHIPS];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) static struct wf_cpu_pid_state cpu_pid[NR_CHIPS];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) static u32 cpu_thist[CPU_TEMP_HIST_SIZE];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) static int cpu_thist_pt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) static s64 cpu_thist_total;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) static s32 cpu_all_tmax = 100 << 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) static struct wf_pid_state backside_pid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) static int backside_tick;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) static struct wf_pid_state slots_pid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) static int slots_tick;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) static int slots_speed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) static struct wf_pid_state dimms_pid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) static int dimms_output_clamp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) static int nr_chips;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) static bool have_all_controls;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) static bool have_all_sensors;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) static bool started;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) static int failure_state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) #define FAILURE_SENSOR 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) #define FAILURE_FAN 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) #define FAILURE_PERM 4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) #define FAILURE_LOW_OVERTEMP 8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) #define FAILURE_HIGH_OVERTEMP 16
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) /* Overtemp values */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) #define LOW_OVER_AVERAGE 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) #define LOW_OVER_IMMEDIATE (10 << 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) #define LOW_OVER_CLEAR ((-10) << 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) #define HIGH_OVER_IMMEDIATE (14 << 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) #define HIGH_OVER_AVERAGE (10 << 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) #define HIGH_OVER_IMMEDIATE (14 << 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) static void cpu_max_all_fans(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) /* We max all CPU fans in case of a sensor error. We also do the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) * cpufreq clamping now, even if it's supposedly done later by the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) * generic code anyway, we do it earlier here to react faster
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) if (cpufreq_clamp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) wf_control_set_max(cpufreq_clamp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) for (i = 0; i < nr_chips; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) if (cpu_fans[i][0])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) wf_control_set_max(cpu_fans[i][0]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) if (cpu_fans[i][1])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) wf_control_set_max(cpu_fans[i][1]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) if (cpu_fans[i][2])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) wf_control_set_max(cpu_fans[i][2]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) static int cpu_check_overtemp(s32 temp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) int new_state = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) s32 t_avg, t_old;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) static bool first = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) /* First check for immediate overtemps */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) if (temp >= (cpu_all_tmax + LOW_OVER_IMMEDIATE)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) new_state |= FAILURE_LOW_OVERTEMP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) if ((failure_state & FAILURE_LOW_OVERTEMP) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) printk(KERN_ERR "windfarm: Overtemp due to immediate CPU"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) " temperature !\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) if (temp >= (cpu_all_tmax + HIGH_OVER_IMMEDIATE)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) new_state |= FAILURE_HIGH_OVERTEMP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) if ((failure_state & FAILURE_HIGH_OVERTEMP) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) printk(KERN_ERR "windfarm: Critical overtemp due to"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) " immediate CPU temperature !\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) * The first time around, initialize the array with the first
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) * temperature reading
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) if (first) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) cpu_thist_total = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) for (i = 0; i < CPU_TEMP_HIST_SIZE; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) cpu_thist[i] = temp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) cpu_thist_total += temp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) first = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) * We calculate a history of max temperatures and use that for the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) * overtemp management
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) t_old = cpu_thist[cpu_thist_pt];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) cpu_thist[cpu_thist_pt] = temp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) cpu_thist_pt = (cpu_thist_pt + 1) % CPU_TEMP_HIST_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) cpu_thist_total -= t_old;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) cpu_thist_total += temp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) t_avg = cpu_thist_total / CPU_TEMP_HIST_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) DBG_LOTS(" t_avg = %d.%03d (out: %d.%03d, in: %d.%03d)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) FIX32TOPRINT(t_avg), FIX32TOPRINT(t_old), FIX32TOPRINT(temp));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) /* Now check for average overtemps */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) if (t_avg >= (cpu_all_tmax + LOW_OVER_AVERAGE)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) new_state |= FAILURE_LOW_OVERTEMP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) if ((failure_state & FAILURE_LOW_OVERTEMP) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) printk(KERN_ERR "windfarm: Overtemp due to average CPU"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) " temperature !\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) if (t_avg >= (cpu_all_tmax + HIGH_OVER_AVERAGE)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) new_state |= FAILURE_HIGH_OVERTEMP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) if ((failure_state & FAILURE_HIGH_OVERTEMP) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) printk(KERN_ERR "windfarm: Critical overtemp due to"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) " average CPU temperature !\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) /* Now handle overtemp conditions. We don't currently use the windfarm
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) * overtemp handling core as it's not fully suited to the needs of those
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) * new machine. This will be fixed later.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) if (new_state) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) /* High overtemp -> immediate shutdown */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) if (new_state & FAILURE_HIGH_OVERTEMP)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) machine_power_off();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) if ((failure_state & new_state) != new_state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) cpu_max_all_fans();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) failure_state |= new_state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) } else if ((failure_state & FAILURE_LOW_OVERTEMP) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) (temp < (cpu_all_tmax + LOW_OVER_CLEAR))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) printk(KERN_ERR "windfarm: Overtemp condition cleared !\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) failure_state &= ~FAILURE_LOW_OVERTEMP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) return failure_state & (FAILURE_LOW_OVERTEMP | FAILURE_HIGH_OVERTEMP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) static int read_one_cpu_vals(int cpu, s32 *temp, s32 *power)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) s32 dtemp, volts, amps;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) /* Get diode temperature */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) rc = wf_sensor_get(sens_cpu_temp[cpu], &dtemp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) if (rc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) DBG(" CPU%d: temp reading error !\n", cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) DBG_LOTS(" CPU%d: temp = %d.%03d\n", cpu, FIX32TOPRINT((dtemp)));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) *temp = dtemp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) /* Get voltage */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) rc = wf_sensor_get(sens_cpu_volts[cpu], &volts);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) if (rc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) DBG(" CPU%d, volts reading error !\n", cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) DBG_LOTS(" CPU%d: volts = %d.%03d\n", cpu, FIX32TOPRINT((volts)));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) /* Get current */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) rc = wf_sensor_get(sens_cpu_amps[cpu], &s);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) if (rc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) DBG(" CPU%d, current reading error !\n", cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) DBG_LOTS(" CPU%d: amps = %d.%03d\n", cpu, FIX32TOPRINT((amps)));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) /* Calculate power */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) /* Scale voltage and current raw sensor values according to fixed scales
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) * obtained in Darwin and calculate power from I and V
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) *power = (((u64)volts) * ((u64)amps)) >> 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) DBG_LOTS(" CPU%d: power = %d.%03d\n", cpu, FIX32TOPRINT((*power)));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) static void cpu_fans_tick(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) int err, cpu, i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) s32 speed, temp, power, t_max = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) DBG_LOTS("* cpu fans_tick_split()\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) for (cpu = 0; cpu < nr_chips; ++cpu) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) struct wf_cpu_pid_state *sp = &cpu_pid[cpu];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) /* Read current speed */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) wf_control_get(cpu_fans[cpu][0], &sp->target);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) err = read_one_cpu_vals(cpu, &temp, &power);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) failure_state |= FAILURE_SENSOR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) cpu_max_all_fans();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) /* Keep track of highest temp */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) t_max = max(t_max, temp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) /* Handle possible overtemps */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) if (cpu_check_overtemp(t_max))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) /* Run PID */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) wf_cpu_pid_run(sp, power, temp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) DBG_LOTS(" CPU%d: target = %d RPM\n", cpu, sp->target);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) /* Apply DIMMs clamp */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) speed = max(sp->target, dimms_output_clamp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) /* Apply result to all cpu fans */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) for (i = 0; i < 3; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) err = wf_control_set(cpu_fans[cpu][i], speed);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) pr_warn("wf_rm31: Fan %s reports error %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) cpu_fans[cpu][i]->name, err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) failure_state |= FAILURE_FAN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) /* Implementation... */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) static int cpu_setup_pid(int cpu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) struct wf_cpu_pid_param pid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) const struct mpu_data *mpu = cpu_mpu_data[cpu];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) s32 tmax, ttarget, ptarget;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) int fmin, fmax, hsize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) /* Get PID params from the appropriate MPU EEPROM */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) tmax = mpu->tmax << 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) ttarget = mpu->ttarget << 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) ptarget = ((s32)(mpu->pmaxh - mpu->padjmax)) << 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) DBG("wf_72: CPU%d ttarget = %d.%03d, tmax = %d.%03d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) cpu, FIX32TOPRINT(ttarget), FIX32TOPRINT(tmax));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) /* We keep a global tmax for overtemp calculations */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) if (tmax < cpu_all_tmax)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) cpu_all_tmax = tmax;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) /* Set PID min/max by using the rear fan min/max */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) fmin = wf_control_get_min(cpu_fans[cpu][0]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) fmax = wf_control_get_max(cpu_fans[cpu][0]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) DBG("wf_72: CPU%d max RPM range = [%d..%d]\n", cpu, fmin, fmax);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) /* History size */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) hsize = min_t(int, mpu->tguardband, WF_PID_MAX_HISTORY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) DBG("wf_72: CPU%d history size = %d\n", cpu, hsize);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) /* Initialize PID loop */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) pid.interval = 1; /* seconds */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) pid.history_len = hsize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) pid.gd = mpu->pid_gd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) pid.gp = mpu->pid_gp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) pid.gr = mpu->pid_gr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) pid.tmax = tmax;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) pid.ttarget = ttarget;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) pid.pmaxadj = ptarget;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) pid.min = fmin;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) pid.max = fmax;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) wf_cpu_pid_init(&cpu_pid[cpu], &pid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) cpu_pid[cpu].target = 4000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) /* Backside/U3 fan */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) static const struct wf_pid_param backside_param = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) .interval = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) .history_len = 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) .gd = 0x00500000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) .gp = 0x0004cccc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) .gr = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) .itarget = 70 << 16,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) .additive = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) .min = 20,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) .max = 100,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) /* DIMMs temperature (clamp the backside fan) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) static const struct wf_pid_param dimms_param = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) .interval = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) .history_len = 20,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) .gd = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) .gp = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) .gr = 0x06553600,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) .itarget = 50 << 16,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) .additive = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) .min = 4000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) .max = 14000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) static void backside_fan_tick(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) s32 temp, dtemp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) int speed, dspeed, fan_min;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) if (!backside_fan || !backside_temp || !dimms_temp || !backside_tick)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) if (--backside_tick > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) backside_tick = backside_pid.param.interval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) DBG_LOTS("* backside fans tick\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) /* Update fan speed from actual fans */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) err = wf_control_get(backside_fan, &speed);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) if (!err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) backside_pid.target = speed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) err = wf_sensor_get(backside_temp, &temp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) printk(KERN_WARNING "windfarm: U3 temp sensor error %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) failure_state |= FAILURE_SENSOR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) wf_control_set_max(backside_fan);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) speed = wf_pid_run(&backside_pid, temp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) DBG_LOTS("backside PID temp=%d.%.3d speed=%d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) FIX32TOPRINT(temp), speed);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) err = wf_sensor_get(dimms_temp, &dtemp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) printk(KERN_WARNING "windfarm: DIMMs temp sensor error %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) failure_state |= FAILURE_SENSOR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) wf_control_set_max(backside_fan);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) dspeed = wf_pid_run(&dimms_pid, dtemp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) dimms_output_clamp = dspeed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) fan_min = (dspeed * 100) / 14000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) fan_min = max(fan_min, backside_param.min);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) speed = max(speed, fan_min);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) err = wf_control_set(backside_fan, speed);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) printk(KERN_WARNING "windfarm: backside fan error %d\n", err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) failure_state |= FAILURE_FAN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) static void backside_setup_pid(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) /* first time initialize things */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) s32 fmin = wf_control_get_min(backside_fan);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) s32 fmax = wf_control_get_max(backside_fan);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) struct wf_pid_param param;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) param = backside_param;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) param.min = max(param.min, fmin);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) param.max = min(param.max, fmax);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) wf_pid_init(&backside_pid, ¶m);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) param = dimms_param;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) wf_pid_init(&dimms_pid, ¶m);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) backside_tick = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) pr_info("wf_rm31: Backside control loop started.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) /* Slots fan */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) static const struct wf_pid_param slots_param = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) .interval = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) .history_len = 20,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) .gd = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) .gp = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) .gr = 0x00100000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) .itarget = 3200000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) .additive = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) .min = 20,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) .max = 100,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) static void slots_fan_tick(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) s32 temp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) int speed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) if (!slots_fan || !slots_temp || !slots_tick)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) if (--slots_tick > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) slots_tick = slots_pid.param.interval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) DBG_LOTS("* slots fans tick\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) err = wf_sensor_get(slots_temp, &temp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) pr_warn("wf_rm31: slots temp sensor error %d\n", err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) failure_state |= FAILURE_SENSOR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) wf_control_set_max(slots_fan);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) speed = wf_pid_run(&slots_pid, temp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) DBG_LOTS("slots PID temp=%d.%.3d speed=%d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) FIX32TOPRINT(temp), speed);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) slots_speed = speed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) err = wf_control_set(slots_fan, speed);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) printk(KERN_WARNING "windfarm: slots bay fan error %d\n", err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) failure_state |= FAILURE_FAN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) static void slots_setup_pid(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) /* first time initialize things */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) s32 fmin = wf_control_get_min(slots_fan);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) s32 fmax = wf_control_get_max(slots_fan);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) struct wf_pid_param param = slots_param;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) param.min = max(param.min, fmin);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) param.max = min(param.max, fmax);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) wf_pid_init(&slots_pid, ¶m);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) slots_tick = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) pr_info("wf_rm31: Slots control loop started.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) static void set_fail_state(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) cpu_max_all_fans();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) if (backside_fan)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) wf_control_set_max(backside_fan);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) if (slots_fan)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) wf_control_set_max(slots_fan);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) static void rm31_tick(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) int i, last_failure;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) if (!started) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) started = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) printk(KERN_INFO "windfarm: CPUs control loops started.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) for (i = 0; i < nr_chips; ++i) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) if (cpu_setup_pid(i) < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) failure_state = FAILURE_PERM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) set_fail_state();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) DBG_LOTS("cpu_all_tmax=%d.%03d\n", FIX32TOPRINT(cpu_all_tmax));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) backside_setup_pid();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) slots_setup_pid();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) #ifdef HACKED_OVERTEMP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) cpu_all_tmax = 60 << 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) /* Permanent failure, bail out */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) if (failure_state & FAILURE_PERM)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) * Clear all failure bits except low overtemp which will be eventually
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) * cleared by the control loop itself
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) last_failure = failure_state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) failure_state &= FAILURE_LOW_OVERTEMP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) backside_fan_tick();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) slots_fan_tick();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) /* We do CPUs last because they can be clamped high by
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) * DIMM temperature
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) cpu_fans_tick();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) DBG_LOTS(" last_failure: 0x%x, failure_state: %x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) last_failure, failure_state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) /* Check for failures. Any failure causes cpufreq clamping */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) if (failure_state && last_failure == 0 && cpufreq_clamp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) wf_control_set_max(cpufreq_clamp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) if (failure_state == 0 && last_failure && cpufreq_clamp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) wf_control_set_min(cpufreq_clamp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) /* That's it for now, we might want to deal with other failures
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) * differently in the future though
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) static void rm31_new_control(struct wf_control *ct)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) bool all_controls;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) if (!strcmp(ct->name, "cpu-fan-a-0"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) cpu_fans[0][0] = ct;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) else if (!strcmp(ct->name, "cpu-fan-b-0"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) cpu_fans[0][1] = ct;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) else if (!strcmp(ct->name, "cpu-fan-c-0"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) cpu_fans[0][2] = ct;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) else if (!strcmp(ct->name, "cpu-fan-a-1"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) cpu_fans[1][0] = ct;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) else if (!strcmp(ct->name, "cpu-fan-b-1"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) cpu_fans[1][1] = ct;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) else if (!strcmp(ct->name, "cpu-fan-c-1"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) cpu_fans[1][2] = ct;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) else if (!strcmp(ct->name, "backside-fan"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) backside_fan = ct;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) else if (!strcmp(ct->name, "slots-fan"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) slots_fan = ct;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) else if (!strcmp(ct->name, "cpufreq-clamp"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) cpufreq_clamp = ct;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) all_controls =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) cpu_fans[0][0] &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) cpu_fans[0][1] &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) cpu_fans[0][2] &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) backside_fan &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) slots_fan;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) if (nr_chips > 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) all_controls &=
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) cpu_fans[1][0] &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) cpu_fans[1][1] &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) cpu_fans[1][2];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) have_all_controls = all_controls;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) static void rm31_new_sensor(struct wf_sensor *sr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) bool all_sensors;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) if (!strcmp(sr->name, "cpu-diode-temp-0"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) sens_cpu_temp[0] = sr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) else if (!strcmp(sr->name, "cpu-diode-temp-1"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) sens_cpu_temp[1] = sr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) else if (!strcmp(sr->name, "cpu-voltage-0"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) sens_cpu_volts[0] = sr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) else if (!strcmp(sr->name, "cpu-voltage-1"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) sens_cpu_volts[1] = sr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) else if (!strcmp(sr->name, "cpu-current-0"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) sens_cpu_amps[0] = sr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) else if (!strcmp(sr->name, "cpu-current-1"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) sens_cpu_amps[1] = sr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) else if (!strcmp(sr->name, "backside-temp"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) backside_temp = sr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) else if (!strcmp(sr->name, "slots-temp"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) slots_temp = sr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) else if (!strcmp(sr->name, "dimms-temp"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) dimms_temp = sr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) all_sensors =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) sens_cpu_temp[0] &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) sens_cpu_volts[0] &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) sens_cpu_amps[0] &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) backside_temp &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) slots_temp &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) dimms_temp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) if (nr_chips > 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) all_sensors &=
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) sens_cpu_temp[1] &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) sens_cpu_volts[1] &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) sens_cpu_amps[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) have_all_sensors = all_sensors;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) static int rm31_wf_notify(struct notifier_block *self,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) unsigned long event, void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) switch (event) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) case WF_EVENT_NEW_SENSOR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) rm31_new_sensor(data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) case WF_EVENT_NEW_CONTROL:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) rm31_new_control(data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) case WF_EVENT_TICK:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) if (have_all_controls && have_all_sensors)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) rm31_tick();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) static struct notifier_block rm31_events = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) .notifier_call = rm31_wf_notify,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) static int wf_rm31_probe(struct platform_device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) wf_register_client(&rm31_events);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) static int wf_rm31_remove(struct platform_device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) wf_unregister_client(&rm31_events);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) /* should release all sensors and controls */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) static struct platform_driver wf_rm31_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) .probe = wf_rm31_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) .remove = wf_rm31_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) .name = "windfarm",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) static int __init wf_rm31_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) struct device_node *cpu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) if (!of_machine_is_compatible("RackMac3,1"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) /* Count the number of CPU cores */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) nr_chips = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) for_each_node_by_type(cpu, "cpu")
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) ++nr_chips;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) if (nr_chips > NR_CHIPS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) nr_chips = NR_CHIPS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) pr_info("windfarm: Initializing for desktop G5 with %d chips\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) nr_chips);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) /* Get MPU data for each CPU */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) for (i = 0; i < nr_chips; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) cpu_mpu_data[i] = wf_get_mpu(i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) if (!cpu_mpu_data[i]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) pr_err("wf_rm31: Failed to find MPU data for CPU %d\n", i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) return -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) #ifdef MODULE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) request_module("windfarm_fcu_controls");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) request_module("windfarm_lm75_sensor");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) request_module("windfarm_lm87_sensor");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) request_module("windfarm_ad7417_sensor");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) request_module("windfarm_max6690_sensor");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) request_module("windfarm_cpufreq_clamp");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) #endif /* MODULE */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) platform_driver_register(&wf_rm31_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) static void __exit wf_rm31_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) platform_driver_unregister(&wf_rm31_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) module_init(wf_rm31_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) module_exit(wf_rm31_exit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) MODULE_DESCRIPTION("Thermal control for Xserve G5");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) MODULE_ALIAS("platform:windfarm");