^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. SMU based 1 CPU desktop control loops
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * (c) Copyright 2005 Benjamin Herrenschmidt, IBM Corp.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * <benh@kernel.crashing.org>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * The algorithm used is the PID control algorithm, used the same
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * way the published Darwin code does, using the same values that
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * are present in the Darwin 8.2 snapshot property lists (note however
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * that none of the code has been re-used, it's a complete re-implementation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * The various control loops found in Darwin config file are:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) * PowerMac9,1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) * ===========
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) * Has 3 control loops: CPU fans is similar to PowerMac8,1 (though it doesn't
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) * try to play with other control loops fans). Drive bay is rather basic PID
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) * with one sensor and one fan. Slots area is a bit different as the Darwin
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) * driver is supposed to be capable of working in a special "AGP" mode which
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) * involves the presence of an AGP sensor and an AGP fan (possibly on the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) * AGP card itself). I can't deal with that special mode as I don't have
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) * access to those additional sensor/fans for now (though ultimately, it would
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) * be possible to add sensor objects for them) so I'm only implementing the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) * basic PCI slot control loop
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #include <linux/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #include <linux/errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #include <linux/spinlock.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #include <linux/wait.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #include <linux/kmod.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #include <linux/device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) #include <asm/prom.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) #include <asm/machdep.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) #include <asm/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) #include <asm/sections.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) #include <asm/smu.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) #include "windfarm.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) #include "windfarm_pid.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) #define VERSION "0.4"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) #undef DEBUG
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) #ifdef DEBUG
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) #define DBG(args...) printk(args)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) #define DBG(args...) do { } while(0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) /* define this to force CPU overtemp to 74 degree, useful for testing
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) * the overtemp code
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) #undef HACKED_OVERTEMP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) /* Controls & sensors */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) static struct wf_sensor *sensor_cpu_power;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) static struct wf_sensor *sensor_cpu_temp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) static struct wf_sensor *sensor_hd_temp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) static struct wf_sensor *sensor_slots_power;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) static struct wf_control *fan_cpu_main;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) static struct wf_control *fan_cpu_second;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) static struct wf_control *fan_cpu_third;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) static struct wf_control *fan_hd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) static struct wf_control *fan_slots;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) static struct wf_control *cpufreq_clamp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) /* Set to kick the control loop into life */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) static int wf_smu_all_controls_ok, wf_smu_all_sensors_ok;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) static bool wf_smu_started;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) static bool wf_smu_overtemp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) /* Failure handling.. could be nicer */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) #define FAILURE_FAN 0x01
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) #define FAILURE_SENSOR 0x02
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) #define FAILURE_OVERTEMP 0x04
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) static unsigned int wf_smu_failure_state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) static int wf_smu_readjust, wf_smu_skipping;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) * ****** CPU Fans Control Loop ******
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) #define WF_SMU_CPU_FANS_INTERVAL 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) #define WF_SMU_CPU_FANS_MAX_HISTORY 16
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) /* State data used by the cpu fans control loop
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) struct wf_smu_cpu_fans_state {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) int ticks;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) s32 cpu_setpoint;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) struct wf_cpu_pid_state pid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) static struct wf_smu_cpu_fans_state *wf_smu_cpu_fans;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) * ****** Drive Fan Control Loop ******
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) struct wf_smu_drive_fans_state {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) int ticks;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) s32 setpoint;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) struct wf_pid_state pid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) static struct wf_smu_drive_fans_state *wf_smu_drive_fans;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) * ****** Slots Fan Control Loop ******
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) struct wf_smu_slots_fans_state {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) int ticks;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) s32 setpoint;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) struct wf_pid_state pid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) static struct wf_smu_slots_fans_state *wf_smu_slots_fans;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) * ***** Implementation *****
^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)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) static void wf_smu_create_cpu_fans(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) struct wf_cpu_pid_param pid_param;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) const struct smu_sdbp_header *hdr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) struct smu_sdbp_cpupiddata *piddata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) struct smu_sdbp_fvt *fvt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) s32 tmax, tdelta, maxpow, powadj;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) /* First, locate the PID params in SMU SBD */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) hdr = smu_get_sdb_partition(SMU_SDB_CPUPIDDATA_ID, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) if (hdr == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) printk(KERN_WARNING "windfarm: CPU PID fan config not found "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) "max fan speed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) piddata = (struct smu_sdbp_cpupiddata *)&hdr[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) /* Get the FVT params for operating point 0 (the only supported one
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) * for now) in order to get tmax
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) hdr = smu_get_sdb_partition(SMU_SDB_FVT_ID, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) if (hdr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) fvt = (struct smu_sdbp_fvt *)&hdr[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) tmax = ((s32)fvt->maxtemp) << 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) tmax = 0x5e0000; /* 94 degree default */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) /* Alloc & initialize state */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) wf_smu_cpu_fans = kmalloc(sizeof(struct wf_smu_cpu_fans_state),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) if (wf_smu_cpu_fans == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) wf_smu_cpu_fans->ticks = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) /* Fill PID params */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) pid_param.interval = WF_SMU_CPU_FANS_INTERVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) pid_param.history_len = piddata->history_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) if (pid_param.history_len > WF_CPU_PID_MAX_HISTORY) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) printk(KERN_WARNING "windfarm: History size overflow on "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) "CPU control loop (%d)\n", piddata->history_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) pid_param.history_len = WF_CPU_PID_MAX_HISTORY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) pid_param.gd = piddata->gd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) pid_param.gp = piddata->gp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) pid_param.gr = piddata->gr / pid_param.history_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) tdelta = ((s32)piddata->target_temp_delta) << 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) maxpow = ((s32)piddata->max_power) << 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) powadj = ((s32)piddata->power_adj) << 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) pid_param.tmax = tmax;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) pid_param.ttarget = tmax - tdelta;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) pid_param.pmaxadj = maxpow - powadj;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) pid_param.min = wf_control_get_min(fan_cpu_main);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) pid_param.max = wf_control_get_max(fan_cpu_main);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) wf_cpu_pid_init(&wf_smu_cpu_fans->pid, &pid_param);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) DBG("wf: CPU Fan control initialized.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) DBG(" ttarget=%d.%03d, tmax=%d.%03d, min=%d RPM, max=%d RPM\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) FIX32TOPRINT(pid_param.ttarget), FIX32TOPRINT(pid_param.tmax),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) pid_param.min, pid_param.max);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) fail:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) printk(KERN_WARNING "windfarm: CPU fan config not found\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) "for this machine model, max fan speed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) if (cpufreq_clamp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) wf_control_set_max(cpufreq_clamp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) if (fan_cpu_main)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) wf_control_set_max(fan_cpu_main);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) static void wf_smu_cpu_fans_tick(struct wf_smu_cpu_fans_state *st)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) s32 new_setpoint, temp, power;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) if (--st->ticks != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) if (wf_smu_readjust)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) goto readjust;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) st->ticks = WF_SMU_CPU_FANS_INTERVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) rc = wf_sensor_get(sensor_cpu_temp, &temp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) if (rc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) printk(KERN_WARNING "windfarm: CPU temp sensor error %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) rc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) wf_smu_failure_state |= FAILURE_SENSOR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) rc = wf_sensor_get(sensor_cpu_power, &power);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) if (rc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) printk(KERN_WARNING "windfarm: CPU power sensor error %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) rc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) wf_smu_failure_state |= FAILURE_SENSOR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) DBG("wf_smu: CPU Fans tick ! CPU temp: %d.%03d, power: %d.%03d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) FIX32TOPRINT(temp), FIX32TOPRINT(power));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) #ifdef HACKED_OVERTEMP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) if (temp > 0x4a0000)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) wf_smu_failure_state |= FAILURE_OVERTEMP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) if (temp > st->pid.param.tmax)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) wf_smu_failure_state |= FAILURE_OVERTEMP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) new_setpoint = wf_cpu_pid_run(&st->pid, power, temp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) DBG("wf_smu: new_setpoint: %d RPM\n", (int)new_setpoint);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) if (st->cpu_setpoint == new_setpoint)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) st->cpu_setpoint = new_setpoint;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) readjust:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) if (fan_cpu_main && wf_smu_failure_state == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) rc = wf_control_set(fan_cpu_main, st->cpu_setpoint);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) if (rc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) printk(KERN_WARNING "windfarm: CPU main fan"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) " error %d\n", rc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) wf_smu_failure_state |= FAILURE_FAN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) if (fan_cpu_second && wf_smu_failure_state == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) rc = wf_control_set(fan_cpu_second, st->cpu_setpoint);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) if (rc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) printk(KERN_WARNING "windfarm: CPU second fan"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) " error %d\n", rc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) wf_smu_failure_state |= FAILURE_FAN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) if (fan_cpu_third && wf_smu_failure_state == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) rc = wf_control_set(fan_cpu_third, st->cpu_setpoint);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) if (rc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) printk(KERN_WARNING "windfarm: CPU third fan"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) " error %d\n", rc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) wf_smu_failure_state |= FAILURE_FAN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) }
^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) static void wf_smu_create_drive_fans(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) struct wf_pid_param param = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) .interval = 5,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) .history_len = 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) .gd = 0x01e00000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) .gp = 0x00500000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) .gr = 0x00000000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) .itarget = 0x00200000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) /* Alloc & initialize state */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) wf_smu_drive_fans = kmalloc(sizeof(struct wf_smu_drive_fans_state),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) if (wf_smu_drive_fans == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) printk(KERN_WARNING "windfarm: Memory allocation error"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) " max fan speed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) wf_smu_drive_fans->ticks = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) /* Fill PID params */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) param.additive = (fan_hd->type == WF_CONTROL_RPM_FAN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) param.min = wf_control_get_min(fan_hd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) param.max = wf_control_get_max(fan_hd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) wf_pid_init(&wf_smu_drive_fans->pid, ¶m);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) DBG("wf: Drive Fan control initialized.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) DBG(" itarged=%d.%03d, min=%d RPM, max=%d RPM\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) FIX32TOPRINT(param.itarget), param.min, param.max);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) fail:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) if (fan_hd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) wf_control_set_max(fan_hd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) static void wf_smu_drive_fans_tick(struct wf_smu_drive_fans_state *st)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) s32 new_setpoint, temp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) if (--st->ticks != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) if (wf_smu_readjust)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) goto readjust;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) st->ticks = st->pid.param.interval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) rc = wf_sensor_get(sensor_hd_temp, &temp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) if (rc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) printk(KERN_WARNING "windfarm: HD temp sensor error %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) rc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) wf_smu_failure_state |= FAILURE_SENSOR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) DBG("wf_smu: Drive Fans tick ! HD temp: %d.%03d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) FIX32TOPRINT(temp));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) if (temp > (st->pid.param.itarget + 0x50000))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) wf_smu_failure_state |= FAILURE_OVERTEMP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) new_setpoint = wf_pid_run(&st->pid, temp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) DBG("wf_smu: new_setpoint: %d\n", (int)new_setpoint);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) if (st->setpoint == new_setpoint)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) st->setpoint = new_setpoint;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) readjust:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) if (fan_hd && wf_smu_failure_state == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) rc = wf_control_set(fan_hd, st->setpoint);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) if (rc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) printk(KERN_WARNING "windfarm: HD fan error %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) rc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) wf_smu_failure_state |= FAILURE_FAN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) static void wf_smu_create_slots_fans(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) struct wf_pid_param param = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) .interval = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) .history_len = 8,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) .gd = 0x00000000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) .gp = 0x00000000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) .gr = 0x00020000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) .itarget = 0x00000000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) /* Alloc & initialize state */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) wf_smu_slots_fans = kmalloc(sizeof(struct wf_smu_slots_fans_state),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) if (wf_smu_slots_fans == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) printk(KERN_WARNING "windfarm: Memory allocation error"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) " max fan speed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) wf_smu_slots_fans->ticks = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) /* Fill PID params */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) param.additive = (fan_slots->type == WF_CONTROL_RPM_FAN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) param.min = wf_control_get_min(fan_slots);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) param.max = wf_control_get_max(fan_slots);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) wf_pid_init(&wf_smu_slots_fans->pid, ¶m);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) DBG("wf: Slots Fan control initialized.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) DBG(" itarged=%d.%03d, min=%d RPM, max=%d RPM\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) FIX32TOPRINT(param.itarget), param.min, param.max);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) fail:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) if (fan_slots)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) wf_control_set_max(fan_slots);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) static void wf_smu_slots_fans_tick(struct wf_smu_slots_fans_state *st)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) s32 new_setpoint, power;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) if (--st->ticks != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) if (wf_smu_readjust)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) goto readjust;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) st->ticks = st->pid.param.interval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) rc = wf_sensor_get(sensor_slots_power, &power);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) if (rc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) printk(KERN_WARNING "windfarm: Slots power sensor error %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) rc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) wf_smu_failure_state |= FAILURE_SENSOR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) DBG("wf_smu: Slots Fans tick ! Slots power: %d.%03d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) FIX32TOPRINT(power));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) #if 0 /* Check what makes a good overtemp condition */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) if (power > (st->pid.param.itarget + 0x50000))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) wf_smu_failure_state |= FAILURE_OVERTEMP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) new_setpoint = wf_pid_run(&st->pid, power);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) DBG("wf_smu: new_setpoint: %d\n", (int)new_setpoint);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) if (st->setpoint == new_setpoint)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) st->setpoint = new_setpoint;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) readjust:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) if (fan_slots && wf_smu_failure_state == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) rc = wf_control_set(fan_slots, st->setpoint);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) if (rc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) printk(KERN_WARNING "windfarm: Slots fan error %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) rc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) wf_smu_failure_state |= FAILURE_FAN;
^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) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) * ****** Setup / Init / Misc ... ******
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) static void wf_smu_tick(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) unsigned int last_failure = wf_smu_failure_state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) unsigned int new_failure;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) if (!wf_smu_started) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) DBG("wf: creating control loops !\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) wf_smu_create_drive_fans();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) wf_smu_create_slots_fans();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) wf_smu_create_cpu_fans();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) wf_smu_started = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) /* Skipping ticks */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) if (wf_smu_skipping && --wf_smu_skipping)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) wf_smu_failure_state = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) if (wf_smu_drive_fans)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) wf_smu_drive_fans_tick(wf_smu_drive_fans);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) if (wf_smu_slots_fans)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) wf_smu_slots_fans_tick(wf_smu_slots_fans);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) if (wf_smu_cpu_fans)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) wf_smu_cpu_fans_tick(wf_smu_cpu_fans);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) wf_smu_readjust = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) new_failure = wf_smu_failure_state & ~last_failure;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) /* If entering failure mode, clamp cpufreq and ramp all
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) * fans to full speed.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) if (wf_smu_failure_state && !last_failure) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) if (cpufreq_clamp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) wf_control_set_max(cpufreq_clamp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) if (fan_cpu_main)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) wf_control_set_max(fan_cpu_main);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) if (fan_cpu_second)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) wf_control_set_max(fan_cpu_second);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) if (fan_cpu_third)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) wf_control_set_max(fan_cpu_third);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) if (fan_hd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) wf_control_set_max(fan_hd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) if (fan_slots)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) wf_control_set_max(fan_slots);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) /* If leaving failure mode, unclamp cpufreq and readjust
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) * all fans on next iteration
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) if (!wf_smu_failure_state && last_failure) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) if (cpufreq_clamp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) wf_control_set_min(cpufreq_clamp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) wf_smu_readjust = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) /* Overtemp condition detected, notify and start skipping a couple
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) * ticks to let the temperature go down
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) if (new_failure & FAILURE_OVERTEMP) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) wf_set_overtemp();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) wf_smu_skipping = 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) wf_smu_overtemp = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) /* We only clear the overtemp condition if overtemp is cleared
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) * _and_ no other failure is present. Since a sensor error will
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) * clear the overtemp condition (can't measure temperature) at
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) * the control loop levels, but we don't want to keep it clear
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) * here in this case
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) if (!wf_smu_failure_state && wf_smu_overtemp) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) wf_clear_overtemp();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) wf_smu_overtemp = false;
^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)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) static void wf_smu_new_control(struct wf_control *ct)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) if (wf_smu_all_controls_ok)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) if (fan_cpu_main == NULL && !strcmp(ct->name, "cpu-rear-fan-0")) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) if (wf_get_control(ct) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) fan_cpu_main = ct;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) if (fan_cpu_second == NULL && !strcmp(ct->name, "cpu-rear-fan-1")) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) if (wf_get_control(ct) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) fan_cpu_second = ct;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) if (fan_cpu_third == NULL && !strcmp(ct->name, "cpu-front-fan-0")) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) if (wf_get_control(ct) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) fan_cpu_third = ct;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) if (cpufreq_clamp == NULL && !strcmp(ct->name, "cpufreq-clamp")) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) if (wf_get_control(ct) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) cpufreq_clamp = ct;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) if (fan_hd == NULL && !strcmp(ct->name, "drive-bay-fan")) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) if (wf_get_control(ct) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) fan_hd = ct;
^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) if (fan_slots == NULL && !strcmp(ct->name, "slots-fan")) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) if (wf_get_control(ct) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) fan_slots = ct;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) if (fan_cpu_main && (fan_cpu_second || fan_cpu_third) && fan_hd &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) fan_slots && cpufreq_clamp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) wf_smu_all_controls_ok = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) static void wf_smu_new_sensor(struct wf_sensor *sr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) if (wf_smu_all_sensors_ok)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) if (sensor_cpu_power == NULL && !strcmp(sr->name, "cpu-power")) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) if (wf_get_sensor(sr) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) sensor_cpu_power = sr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) if (sensor_cpu_temp == NULL && !strcmp(sr->name, "cpu-temp")) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) if (wf_get_sensor(sr) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) sensor_cpu_temp = sr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) if (sensor_hd_temp == NULL && !strcmp(sr->name, "hd-temp")) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) if (wf_get_sensor(sr) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) sensor_hd_temp = sr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) if (sensor_slots_power == NULL && !strcmp(sr->name, "slots-power")) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) if (wf_get_sensor(sr) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) sensor_slots_power = sr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) if (sensor_cpu_power && sensor_cpu_temp &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) sensor_hd_temp && sensor_slots_power)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) wf_smu_all_sensors_ok = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) static int wf_smu_notify(struct notifier_block *self,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) unsigned long event, void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) switch(event) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) case WF_EVENT_NEW_CONTROL:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) DBG("wf: new control %s detected\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) ((struct wf_control *)data)->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) wf_smu_new_control(data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) wf_smu_readjust = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) case WF_EVENT_NEW_SENSOR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) DBG("wf: new sensor %s detected\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) ((struct wf_sensor *)data)->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) wf_smu_new_sensor(data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) case WF_EVENT_TICK:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) if (wf_smu_all_controls_ok && wf_smu_all_sensors_ok)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) wf_smu_tick();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) static struct notifier_block wf_smu_events = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) .notifier_call = wf_smu_notify,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) static int wf_init_pm(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) printk(KERN_INFO "windfarm: Initializing for Desktop G5 model\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) static int wf_smu_probe(struct platform_device *ddev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) wf_register_client(&wf_smu_events);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) static int wf_smu_remove(struct platform_device *ddev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) wf_unregister_client(&wf_smu_events);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) /* XXX We don't have yet a guarantee that our callback isn't
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) * in progress when returning from wf_unregister_client, so
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) * we add an arbitrary delay. I'll have to fix that in the core
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) msleep(1000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) /* Release all sensors */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) /* One more crappy race: I don't think we have any guarantee here
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) * that the attribute callback won't race with the sensor beeing
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) * disposed of, and I'm not 100% certain what best way to deal
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) * with that except by adding locks all over... I'll do that
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) * eventually but heh, who ever rmmod this module anyway ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) if (sensor_cpu_power)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) wf_put_sensor(sensor_cpu_power);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) if (sensor_cpu_temp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) wf_put_sensor(sensor_cpu_temp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) if (sensor_hd_temp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) wf_put_sensor(sensor_hd_temp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) if (sensor_slots_power)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) wf_put_sensor(sensor_slots_power);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) /* Release all controls */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) if (fan_cpu_main)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) wf_put_control(fan_cpu_main);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) if (fan_cpu_second)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) wf_put_control(fan_cpu_second);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) if (fan_cpu_third)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) wf_put_control(fan_cpu_third);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) if (fan_hd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) wf_put_control(fan_hd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) if (fan_slots)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) wf_put_control(fan_slots);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) if (cpufreq_clamp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) wf_put_control(cpufreq_clamp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) /* Destroy control loops state structures */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) kfree(wf_smu_slots_fans);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) kfree(wf_smu_drive_fans);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) kfree(wf_smu_cpu_fans);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) static struct platform_driver wf_smu_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) .probe = wf_smu_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) .remove = wf_smu_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) .name = "windfarm",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) static int __init wf_smu_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) int rc = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) if (of_machine_is_compatible("PowerMac9,1"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) rc = wf_init_pm();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) if (rc == 0) {
^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_smu_controls");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) request_module("windfarm_smu_sensors");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) request_module("windfarm_lm75_sensor");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) request_module("windfarm_cpufreq_clamp");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) #endif /* MODULE */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) platform_driver_register(&wf_smu_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) return rc;
^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_smu_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) platform_driver_unregister(&wf_smu_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) module_init(wf_smu_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) module_exit(wf_smu_exit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) MODULE_DESCRIPTION("Thermal control logic for PowerMac9,1");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) MODULE_ALIAS("platform:windfarm");