1ddceed9dSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2ac171c46SBenjamin Herrenschmidt /*
3ac171c46SBenjamin Herrenschmidt * Windfarm PowerMac thermal control.
4ac171c46SBenjamin Herrenschmidt * Control loops for machines with SMU and PPC970MP processors.
5ac171c46SBenjamin Herrenschmidt *
6ac171c46SBenjamin Herrenschmidt * Copyright (C) 2005 Paul Mackerras, IBM Corp. <paulus@samba.org>
7ac171c46SBenjamin Herrenschmidt * Copyright (C) 2006 Benjamin Herrenschmidt, IBM Corp.
8ac171c46SBenjamin Herrenschmidt */
9ac171c46SBenjamin Herrenschmidt #include <linux/types.h>
10ac171c46SBenjamin Herrenschmidt #include <linux/errno.h>
11ac171c46SBenjamin Herrenschmidt #include <linux/kernel.h>
12ac171c46SBenjamin Herrenschmidt #include <linux/device.h>
13ac171c46SBenjamin Herrenschmidt #include <linux/platform_device.h>
14ac171c46SBenjamin Herrenschmidt #include <linux/reboot.h>
15*a486e512SChristophe Leroy #include <linux/of.h>
16*a486e512SChristophe Leroy #include <linux/slab.h>
17*a486e512SChristophe Leroy
18ac171c46SBenjamin Herrenschmidt #include <asm/smu.h>
19ac171c46SBenjamin Herrenschmidt
20ac171c46SBenjamin Herrenschmidt #include "windfarm.h"
21ac171c46SBenjamin Herrenschmidt #include "windfarm_pid.h"
22ac171c46SBenjamin Herrenschmidt
23ac171c46SBenjamin Herrenschmidt #define VERSION "0.2"
24ac171c46SBenjamin Herrenschmidt
25ac171c46SBenjamin Herrenschmidt #define DEBUG
26ac171c46SBenjamin Herrenschmidt #undef LOTSA_DEBUG
27ac171c46SBenjamin Herrenschmidt
28ac171c46SBenjamin Herrenschmidt #ifdef DEBUG
29ac171c46SBenjamin Herrenschmidt #define DBG(args...) printk(args)
30ac171c46SBenjamin Herrenschmidt #else
31ac171c46SBenjamin Herrenschmidt #define DBG(args...) do { } while(0)
32ac171c46SBenjamin Herrenschmidt #endif
33ac171c46SBenjamin Herrenschmidt
34ac171c46SBenjamin Herrenschmidt #ifdef LOTSA_DEBUG
35ac171c46SBenjamin Herrenschmidt #define DBG_LOTS(args...) printk(args)
36ac171c46SBenjamin Herrenschmidt #else
37ac171c46SBenjamin Herrenschmidt #define DBG_LOTS(args...) do { } while(0)
38ac171c46SBenjamin Herrenschmidt #endif
39ac171c46SBenjamin Herrenschmidt
40ac171c46SBenjamin Herrenschmidt /* define this to force CPU overtemp to 60 degree, useful for testing
41ac171c46SBenjamin Herrenschmidt * the overtemp code
42ac171c46SBenjamin Herrenschmidt */
43ac171c46SBenjamin Herrenschmidt #undef HACKED_OVERTEMP
44ac171c46SBenjamin Herrenschmidt
45ac171c46SBenjamin Herrenschmidt /* We currently only handle 2 chips, 4 cores... */
46ac171c46SBenjamin Herrenschmidt #define NR_CHIPS 2
47ac171c46SBenjamin Herrenschmidt #define NR_CORES 4
48ac171c46SBenjamin Herrenschmidt #define NR_CPU_FANS 3 * NR_CHIPS
49ac171c46SBenjamin Herrenschmidt
50ac171c46SBenjamin Herrenschmidt /* Controls and sensors */
51ac171c46SBenjamin Herrenschmidt static struct wf_sensor *sens_cpu_temp[NR_CORES];
52ac171c46SBenjamin Herrenschmidt static struct wf_sensor *sens_cpu_power[NR_CORES];
53ac171c46SBenjamin Herrenschmidt static struct wf_sensor *hd_temp;
54ac171c46SBenjamin Herrenschmidt static struct wf_sensor *slots_power;
55ac171c46SBenjamin Herrenschmidt static struct wf_sensor *u4_temp;
56ac171c46SBenjamin Herrenschmidt
57ac171c46SBenjamin Herrenschmidt static struct wf_control *cpu_fans[NR_CPU_FANS];
58ac171c46SBenjamin Herrenschmidt static char *cpu_fan_names[NR_CPU_FANS] = {
59ac171c46SBenjamin Herrenschmidt "cpu-rear-fan-0",
60ac171c46SBenjamin Herrenschmidt "cpu-rear-fan-1",
61ac171c46SBenjamin Herrenschmidt "cpu-front-fan-0",
62ac171c46SBenjamin Herrenschmidt "cpu-front-fan-1",
63ac171c46SBenjamin Herrenschmidt "cpu-pump-0",
64ac171c46SBenjamin Herrenschmidt "cpu-pump-1",
65ac171c46SBenjamin Herrenschmidt };
66ac171c46SBenjamin Herrenschmidt static struct wf_control *cpufreq_clamp;
67ac171c46SBenjamin Herrenschmidt
68ac171c46SBenjamin Herrenschmidt /* Second pump isn't required (and isn't actually present) */
69ac171c46SBenjamin Herrenschmidt #define CPU_FANS_REQD (NR_CPU_FANS - 2)
70ac171c46SBenjamin Herrenschmidt #define FIRST_PUMP 4
71ac171c46SBenjamin Herrenschmidt #define LAST_PUMP 5
72ac171c46SBenjamin Herrenschmidt
73ac171c46SBenjamin Herrenschmidt /* We keep a temperature history for average calculation of 180s */
74ac171c46SBenjamin Herrenschmidt #define CPU_TEMP_HIST_SIZE 180
75ac171c46SBenjamin Herrenschmidt
76ac171c46SBenjamin Herrenschmidt /* Scale factor for fan speed, *100 */
77ac171c46SBenjamin Herrenschmidt static int cpu_fan_scale[NR_CPU_FANS] = {
78ac171c46SBenjamin Herrenschmidt 100,
79ac171c46SBenjamin Herrenschmidt 100,
80ac171c46SBenjamin Herrenschmidt 97, /* inlet fans run at 97% of exhaust fan */
81ac171c46SBenjamin Herrenschmidt 97,
82ac171c46SBenjamin Herrenschmidt 100, /* updated later */
83ac171c46SBenjamin Herrenschmidt 100, /* updated later */
84ac171c46SBenjamin Herrenschmidt };
85ac171c46SBenjamin Herrenschmidt
86ac171c46SBenjamin Herrenschmidt static struct wf_control *backside_fan;
87ac171c46SBenjamin Herrenschmidt static struct wf_control *slots_fan;
88ac171c46SBenjamin Herrenschmidt static struct wf_control *drive_bay_fan;
89ac171c46SBenjamin Herrenschmidt
90ac171c46SBenjamin Herrenschmidt /* PID loop state */
91ac171c46SBenjamin Herrenschmidt static struct wf_cpu_pid_state cpu_pid[NR_CORES];
92ac171c46SBenjamin Herrenschmidt static u32 cpu_thist[CPU_TEMP_HIST_SIZE];
93ac171c46SBenjamin Herrenschmidt static int cpu_thist_pt;
94ac171c46SBenjamin Herrenschmidt static s64 cpu_thist_total;
95ac171c46SBenjamin Herrenschmidt static s32 cpu_all_tmax = 100 << 16;
96ac171c46SBenjamin Herrenschmidt static int cpu_last_target;
97ac171c46SBenjamin Herrenschmidt static struct wf_pid_state backside_pid;
98ac171c46SBenjamin Herrenschmidt static int backside_tick;
99ac171c46SBenjamin Herrenschmidt static struct wf_pid_state slots_pid;
1004f256d56SGustavo A. R. Silva static bool slots_started;
101ac171c46SBenjamin Herrenschmidt static struct wf_pid_state drive_bay_pid;
102ac171c46SBenjamin Herrenschmidt static int drive_bay_tick;
103ac171c46SBenjamin Herrenschmidt
104ac171c46SBenjamin Herrenschmidt static int nr_cores;
105ac171c46SBenjamin Herrenschmidt static int have_all_controls;
106ac171c46SBenjamin Herrenschmidt static int have_all_sensors;
1074f256d56SGustavo A. R. Silva static bool started;
108ac171c46SBenjamin Herrenschmidt
109ac171c46SBenjamin Herrenschmidt static int failure_state;
110ac171c46SBenjamin Herrenschmidt #define FAILURE_SENSOR 1
111ac171c46SBenjamin Herrenschmidt #define FAILURE_FAN 2
112ac171c46SBenjamin Herrenschmidt #define FAILURE_PERM 4
113ac171c46SBenjamin Herrenschmidt #define FAILURE_LOW_OVERTEMP 8
114ac171c46SBenjamin Herrenschmidt #define FAILURE_HIGH_OVERTEMP 16
115ac171c46SBenjamin Herrenschmidt
116ac171c46SBenjamin Herrenschmidt /* Overtemp values */
117ac171c46SBenjamin Herrenschmidt #define LOW_OVER_AVERAGE 0
118ac171c46SBenjamin Herrenschmidt #define LOW_OVER_IMMEDIATE (10 << 16)
119ac171c46SBenjamin Herrenschmidt #define LOW_OVER_CLEAR ((-10) << 16)
120ac171c46SBenjamin Herrenschmidt #define HIGH_OVER_IMMEDIATE (14 << 16)
121ac171c46SBenjamin Herrenschmidt #define HIGH_OVER_AVERAGE (10 << 16)
122ac171c46SBenjamin Herrenschmidt #define HIGH_OVER_IMMEDIATE (14 << 16)
123ac171c46SBenjamin Herrenschmidt
124ac171c46SBenjamin Herrenschmidt
125ac171c46SBenjamin Herrenschmidt /* Implementation... */
create_cpu_loop(int cpu)126ac171c46SBenjamin Herrenschmidt static int create_cpu_loop(int cpu)
127ac171c46SBenjamin Herrenschmidt {
128ac171c46SBenjamin Herrenschmidt int chip = cpu / 2;
129ac171c46SBenjamin Herrenschmidt int core = cpu & 1;
130ac171c46SBenjamin Herrenschmidt struct smu_sdbp_header *hdr;
131ac171c46SBenjamin Herrenschmidt struct smu_sdbp_cpupiddata *piddata;
132ac171c46SBenjamin Herrenschmidt struct wf_cpu_pid_param pid;
133ac171c46SBenjamin Herrenschmidt struct wf_control *main_fan = cpu_fans[0];
134ac171c46SBenjamin Herrenschmidt s32 tmax;
135ac171c46SBenjamin Herrenschmidt int fmin;
136ac171c46SBenjamin Herrenschmidt
137ac171c46SBenjamin Herrenschmidt /* Get FVT params to get Tmax; if not found, assume default */
138ac171c46SBenjamin Herrenschmidt hdr = smu_sat_get_sdb_partition(chip, 0xC4 + core, NULL);
139ac171c46SBenjamin Herrenschmidt if (hdr) {
140ac171c46SBenjamin Herrenschmidt struct smu_sdbp_fvt *fvt = (struct smu_sdbp_fvt *)&hdr[1];
141ac171c46SBenjamin Herrenschmidt tmax = fvt->maxtemp << 16;
142ac171c46SBenjamin Herrenschmidt } else
143ac171c46SBenjamin Herrenschmidt tmax = 95 << 16; /* default to 95 degrees C */
144ac171c46SBenjamin Herrenschmidt
145ac171c46SBenjamin Herrenschmidt /* We keep a global tmax for overtemp calculations */
146ac171c46SBenjamin Herrenschmidt if (tmax < cpu_all_tmax)
147ac171c46SBenjamin Herrenschmidt cpu_all_tmax = tmax;
148ac171c46SBenjamin Herrenschmidt
14993900337SMichael Ellerman kfree(hdr);
15093900337SMichael Ellerman
15193900337SMichael Ellerman /* Get PID params from the appropriate SAT */
15293900337SMichael Ellerman hdr = smu_sat_get_sdb_partition(chip, 0xC8 + core, NULL);
15393900337SMichael Ellerman if (hdr == NULL) {
15493900337SMichael Ellerman printk(KERN_WARNING"windfarm: can't get CPU PID fan config\n");
15593900337SMichael Ellerman return -EINVAL;
15693900337SMichael Ellerman }
15793900337SMichael Ellerman piddata = (struct smu_sdbp_cpupiddata *)&hdr[1];
15893900337SMichael Ellerman
159ac171c46SBenjamin Herrenschmidt /*
160ac171c46SBenjamin Herrenschmidt * Darwin has a minimum fan speed of 1000 rpm for the 4-way and
161ac171c46SBenjamin Herrenschmidt * 515 for the 2-way. That appears to be overkill, so for now,
162ac171c46SBenjamin Herrenschmidt * impose a minimum of 750 or 515.
163ac171c46SBenjamin Herrenschmidt */
164ac171c46SBenjamin Herrenschmidt fmin = (nr_cores > 2) ? 750 : 515;
165ac171c46SBenjamin Herrenschmidt
166ac171c46SBenjamin Herrenschmidt /* Initialize PID loop */
167ac171c46SBenjamin Herrenschmidt pid.interval = 1; /* seconds */
168ac171c46SBenjamin Herrenschmidt pid.history_len = piddata->history_len;
169ac171c46SBenjamin Herrenschmidt pid.gd = piddata->gd;
170ac171c46SBenjamin Herrenschmidt pid.gp = piddata->gp;
171ac171c46SBenjamin Herrenschmidt pid.gr = piddata->gr / piddata->history_len;
172ac171c46SBenjamin Herrenschmidt pid.pmaxadj = (piddata->max_power << 16) - (piddata->power_adj << 8);
173ac171c46SBenjamin Herrenschmidt pid.ttarget = tmax - (piddata->target_temp_delta << 16);
174ac171c46SBenjamin Herrenschmidt pid.tmax = tmax;
175ac171c46SBenjamin Herrenschmidt pid.min = main_fan->ops->get_min(main_fan);
176ac171c46SBenjamin Herrenschmidt pid.max = main_fan->ops->get_max(main_fan);
177ac171c46SBenjamin Herrenschmidt if (pid.min < fmin)
178ac171c46SBenjamin Herrenschmidt pid.min = fmin;
179ac171c46SBenjamin Herrenschmidt
180ac171c46SBenjamin Herrenschmidt wf_cpu_pid_init(&cpu_pid[cpu], &pid);
18193900337SMichael Ellerman
18293900337SMichael Ellerman kfree(hdr);
18393900337SMichael Ellerman
184ac171c46SBenjamin Herrenschmidt return 0;
185ac171c46SBenjamin Herrenschmidt }
186ac171c46SBenjamin Herrenschmidt
cpu_max_all_fans(void)187ac171c46SBenjamin Herrenschmidt static void cpu_max_all_fans(void)
188ac171c46SBenjamin Herrenschmidt {
189ac171c46SBenjamin Herrenschmidt int i;
190ac171c46SBenjamin Herrenschmidt
191ac171c46SBenjamin Herrenschmidt /* We max all CPU fans in case of a sensor error. We also do the
192ac171c46SBenjamin Herrenschmidt * cpufreq clamping now, even if it's supposedly done later by the
193ac171c46SBenjamin Herrenschmidt * generic code anyway, we do it earlier here to react faster
194ac171c46SBenjamin Herrenschmidt */
195ac171c46SBenjamin Herrenschmidt if (cpufreq_clamp)
196ac171c46SBenjamin Herrenschmidt wf_control_set_max(cpufreq_clamp);
197ac171c46SBenjamin Herrenschmidt for (i = 0; i < NR_CPU_FANS; ++i)
198ac171c46SBenjamin Herrenschmidt if (cpu_fans[i])
199ac171c46SBenjamin Herrenschmidt wf_control_set_max(cpu_fans[i]);
200ac171c46SBenjamin Herrenschmidt }
201ac171c46SBenjamin Herrenschmidt
cpu_check_overtemp(s32 temp)202ac171c46SBenjamin Herrenschmidt static int cpu_check_overtemp(s32 temp)
203ac171c46SBenjamin Herrenschmidt {
204ac171c46SBenjamin Herrenschmidt int new_state = 0;
205ac171c46SBenjamin Herrenschmidt s32 t_avg, t_old;
206ac171c46SBenjamin Herrenschmidt
207ac171c46SBenjamin Herrenschmidt /* First check for immediate overtemps */
208ac171c46SBenjamin Herrenschmidt if (temp >= (cpu_all_tmax + LOW_OVER_IMMEDIATE)) {
209ac171c46SBenjamin Herrenschmidt new_state |= FAILURE_LOW_OVERTEMP;
210ac171c46SBenjamin Herrenschmidt if ((failure_state & FAILURE_LOW_OVERTEMP) == 0)
211ac171c46SBenjamin Herrenschmidt printk(KERN_ERR "windfarm: Overtemp due to immediate CPU"
212ac171c46SBenjamin Herrenschmidt " temperature !\n");
213ac171c46SBenjamin Herrenschmidt }
214ac171c46SBenjamin Herrenschmidt if (temp >= (cpu_all_tmax + HIGH_OVER_IMMEDIATE)) {
215ac171c46SBenjamin Herrenschmidt new_state |= FAILURE_HIGH_OVERTEMP;
216ac171c46SBenjamin Herrenschmidt if ((failure_state & FAILURE_HIGH_OVERTEMP) == 0)
217ac171c46SBenjamin Herrenschmidt printk(KERN_ERR "windfarm: Critical overtemp due to"
218ac171c46SBenjamin Herrenschmidt " immediate CPU temperature !\n");
219ac171c46SBenjamin Herrenschmidt }
220ac171c46SBenjamin Herrenschmidt
221ac171c46SBenjamin Herrenschmidt /* We calculate a history of max temperatures and use that for the
222ac171c46SBenjamin Herrenschmidt * overtemp management
223ac171c46SBenjamin Herrenschmidt */
224ac171c46SBenjamin Herrenschmidt t_old = cpu_thist[cpu_thist_pt];
225ac171c46SBenjamin Herrenschmidt cpu_thist[cpu_thist_pt] = temp;
226ac171c46SBenjamin Herrenschmidt cpu_thist_pt = (cpu_thist_pt + 1) % CPU_TEMP_HIST_SIZE;
227ac171c46SBenjamin Herrenschmidt cpu_thist_total -= t_old;
228ac171c46SBenjamin Herrenschmidt cpu_thist_total += temp;
229ac171c46SBenjamin Herrenschmidt t_avg = cpu_thist_total / CPU_TEMP_HIST_SIZE;
230ac171c46SBenjamin Herrenschmidt
231ac171c46SBenjamin Herrenschmidt DBG_LOTS("t_avg = %d.%03d (out: %d.%03d, in: %d.%03d)\n",
232ac171c46SBenjamin Herrenschmidt FIX32TOPRINT(t_avg), FIX32TOPRINT(t_old), FIX32TOPRINT(temp));
233ac171c46SBenjamin Herrenschmidt
234ac171c46SBenjamin Herrenschmidt /* Now check for average overtemps */
235ac171c46SBenjamin Herrenschmidt if (t_avg >= (cpu_all_tmax + LOW_OVER_AVERAGE)) {
236ac171c46SBenjamin Herrenschmidt new_state |= FAILURE_LOW_OVERTEMP;
237ac171c46SBenjamin Herrenschmidt if ((failure_state & FAILURE_LOW_OVERTEMP) == 0)
238ac171c46SBenjamin Herrenschmidt printk(KERN_ERR "windfarm: Overtemp due to average CPU"
239ac171c46SBenjamin Herrenschmidt " temperature !\n");
240ac171c46SBenjamin Herrenschmidt }
241ac171c46SBenjamin Herrenschmidt if (t_avg >= (cpu_all_tmax + HIGH_OVER_AVERAGE)) {
242ac171c46SBenjamin Herrenschmidt new_state |= FAILURE_HIGH_OVERTEMP;
243ac171c46SBenjamin Herrenschmidt if ((failure_state & FAILURE_HIGH_OVERTEMP) == 0)
244ac171c46SBenjamin Herrenschmidt printk(KERN_ERR "windfarm: Critical overtemp due to"
245ac171c46SBenjamin Herrenschmidt " average CPU temperature !\n");
246ac171c46SBenjamin Herrenschmidt }
247ac171c46SBenjamin Herrenschmidt
248ac171c46SBenjamin Herrenschmidt /* Now handle overtemp conditions. We don't currently use the windfarm
249ac171c46SBenjamin Herrenschmidt * overtemp handling core as it's not fully suited to the needs of those
250ac171c46SBenjamin Herrenschmidt * new machine. This will be fixed later.
251ac171c46SBenjamin Herrenschmidt */
252ac171c46SBenjamin Herrenschmidt if (new_state) {
253ac171c46SBenjamin Herrenschmidt /* High overtemp -> immediate shutdown */
254ac171c46SBenjamin Herrenschmidt if (new_state & FAILURE_HIGH_OVERTEMP)
255ac171c46SBenjamin Herrenschmidt machine_power_off();
256ac171c46SBenjamin Herrenschmidt if ((failure_state & new_state) != new_state)
257ac171c46SBenjamin Herrenschmidt cpu_max_all_fans();
258ac171c46SBenjamin Herrenschmidt failure_state |= new_state;
259ac171c46SBenjamin Herrenschmidt } else if ((failure_state & FAILURE_LOW_OVERTEMP) &&
260ac171c46SBenjamin Herrenschmidt (temp < (cpu_all_tmax + LOW_OVER_CLEAR))) {
261ac171c46SBenjamin Herrenschmidt printk(KERN_ERR "windfarm: Overtemp condition cleared !\n");
262ac171c46SBenjamin Herrenschmidt failure_state &= ~FAILURE_LOW_OVERTEMP;
263ac171c46SBenjamin Herrenschmidt }
264ac171c46SBenjamin Herrenschmidt
265ac171c46SBenjamin Herrenschmidt return failure_state & (FAILURE_LOW_OVERTEMP | FAILURE_HIGH_OVERTEMP);
266ac171c46SBenjamin Herrenschmidt }
267ac171c46SBenjamin Herrenschmidt
cpu_fans_tick(void)268ac171c46SBenjamin Herrenschmidt static void cpu_fans_tick(void)
269ac171c46SBenjamin Herrenschmidt {
270ac171c46SBenjamin Herrenschmidt int err, cpu;
271ac171c46SBenjamin Herrenschmidt s32 greatest_delta = 0;
272ac171c46SBenjamin Herrenschmidt s32 temp, power, t_max = 0;
273ac171c46SBenjamin Herrenschmidt int i, t, target = 0;
274ac171c46SBenjamin Herrenschmidt struct wf_sensor *sr;
275ac171c46SBenjamin Herrenschmidt struct wf_control *ct;
276ac171c46SBenjamin Herrenschmidt struct wf_cpu_pid_state *sp;
277ac171c46SBenjamin Herrenschmidt
278ac171c46SBenjamin Herrenschmidt DBG_LOTS(KERN_DEBUG);
279ac171c46SBenjamin Herrenschmidt for (cpu = 0; cpu < nr_cores; ++cpu) {
280ac171c46SBenjamin Herrenschmidt /* Get CPU core temperature */
281ac171c46SBenjamin Herrenschmidt sr = sens_cpu_temp[cpu];
282ac171c46SBenjamin Herrenschmidt err = sr->ops->get_value(sr, &temp);
283ac171c46SBenjamin Herrenschmidt if (err) {
284ac171c46SBenjamin Herrenschmidt DBG("\n");
285ac171c46SBenjamin Herrenschmidt printk(KERN_WARNING "windfarm: CPU %d temperature "
286ac171c46SBenjamin Herrenschmidt "sensor error %d\n", cpu, err);
287ac171c46SBenjamin Herrenschmidt failure_state |= FAILURE_SENSOR;
288ac171c46SBenjamin Herrenschmidt cpu_max_all_fans();
289ac171c46SBenjamin Herrenschmidt return;
290ac171c46SBenjamin Herrenschmidt }
291ac171c46SBenjamin Herrenschmidt
292ac171c46SBenjamin Herrenschmidt /* Keep track of highest temp */
293ac171c46SBenjamin Herrenschmidt t_max = max(t_max, temp);
294ac171c46SBenjamin Herrenschmidt
295ac171c46SBenjamin Herrenschmidt /* Get CPU power */
296ac171c46SBenjamin Herrenschmidt sr = sens_cpu_power[cpu];
297ac171c46SBenjamin Herrenschmidt err = sr->ops->get_value(sr, &power);
298ac171c46SBenjamin Herrenschmidt if (err) {
299ac171c46SBenjamin Herrenschmidt DBG("\n");
300ac171c46SBenjamin Herrenschmidt printk(KERN_WARNING "windfarm: CPU %d power "
301ac171c46SBenjamin Herrenschmidt "sensor error %d\n", cpu, err);
302ac171c46SBenjamin Herrenschmidt failure_state |= FAILURE_SENSOR;
303ac171c46SBenjamin Herrenschmidt cpu_max_all_fans();
304ac171c46SBenjamin Herrenschmidt return;
305ac171c46SBenjamin Herrenschmidt }
306ac171c46SBenjamin Herrenschmidt
307ac171c46SBenjamin Herrenschmidt /* Run PID */
308ac171c46SBenjamin Herrenschmidt sp = &cpu_pid[cpu];
309ac171c46SBenjamin Herrenschmidt t = wf_cpu_pid_run(sp, power, temp);
310ac171c46SBenjamin Herrenschmidt
311ac171c46SBenjamin Herrenschmidt if (cpu == 0 || sp->last_delta > greatest_delta) {
312ac171c46SBenjamin Herrenschmidt greatest_delta = sp->last_delta;
313ac171c46SBenjamin Herrenschmidt target = t;
314ac171c46SBenjamin Herrenschmidt }
315ac171c46SBenjamin Herrenschmidt DBG_LOTS("[%d] P=%d.%.3d T=%d.%.3d ",
316ac171c46SBenjamin Herrenschmidt cpu, FIX32TOPRINT(power), FIX32TOPRINT(temp));
317ac171c46SBenjamin Herrenschmidt }
318ac171c46SBenjamin Herrenschmidt DBG_LOTS("fans = %d, t_max = %d.%03d\n", target, FIX32TOPRINT(t_max));
319ac171c46SBenjamin Herrenschmidt
320ac171c46SBenjamin Herrenschmidt /* Darwin limits decrease to 20 per iteration */
321ac171c46SBenjamin Herrenschmidt if (target < (cpu_last_target - 20))
322ac171c46SBenjamin Herrenschmidt target = cpu_last_target - 20;
323ac171c46SBenjamin Herrenschmidt cpu_last_target = target;
324ac171c46SBenjamin Herrenschmidt for (cpu = 0; cpu < nr_cores; ++cpu)
325ac171c46SBenjamin Herrenschmidt cpu_pid[cpu].target = target;
326ac171c46SBenjamin Herrenschmidt
327ac171c46SBenjamin Herrenschmidt /* Handle possible overtemps */
328ac171c46SBenjamin Herrenschmidt if (cpu_check_overtemp(t_max))
329ac171c46SBenjamin Herrenschmidt return;
330ac171c46SBenjamin Herrenschmidt
331ac171c46SBenjamin Herrenschmidt /* Set fans */
332ac171c46SBenjamin Herrenschmidt for (i = 0; i < NR_CPU_FANS; ++i) {
333ac171c46SBenjamin Herrenschmidt ct = cpu_fans[i];
334ac171c46SBenjamin Herrenschmidt if (ct == NULL)
335ac171c46SBenjamin Herrenschmidt continue;
336ac171c46SBenjamin Herrenschmidt err = ct->ops->set_value(ct, target * cpu_fan_scale[i] / 100);
337ac171c46SBenjamin Herrenschmidt if (err) {
338ac171c46SBenjamin Herrenschmidt printk(KERN_WARNING "windfarm: fan %s reports "
339ac171c46SBenjamin Herrenschmidt "error %d\n", ct->name, err);
340ac171c46SBenjamin Herrenschmidt failure_state |= FAILURE_FAN;
341ac171c46SBenjamin Herrenschmidt break;
342ac171c46SBenjamin Herrenschmidt }
343ac171c46SBenjamin Herrenschmidt }
344ac171c46SBenjamin Herrenschmidt }
345ac171c46SBenjamin Herrenschmidt
346ac171c46SBenjamin Herrenschmidt /* Backside/U4 fan */
347ac171c46SBenjamin Herrenschmidt static struct wf_pid_param backside_param = {
348ac171c46SBenjamin Herrenschmidt .interval = 5,
349ac171c46SBenjamin Herrenschmidt .history_len = 2,
350ac171c46SBenjamin Herrenschmidt .gd = 48 << 20,
351ac171c46SBenjamin Herrenschmidt .gp = 5 << 20,
352ac171c46SBenjamin Herrenschmidt .gr = 0,
353ac171c46SBenjamin Herrenschmidt .itarget = 64 << 16,
354ac171c46SBenjamin Herrenschmidt .additive = 1,
355ac171c46SBenjamin Herrenschmidt };
356ac171c46SBenjamin Herrenschmidt
backside_fan_tick(void)357ac171c46SBenjamin Herrenschmidt static void backside_fan_tick(void)
358ac171c46SBenjamin Herrenschmidt {
359ac171c46SBenjamin Herrenschmidt s32 temp;
360ac171c46SBenjamin Herrenschmidt int speed;
361ac171c46SBenjamin Herrenschmidt int err;
362ac171c46SBenjamin Herrenschmidt
363ac171c46SBenjamin Herrenschmidt if (!backside_fan || !u4_temp)
364ac171c46SBenjamin Herrenschmidt return;
365ac171c46SBenjamin Herrenschmidt if (!backside_tick) {
366ac171c46SBenjamin Herrenschmidt /* first time; initialize things */
367e2a002b9SBenjamin Herrenschmidt printk(KERN_INFO "windfarm: Backside control loop started.\n");
368ac171c46SBenjamin Herrenschmidt backside_param.min = backside_fan->ops->get_min(backside_fan);
369ac171c46SBenjamin Herrenschmidt backside_param.max = backside_fan->ops->get_max(backside_fan);
370ac171c46SBenjamin Herrenschmidt wf_pid_init(&backside_pid, &backside_param);
371ac171c46SBenjamin Herrenschmidt backside_tick = 1;
372ac171c46SBenjamin Herrenschmidt }
373ac171c46SBenjamin Herrenschmidt if (--backside_tick > 0)
374ac171c46SBenjamin Herrenschmidt return;
375ac171c46SBenjamin Herrenschmidt backside_tick = backside_pid.param.interval;
376ac171c46SBenjamin Herrenschmidt
377ac171c46SBenjamin Herrenschmidt err = u4_temp->ops->get_value(u4_temp, &temp);
378ac171c46SBenjamin Herrenschmidt if (err) {
379ac171c46SBenjamin Herrenschmidt printk(KERN_WARNING "windfarm: U4 temp sensor error %d\n",
380ac171c46SBenjamin Herrenschmidt err);
381ac171c46SBenjamin Herrenschmidt failure_state |= FAILURE_SENSOR;
382ac171c46SBenjamin Herrenschmidt wf_control_set_max(backside_fan);
383ac171c46SBenjamin Herrenschmidt return;
384ac171c46SBenjamin Herrenschmidt }
385ac171c46SBenjamin Herrenschmidt speed = wf_pid_run(&backside_pid, temp);
386ac171c46SBenjamin Herrenschmidt DBG_LOTS("backside PID temp=%d.%.3d speed=%d\n",
387ac171c46SBenjamin Herrenschmidt FIX32TOPRINT(temp), speed);
388ac171c46SBenjamin Herrenschmidt
389ac171c46SBenjamin Herrenschmidt err = backside_fan->ops->set_value(backside_fan, speed);
390ac171c46SBenjamin Herrenschmidt if (err) {
391ac171c46SBenjamin Herrenschmidt printk(KERN_WARNING "windfarm: backside fan error %d\n", err);
392ac171c46SBenjamin Herrenschmidt failure_state |= FAILURE_FAN;
393ac171c46SBenjamin Herrenschmidt }
394ac171c46SBenjamin Herrenschmidt }
395ac171c46SBenjamin Herrenschmidt
396ac171c46SBenjamin Herrenschmidt /* Drive bay fan */
397ac171c46SBenjamin Herrenschmidt static struct wf_pid_param drive_bay_prm = {
398ac171c46SBenjamin Herrenschmidt .interval = 5,
399ac171c46SBenjamin Herrenschmidt .history_len = 2,
400ac171c46SBenjamin Herrenschmidt .gd = 30 << 20,
401ac171c46SBenjamin Herrenschmidt .gp = 5 << 20,
402ac171c46SBenjamin Herrenschmidt .gr = 0,
403ac171c46SBenjamin Herrenschmidt .itarget = 40 << 16,
404ac171c46SBenjamin Herrenschmidt .additive = 1,
405ac171c46SBenjamin Herrenschmidt };
406ac171c46SBenjamin Herrenschmidt
drive_bay_fan_tick(void)407ac171c46SBenjamin Herrenschmidt static void drive_bay_fan_tick(void)
408ac171c46SBenjamin Herrenschmidt {
409ac171c46SBenjamin Herrenschmidt s32 temp;
410ac171c46SBenjamin Herrenschmidt int speed;
411ac171c46SBenjamin Herrenschmidt int err;
412ac171c46SBenjamin Herrenschmidt
413ac171c46SBenjamin Herrenschmidt if (!drive_bay_fan || !hd_temp)
414ac171c46SBenjamin Herrenschmidt return;
415ac171c46SBenjamin Herrenschmidt if (!drive_bay_tick) {
416ac171c46SBenjamin Herrenschmidt /* first time; initialize things */
417e2a002b9SBenjamin Herrenschmidt printk(KERN_INFO "windfarm: Drive bay control loop started.\n");
418ac171c46SBenjamin Herrenschmidt drive_bay_prm.min = drive_bay_fan->ops->get_min(drive_bay_fan);
419ac171c46SBenjamin Herrenschmidt drive_bay_prm.max = drive_bay_fan->ops->get_max(drive_bay_fan);
420ac171c46SBenjamin Herrenschmidt wf_pid_init(&drive_bay_pid, &drive_bay_prm);
421ac171c46SBenjamin Herrenschmidt drive_bay_tick = 1;
422ac171c46SBenjamin Herrenschmidt }
423ac171c46SBenjamin Herrenschmidt if (--drive_bay_tick > 0)
424ac171c46SBenjamin Herrenschmidt return;
425ac171c46SBenjamin Herrenschmidt drive_bay_tick = drive_bay_pid.param.interval;
426ac171c46SBenjamin Herrenschmidt
427ac171c46SBenjamin Herrenschmidt err = hd_temp->ops->get_value(hd_temp, &temp);
428ac171c46SBenjamin Herrenschmidt if (err) {
429ac171c46SBenjamin Herrenschmidt printk(KERN_WARNING "windfarm: drive bay temp sensor "
430ac171c46SBenjamin Herrenschmidt "error %d\n", err);
431ac171c46SBenjamin Herrenschmidt failure_state |= FAILURE_SENSOR;
432ac171c46SBenjamin Herrenschmidt wf_control_set_max(drive_bay_fan);
433ac171c46SBenjamin Herrenschmidt return;
434ac171c46SBenjamin Herrenschmidt }
435ac171c46SBenjamin Herrenschmidt speed = wf_pid_run(&drive_bay_pid, temp);
436ac171c46SBenjamin Herrenschmidt DBG_LOTS("drive_bay PID temp=%d.%.3d speed=%d\n",
437ac171c46SBenjamin Herrenschmidt FIX32TOPRINT(temp), speed);
438ac171c46SBenjamin Herrenschmidt
439ac171c46SBenjamin Herrenschmidt err = drive_bay_fan->ops->set_value(drive_bay_fan, speed);
440ac171c46SBenjamin Herrenschmidt if (err) {
441ac171c46SBenjamin Herrenschmidt printk(KERN_WARNING "windfarm: drive bay fan error %d\n", err);
442ac171c46SBenjamin Herrenschmidt failure_state |= FAILURE_FAN;
443ac171c46SBenjamin Herrenschmidt }
444ac171c46SBenjamin Herrenschmidt }
445ac171c46SBenjamin Herrenschmidt
446ac171c46SBenjamin Herrenschmidt /* PCI slots area fan */
447ac171c46SBenjamin Herrenschmidt /* This makes the fan speed proportional to the power consumed */
448ac171c46SBenjamin Herrenschmidt static struct wf_pid_param slots_param = {
449ac171c46SBenjamin Herrenschmidt .interval = 1,
450ac171c46SBenjamin Herrenschmidt .history_len = 2,
451ac171c46SBenjamin Herrenschmidt .gd = 0,
452ac171c46SBenjamin Herrenschmidt .gp = 0,
453ac171c46SBenjamin Herrenschmidt .gr = 0x1277952,
454ac171c46SBenjamin Herrenschmidt .itarget = 0,
455ac171c46SBenjamin Herrenschmidt .min = 1560,
456ac171c46SBenjamin Herrenschmidt .max = 3510,
457ac171c46SBenjamin Herrenschmidt };
458ac171c46SBenjamin Herrenschmidt
slots_fan_tick(void)459ac171c46SBenjamin Herrenschmidt static void slots_fan_tick(void)
460ac171c46SBenjamin Herrenschmidt {
461ac171c46SBenjamin Herrenschmidt s32 power;
462ac171c46SBenjamin Herrenschmidt int speed;
463ac171c46SBenjamin Herrenschmidt int err;
464ac171c46SBenjamin Herrenschmidt
465ac171c46SBenjamin Herrenschmidt if (!slots_fan || !slots_power)
466ac171c46SBenjamin Herrenschmidt return;
467ac171c46SBenjamin Herrenschmidt if (!slots_started) {
468ac171c46SBenjamin Herrenschmidt /* first time; initialize things */
469e2a002b9SBenjamin Herrenschmidt printk(KERN_INFO "windfarm: Slots control loop started.\n");
470ac171c46SBenjamin Herrenschmidt wf_pid_init(&slots_pid, &slots_param);
4714f256d56SGustavo A. R. Silva slots_started = true;
472ac171c46SBenjamin Herrenschmidt }
473ac171c46SBenjamin Herrenschmidt
474ac171c46SBenjamin Herrenschmidt err = slots_power->ops->get_value(slots_power, &power);
475ac171c46SBenjamin Herrenschmidt if (err) {
476ac171c46SBenjamin Herrenschmidt printk(KERN_WARNING "windfarm: slots power sensor error %d\n",
477ac171c46SBenjamin Herrenschmidt err);
478ac171c46SBenjamin Herrenschmidt failure_state |= FAILURE_SENSOR;
479ac171c46SBenjamin Herrenschmidt wf_control_set_max(slots_fan);
480ac171c46SBenjamin Herrenschmidt return;
481ac171c46SBenjamin Herrenschmidt }
482ac171c46SBenjamin Herrenschmidt speed = wf_pid_run(&slots_pid, power);
483ac171c46SBenjamin Herrenschmidt DBG_LOTS("slots PID power=%d.%.3d speed=%d\n",
484ac171c46SBenjamin Herrenschmidt FIX32TOPRINT(power), speed);
485ac171c46SBenjamin Herrenschmidt
486ac171c46SBenjamin Herrenschmidt err = slots_fan->ops->set_value(slots_fan, speed);
487ac171c46SBenjamin Herrenschmidt if (err) {
488ac171c46SBenjamin Herrenschmidt printk(KERN_WARNING "windfarm: slots fan error %d\n", err);
489ac171c46SBenjamin Herrenschmidt failure_state |= FAILURE_FAN;
490ac171c46SBenjamin Herrenschmidt }
491ac171c46SBenjamin Herrenschmidt }
492ac171c46SBenjamin Herrenschmidt
set_fail_state(void)493ac171c46SBenjamin Herrenschmidt static void set_fail_state(void)
494ac171c46SBenjamin Herrenschmidt {
495ac171c46SBenjamin Herrenschmidt int i;
496ac171c46SBenjamin Herrenschmidt
497ac171c46SBenjamin Herrenschmidt if (cpufreq_clamp)
498ac171c46SBenjamin Herrenschmidt wf_control_set_max(cpufreq_clamp);
499ac171c46SBenjamin Herrenschmidt for (i = 0; i < NR_CPU_FANS; ++i)
500ac171c46SBenjamin Herrenschmidt if (cpu_fans[i])
501ac171c46SBenjamin Herrenschmidt wf_control_set_max(cpu_fans[i]);
502ac171c46SBenjamin Herrenschmidt if (backside_fan)
503ac171c46SBenjamin Herrenschmidt wf_control_set_max(backside_fan);
504ac171c46SBenjamin Herrenschmidt if (slots_fan)
505ac171c46SBenjamin Herrenschmidt wf_control_set_max(slots_fan);
506ac171c46SBenjamin Herrenschmidt if (drive_bay_fan)
507ac171c46SBenjamin Herrenschmidt wf_control_set_max(drive_bay_fan);
508ac171c46SBenjamin Herrenschmidt }
509ac171c46SBenjamin Herrenschmidt
pm112_tick(void)510ac171c46SBenjamin Herrenschmidt static void pm112_tick(void)
511ac171c46SBenjamin Herrenschmidt {
512ac171c46SBenjamin Herrenschmidt int i, last_failure;
513ac171c46SBenjamin Herrenschmidt
514ac171c46SBenjamin Herrenschmidt if (!started) {
5154f256d56SGustavo A. R. Silva started = true;
516e2a002b9SBenjamin Herrenschmidt printk(KERN_INFO "windfarm: CPUs control loops started.\n");
517ac171c46SBenjamin Herrenschmidt for (i = 0; i < nr_cores; ++i) {
518ac171c46SBenjamin Herrenschmidt if (create_cpu_loop(i) < 0) {
519ac171c46SBenjamin Herrenschmidt failure_state = FAILURE_PERM;
520ac171c46SBenjamin Herrenschmidt set_fail_state();
521ac171c46SBenjamin Herrenschmidt break;
522ac171c46SBenjamin Herrenschmidt }
523ac171c46SBenjamin Herrenschmidt }
524ac171c46SBenjamin Herrenschmidt DBG_LOTS("cpu_all_tmax=%d.%03d\n", FIX32TOPRINT(cpu_all_tmax));
525ac171c46SBenjamin Herrenschmidt
526ac171c46SBenjamin Herrenschmidt #ifdef HACKED_OVERTEMP
527ac171c46SBenjamin Herrenschmidt cpu_all_tmax = 60 << 16;
528ac171c46SBenjamin Herrenschmidt #endif
529ac171c46SBenjamin Herrenschmidt }
530ac171c46SBenjamin Herrenschmidt
531ac171c46SBenjamin Herrenschmidt /* Permanent failure, bail out */
532ac171c46SBenjamin Herrenschmidt if (failure_state & FAILURE_PERM)
533ac171c46SBenjamin Herrenschmidt return;
534ac171c46SBenjamin Herrenschmidt /* Clear all failure bits except low overtemp which will be eventually
535ac171c46SBenjamin Herrenschmidt * cleared by the control loop itself
536ac171c46SBenjamin Herrenschmidt */
537ac171c46SBenjamin Herrenschmidt last_failure = failure_state;
538ac171c46SBenjamin Herrenschmidt failure_state &= FAILURE_LOW_OVERTEMP;
539ac171c46SBenjamin Herrenschmidt cpu_fans_tick();
540ac171c46SBenjamin Herrenschmidt backside_fan_tick();
541ac171c46SBenjamin Herrenschmidt slots_fan_tick();
542ac171c46SBenjamin Herrenschmidt drive_bay_fan_tick();
543ac171c46SBenjamin Herrenschmidt
544ac171c46SBenjamin Herrenschmidt DBG_LOTS("last_failure: 0x%x, failure_state: %x\n",
545ac171c46SBenjamin Herrenschmidt last_failure, failure_state);
546ac171c46SBenjamin Herrenschmidt
547ac171c46SBenjamin Herrenschmidt /* Check for failures. Any failure causes cpufreq clamping */
548ac171c46SBenjamin Herrenschmidt if (failure_state && last_failure == 0 && cpufreq_clamp)
549ac171c46SBenjamin Herrenschmidt wf_control_set_max(cpufreq_clamp);
550ac171c46SBenjamin Herrenschmidt if (failure_state == 0 && last_failure && cpufreq_clamp)
551ac171c46SBenjamin Herrenschmidt wf_control_set_min(cpufreq_clamp);
552ac171c46SBenjamin Herrenschmidt
553ac171c46SBenjamin Herrenschmidt /* That's it for now, we might want to deal with other failures
554ac171c46SBenjamin Herrenschmidt * differently in the future though
555ac171c46SBenjamin Herrenschmidt */
556ac171c46SBenjamin Herrenschmidt }
557ac171c46SBenjamin Herrenschmidt
pm112_new_control(struct wf_control * ct)558ac171c46SBenjamin Herrenschmidt static void pm112_new_control(struct wf_control *ct)
559ac171c46SBenjamin Herrenschmidt {
560ac171c46SBenjamin Herrenschmidt int i, max_exhaust;
561ac171c46SBenjamin Herrenschmidt
562ac171c46SBenjamin Herrenschmidt if (cpufreq_clamp == NULL && !strcmp(ct->name, "cpufreq-clamp")) {
563ac171c46SBenjamin Herrenschmidt if (wf_get_control(ct) == 0)
564ac171c46SBenjamin Herrenschmidt cpufreq_clamp = ct;
565ac171c46SBenjamin Herrenschmidt }
566ac171c46SBenjamin Herrenschmidt
567ac171c46SBenjamin Herrenschmidt for (i = 0; i < NR_CPU_FANS; ++i) {
568ac171c46SBenjamin Herrenschmidt if (!strcmp(ct->name, cpu_fan_names[i])) {
569ac171c46SBenjamin Herrenschmidt if (cpu_fans[i] == NULL && wf_get_control(ct) == 0)
570ac171c46SBenjamin Herrenschmidt cpu_fans[i] = ct;
571ac171c46SBenjamin Herrenschmidt break;
572ac171c46SBenjamin Herrenschmidt }
573ac171c46SBenjamin Herrenschmidt }
574ac171c46SBenjamin Herrenschmidt if (i >= NR_CPU_FANS) {
575ac171c46SBenjamin Herrenschmidt /* not a CPU fan, try the others */
576ac171c46SBenjamin Herrenschmidt if (!strcmp(ct->name, "backside-fan")) {
577ac171c46SBenjamin Herrenschmidt if (backside_fan == NULL && wf_get_control(ct) == 0)
578ac171c46SBenjamin Herrenschmidt backside_fan = ct;
579ac171c46SBenjamin Herrenschmidt } else if (!strcmp(ct->name, "slots-fan")) {
580ac171c46SBenjamin Herrenschmidt if (slots_fan == NULL && wf_get_control(ct) == 0)
581ac171c46SBenjamin Herrenschmidt slots_fan = ct;
582ac171c46SBenjamin Herrenschmidt } else if (!strcmp(ct->name, "drive-bay-fan")) {
583ac171c46SBenjamin Herrenschmidt if (drive_bay_fan == NULL && wf_get_control(ct) == 0)
584ac171c46SBenjamin Herrenschmidt drive_bay_fan = ct;
585ac171c46SBenjamin Herrenschmidt }
586ac171c46SBenjamin Herrenschmidt return;
587ac171c46SBenjamin Herrenschmidt }
588ac171c46SBenjamin Herrenschmidt
589ac171c46SBenjamin Herrenschmidt for (i = 0; i < CPU_FANS_REQD; ++i)
590ac171c46SBenjamin Herrenschmidt if (cpu_fans[i] == NULL)
591ac171c46SBenjamin Herrenschmidt return;
592ac171c46SBenjamin Herrenschmidt
593ac171c46SBenjamin Herrenschmidt /* work out pump scaling factors */
594ac171c46SBenjamin Herrenschmidt max_exhaust = cpu_fans[0]->ops->get_max(cpu_fans[0]);
595ac171c46SBenjamin Herrenschmidt for (i = FIRST_PUMP; i <= LAST_PUMP; ++i)
596ac171c46SBenjamin Herrenschmidt if ((ct = cpu_fans[i]) != NULL)
597ac171c46SBenjamin Herrenschmidt cpu_fan_scale[i] =
598ac171c46SBenjamin Herrenschmidt ct->ops->get_max(ct) * 100 / max_exhaust;
599ac171c46SBenjamin Herrenschmidt
600ac171c46SBenjamin Herrenschmidt have_all_controls = 1;
601ac171c46SBenjamin Herrenschmidt }
602ac171c46SBenjamin Herrenschmidt
pm112_new_sensor(struct wf_sensor * sr)603ac171c46SBenjamin Herrenschmidt static void pm112_new_sensor(struct wf_sensor *sr)
604ac171c46SBenjamin Herrenschmidt {
605ac171c46SBenjamin Herrenschmidt unsigned int i;
606ac171c46SBenjamin Herrenschmidt
607ac171c46SBenjamin Herrenschmidt if (!strncmp(sr->name, "cpu-temp-", 9)) {
608ac171c46SBenjamin Herrenschmidt i = sr->name[9] - '0';
609ac171c46SBenjamin Herrenschmidt if (sr->name[10] == 0 && i < NR_CORES &&
610ac171c46SBenjamin Herrenschmidt sens_cpu_temp[i] == NULL && wf_get_sensor(sr) == 0)
611ac171c46SBenjamin Herrenschmidt sens_cpu_temp[i] = sr;
612ac171c46SBenjamin Herrenschmidt
613ac171c46SBenjamin Herrenschmidt } else if (!strncmp(sr->name, "cpu-power-", 10)) {
614ac171c46SBenjamin Herrenschmidt i = sr->name[10] - '0';
615ac171c46SBenjamin Herrenschmidt if (sr->name[11] == 0 && i < NR_CORES &&
616ac171c46SBenjamin Herrenschmidt sens_cpu_power[i] == NULL && wf_get_sensor(sr) == 0)
617ac171c46SBenjamin Herrenschmidt sens_cpu_power[i] = sr;
618ac171c46SBenjamin Herrenschmidt } else if (!strcmp(sr->name, "hd-temp")) {
619ac171c46SBenjamin Herrenschmidt if (hd_temp == NULL && wf_get_sensor(sr) == 0)
620ac171c46SBenjamin Herrenschmidt hd_temp = sr;
621ac171c46SBenjamin Herrenschmidt } else if (!strcmp(sr->name, "slots-power")) {
622ac171c46SBenjamin Herrenschmidt if (slots_power == NULL && wf_get_sensor(sr) == 0)
623ac171c46SBenjamin Herrenschmidt slots_power = sr;
624b55fafc5SBenjamin Herrenschmidt } else if (!strcmp(sr->name, "backside-temp")) {
625ac171c46SBenjamin Herrenschmidt if (u4_temp == NULL && wf_get_sensor(sr) == 0)
626ac171c46SBenjamin Herrenschmidt u4_temp = sr;
627ac171c46SBenjamin Herrenschmidt } else
628ac171c46SBenjamin Herrenschmidt return;
629ac171c46SBenjamin Herrenschmidt
630ac171c46SBenjamin Herrenschmidt /* check if we have all the sensors we need */
631ac171c46SBenjamin Herrenschmidt for (i = 0; i < nr_cores; ++i)
632ac171c46SBenjamin Herrenschmidt if (sens_cpu_temp[i] == NULL || sens_cpu_power[i] == NULL)
633ac171c46SBenjamin Herrenschmidt return;
634ac171c46SBenjamin Herrenschmidt
635ac171c46SBenjamin Herrenschmidt have_all_sensors = 1;
636ac171c46SBenjamin Herrenschmidt }
637ac171c46SBenjamin Herrenschmidt
pm112_wf_notify(struct notifier_block * self,unsigned long event,void * data)638ac171c46SBenjamin Herrenschmidt static int pm112_wf_notify(struct notifier_block *self,
639ac171c46SBenjamin Herrenschmidt unsigned long event, void *data)
640ac171c46SBenjamin Herrenschmidt {
641ac171c46SBenjamin Herrenschmidt switch (event) {
642ac171c46SBenjamin Herrenschmidt case WF_EVENT_NEW_SENSOR:
643ac171c46SBenjamin Herrenschmidt pm112_new_sensor(data);
644ac171c46SBenjamin Herrenschmidt break;
645ac171c46SBenjamin Herrenschmidt case WF_EVENT_NEW_CONTROL:
646ac171c46SBenjamin Herrenschmidt pm112_new_control(data);
647ac171c46SBenjamin Herrenschmidt break;
648ac171c46SBenjamin Herrenschmidt case WF_EVENT_TICK:
649ac171c46SBenjamin Herrenschmidt if (have_all_controls && have_all_sensors)
650ac171c46SBenjamin Herrenschmidt pm112_tick();
651ac171c46SBenjamin Herrenschmidt }
652ac171c46SBenjamin Herrenschmidt return 0;
653ac171c46SBenjamin Herrenschmidt }
654ac171c46SBenjamin Herrenschmidt
655ac171c46SBenjamin Herrenschmidt static struct notifier_block pm112_events = {
656ac171c46SBenjamin Herrenschmidt .notifier_call = pm112_wf_notify,
657ac171c46SBenjamin Herrenschmidt };
658ac171c46SBenjamin Herrenschmidt
wf_pm112_probe(struct platform_device * dev)65910270613SBenjamin Herrenschmidt static int wf_pm112_probe(struct platform_device *dev)
660ac171c46SBenjamin Herrenschmidt {
661ac171c46SBenjamin Herrenschmidt wf_register_client(&pm112_events);
662ac171c46SBenjamin Herrenschmidt return 0;
663ac171c46SBenjamin Herrenschmidt }
664ac171c46SBenjamin Herrenschmidt
wf_pm112_remove(struct platform_device * dev)6651da42fb6SGreg Kroah-Hartman static int wf_pm112_remove(struct platform_device *dev)
666ac171c46SBenjamin Herrenschmidt {
667ac171c46SBenjamin Herrenschmidt wf_unregister_client(&pm112_events);
668ac171c46SBenjamin Herrenschmidt /* should release all sensors and controls */
669ac171c46SBenjamin Herrenschmidt return 0;
670ac171c46SBenjamin Herrenschmidt }
671ac171c46SBenjamin Herrenschmidt
67210270613SBenjamin Herrenschmidt static struct platform_driver wf_pm112_driver = {
67310270613SBenjamin Herrenschmidt .probe = wf_pm112_probe,
6741da42fb6SGreg Kroah-Hartman .remove = wf_pm112_remove,
67510270613SBenjamin Herrenschmidt .driver = {
676ac171c46SBenjamin Herrenschmidt .name = "windfarm",
67710270613SBenjamin Herrenschmidt },
678ac171c46SBenjamin Herrenschmidt };
679ac171c46SBenjamin Herrenschmidt
wf_pm112_init(void)680ac171c46SBenjamin Herrenschmidt static int __init wf_pm112_init(void)
681ac171c46SBenjamin Herrenschmidt {
682ac171c46SBenjamin Herrenschmidt struct device_node *cpu;
683ac171c46SBenjamin Herrenschmidt
68471a157e8SGrant Likely if (!of_machine_is_compatible("PowerMac11,2"))
685ac171c46SBenjamin Herrenschmidt return -ENODEV;
686ac171c46SBenjamin Herrenschmidt
687ac171c46SBenjamin Herrenschmidt /* Count the number of CPU cores */
688ac171c46SBenjamin Herrenschmidt nr_cores = 0;
689c7c360eeSWei Yongjun for_each_node_by_type(cpu, "cpu")
690ac171c46SBenjamin Herrenschmidt ++nr_cores;
691ac171c46SBenjamin Herrenschmidt
692ac171c46SBenjamin Herrenschmidt printk(KERN_INFO "windfarm: initializing for dual-core desktop G5\n");
693d31e8171SBenjamin Herrenschmidt
694d31e8171SBenjamin Herrenschmidt #ifdef MODULE
695d31e8171SBenjamin Herrenschmidt request_module("windfarm_smu_controls");
696d31e8171SBenjamin Herrenschmidt request_module("windfarm_smu_sensors");
697d31e8171SBenjamin Herrenschmidt request_module("windfarm_smu_sat");
698d31e8171SBenjamin Herrenschmidt request_module("windfarm_lm75_sensor");
699d31e8171SBenjamin Herrenschmidt request_module("windfarm_max6690_sensor");
700d31e8171SBenjamin Herrenschmidt request_module("windfarm_cpufreq_clamp");
701d31e8171SBenjamin Herrenschmidt
702d31e8171SBenjamin Herrenschmidt #endif /* MODULE */
703d31e8171SBenjamin Herrenschmidt
70410270613SBenjamin Herrenschmidt platform_driver_register(&wf_pm112_driver);
705ac171c46SBenjamin Herrenschmidt return 0;
706ac171c46SBenjamin Herrenschmidt }
707ac171c46SBenjamin Herrenschmidt
wf_pm112_exit(void)708ac171c46SBenjamin Herrenschmidt static void __exit wf_pm112_exit(void)
709ac171c46SBenjamin Herrenschmidt {
71010270613SBenjamin Herrenschmidt platform_driver_unregister(&wf_pm112_driver);
711ac171c46SBenjamin Herrenschmidt }
712ac171c46SBenjamin Herrenschmidt
713ac171c46SBenjamin Herrenschmidt module_init(wf_pm112_init);
714ac171c46SBenjamin Herrenschmidt module_exit(wf_pm112_exit);
715ac171c46SBenjamin Herrenschmidt
716ac171c46SBenjamin Herrenschmidt MODULE_AUTHOR("Paul Mackerras <paulus@samba.org>");
717ac171c46SBenjamin Herrenschmidt MODULE_DESCRIPTION("Thermal control for PowerMac11,2");
718ac171c46SBenjamin Herrenschmidt MODULE_LICENSE("GPL");
71923386fe5SKay Sievers MODULE_ALIAS("platform:windfarm");
720