Root/
1 | /* |
2 | * Windfarm PowerMac thermal control. |
3 | * Control loops for PowerMac7,2 and 7,3 |
4 | * |
5 | * Copyright (C) 2012 Benjamin Herrenschmidt, IBM Corp. |
6 | * |
7 | * Use and redistribute under the terms of the GNU GPL v2. |
8 | */ |
9 | #include <linux/types.h> |
10 | #include <linux/errno.h> |
11 | #include <linux/kernel.h> |
12 | #include <linux/device.h> |
13 | #include <linux/platform_device.h> |
14 | #include <linux/reboot.h> |
15 | #include <asm/prom.h> |
16 | #include <asm/smu.h> |
17 | |
18 | #include "windfarm.h" |
19 | #include "windfarm_pid.h" |
20 | #include "windfarm_mpu.h" |
21 | |
22 | #define VERSION "1.0" |
23 | |
24 | #undef DEBUG |
25 | #undef LOTSA_DEBUG |
26 | |
27 | #ifdef DEBUG |
28 | #define DBG(args...) printk(args) |
29 | #else |
30 | #define DBG(args...) do { } while(0) |
31 | #endif |
32 | |
33 | #ifdef LOTSA_DEBUG |
34 | #define DBG_LOTS(args...) printk(args) |
35 | #else |
36 | #define DBG_LOTS(args...) do { } while(0) |
37 | #endif |
38 | |
39 | /* define this to force CPU overtemp to 60 degree, useful for testing |
40 | * the overtemp code |
41 | */ |
42 | #undef HACKED_OVERTEMP |
43 | |
44 | /* We currently only handle 2 chips */ |
45 | #define NR_CHIPS 2 |
46 | #define NR_CPU_FANS 3 * NR_CHIPS |
47 | |
48 | /* Controls and sensors */ |
49 | static struct wf_sensor *sens_cpu_temp[NR_CHIPS]; |
50 | static struct wf_sensor *sens_cpu_volts[NR_CHIPS]; |
51 | static struct wf_sensor *sens_cpu_amps[NR_CHIPS]; |
52 | static struct wf_sensor *backside_temp; |
53 | static struct wf_sensor *drives_temp; |
54 | |
55 | static struct wf_control *cpu_front_fans[NR_CHIPS]; |
56 | static struct wf_control *cpu_rear_fans[NR_CHIPS]; |
57 | static struct wf_control *cpu_pumps[NR_CHIPS]; |
58 | static struct wf_control *backside_fan; |
59 | static struct wf_control *drives_fan; |
60 | static struct wf_control *slots_fan; |
61 | static struct wf_control *cpufreq_clamp; |
62 | |
63 | /* We keep a temperature history for average calculation of 180s */ |
64 | #define CPU_TEMP_HIST_SIZE 180 |
65 | |
66 | /* Fixed speed for slot fan */ |
67 | #define SLOTS_FAN_DEFAULT_PWM 40 |
68 | |
69 | /* Scale value for CPU intake fans */ |
70 | #define CPU_INTAKE_SCALE 0x0000f852 |
71 | |
72 | /* PID loop state */ |
73 | static const struct mpu_data *cpu_mpu_data[NR_CHIPS]; |
74 | static struct wf_cpu_pid_state cpu_pid[NR_CHIPS]; |
75 | static bool cpu_pid_combined; |
76 | static u32 cpu_thist[CPU_TEMP_HIST_SIZE]; |
77 | static int cpu_thist_pt; |
78 | static s64 cpu_thist_total; |
79 | static s32 cpu_all_tmax = 100 << 16; |
80 | static struct wf_pid_state backside_pid; |
81 | static int backside_tick; |
82 | static struct wf_pid_state drives_pid; |
83 | static int drives_tick; |
84 | |
85 | static int nr_chips; |
86 | static bool have_all_controls; |
87 | static bool have_all_sensors; |
88 | static bool started; |
89 | |
90 | static int failure_state; |
91 | #define FAILURE_SENSOR 1 |
92 | #define FAILURE_FAN 2 |
93 | #define FAILURE_PERM 4 |
94 | #define FAILURE_LOW_OVERTEMP 8 |
95 | #define FAILURE_HIGH_OVERTEMP 16 |
96 | |
97 | /* Overtemp values */ |
98 | #define LOW_OVER_AVERAGE 0 |
99 | #define LOW_OVER_IMMEDIATE (10 << 16) |
100 | #define LOW_OVER_CLEAR ((-10) << 16) |
101 | #define HIGH_OVER_IMMEDIATE (14 << 16) |
102 | #define HIGH_OVER_AVERAGE (10 << 16) |
103 | #define HIGH_OVER_IMMEDIATE (14 << 16) |
104 | |
105 | |
106 | static void cpu_max_all_fans(void) |
107 | { |
108 | int i; |
109 | |
110 | /* We max all CPU fans in case of a sensor error. We also do the |
111 | * cpufreq clamping now, even if it's supposedly done later by the |
112 | * generic code anyway, we do it earlier here to react faster |
113 | */ |
114 | if (cpufreq_clamp) |
115 | wf_control_set_max(cpufreq_clamp); |
116 | for (i = 0; i < nr_chips; i++) { |
117 | if (cpu_front_fans[i]) |
118 | wf_control_set_max(cpu_front_fans[i]); |
119 | if (cpu_rear_fans[i]) |
120 | wf_control_set_max(cpu_rear_fans[i]); |
121 | if (cpu_pumps[i]) |
122 | wf_control_set_max(cpu_pumps[i]); |
123 | } |
124 | } |
125 | |
126 | static int cpu_check_overtemp(s32 temp) |
127 | { |
128 | int new_state = 0; |
129 | s32 t_avg, t_old; |
130 | static bool first = true; |
131 | |
132 | /* First check for immediate overtemps */ |
133 | if (temp >= (cpu_all_tmax + LOW_OVER_IMMEDIATE)) { |
134 | new_state |= FAILURE_LOW_OVERTEMP; |
135 | if ((failure_state & FAILURE_LOW_OVERTEMP) == 0) |
136 | printk(KERN_ERR "windfarm: Overtemp due to immediate CPU" |
137 | " temperature !\n"); |
138 | } |
139 | if (temp >= (cpu_all_tmax + HIGH_OVER_IMMEDIATE)) { |
140 | new_state |= FAILURE_HIGH_OVERTEMP; |
141 | if ((failure_state & FAILURE_HIGH_OVERTEMP) == 0) |
142 | printk(KERN_ERR "windfarm: Critical overtemp due to" |
143 | " immediate CPU temperature !\n"); |
144 | } |
145 | |
146 | /* |
147 | * The first time around, initialize the array with the first |
148 | * temperature reading |
149 | */ |
150 | if (first) { |
151 | int i; |
152 | |
153 | cpu_thist_total = 0; |
154 | for (i = 0; i < CPU_TEMP_HIST_SIZE; i++) { |
155 | cpu_thist[i] = temp; |
156 | cpu_thist_total += temp; |
157 | } |
158 | first = false; |
159 | } |
160 | |
161 | /* |
162 | * We calculate a history of max temperatures and use that for the |
163 | * overtemp management |
164 | */ |
165 | t_old = cpu_thist[cpu_thist_pt]; |
166 | cpu_thist[cpu_thist_pt] = temp; |
167 | cpu_thist_pt = (cpu_thist_pt + 1) % CPU_TEMP_HIST_SIZE; |
168 | cpu_thist_total -= t_old; |
169 | cpu_thist_total += temp; |
170 | t_avg = cpu_thist_total / CPU_TEMP_HIST_SIZE; |
171 | |
172 | DBG_LOTS(" t_avg = %d.%03d (out: %d.%03d, in: %d.%03d)\n", |
173 | FIX32TOPRINT(t_avg), FIX32TOPRINT(t_old), FIX32TOPRINT(temp)); |
174 | |
175 | /* Now check for average overtemps */ |
176 | if (t_avg >= (cpu_all_tmax + LOW_OVER_AVERAGE)) { |
177 | new_state |= FAILURE_LOW_OVERTEMP; |
178 | if ((failure_state & FAILURE_LOW_OVERTEMP) == 0) |
179 | printk(KERN_ERR "windfarm: Overtemp due to average CPU" |
180 | " temperature !\n"); |
181 | } |
182 | if (t_avg >= (cpu_all_tmax + HIGH_OVER_AVERAGE)) { |
183 | new_state |= FAILURE_HIGH_OVERTEMP; |
184 | if ((failure_state & FAILURE_HIGH_OVERTEMP) == 0) |
185 | printk(KERN_ERR "windfarm: Critical overtemp due to" |
186 | " average CPU temperature !\n"); |
187 | } |
188 | |
189 | /* Now handle overtemp conditions. We don't currently use the windfarm |
190 | * overtemp handling core as it's not fully suited to the needs of those |
191 | * new machine. This will be fixed later. |
192 | */ |
193 | if (new_state) { |
194 | /* High overtemp -> immediate shutdown */ |
195 | if (new_state & FAILURE_HIGH_OVERTEMP) |
196 | machine_power_off(); |
197 | if ((failure_state & new_state) != new_state) |
198 | cpu_max_all_fans(); |
199 | failure_state |= new_state; |
200 | } else if ((failure_state & FAILURE_LOW_OVERTEMP) && |
201 | (temp < (cpu_all_tmax + LOW_OVER_CLEAR))) { |
202 | printk(KERN_ERR "windfarm: Overtemp condition cleared !\n"); |
203 | failure_state &= ~FAILURE_LOW_OVERTEMP; |
204 | } |
205 | |
206 | return failure_state & (FAILURE_LOW_OVERTEMP | FAILURE_HIGH_OVERTEMP); |
207 | } |
208 | |
209 | static int read_one_cpu_vals(int cpu, s32 *temp, s32 *power) |
210 | { |
211 | s32 dtemp, volts, amps; |
212 | int rc; |
213 | |
214 | /* Get diode temperature */ |
215 | rc = wf_sensor_get(sens_cpu_temp[cpu], &dtemp); |
216 | if (rc) { |
217 | DBG(" CPU%d: temp reading error !\n", cpu); |
218 | return -EIO; |
219 | } |
220 | DBG_LOTS(" CPU%d: temp = %d.%03d\n", cpu, FIX32TOPRINT((dtemp))); |
221 | *temp = dtemp; |
222 | |
223 | /* Get voltage */ |
224 | rc = wf_sensor_get(sens_cpu_volts[cpu], &volts); |
225 | if (rc) { |
226 | DBG(" CPU%d, volts reading error !\n", cpu); |
227 | return -EIO; |
228 | } |
229 | DBG_LOTS(" CPU%d: volts = %d.%03d\n", cpu, FIX32TOPRINT((volts))); |
230 | |
231 | /* Get current */ |
232 | rc = wf_sensor_get(sens_cpu_amps[cpu], &s); |
233 | if (rc) { |
234 | DBG(" CPU%d, current reading error !\n", cpu); |
235 | return -EIO; |
236 | } |
237 | DBG_LOTS(" CPU%d: amps = %d.%03d\n", cpu, FIX32TOPRINT((amps))); |
238 | |
239 | /* Calculate power */ |
240 | |
241 | /* Scale voltage and current raw sensor values according to fixed scales |
242 | * obtained in Darwin and calculate power from I and V |
243 | */ |
244 | *power = (((u64)volts) * ((u64)amps)) >> 16; |
245 | |
246 | DBG_LOTS(" CPU%d: power = %d.%03d\n", cpu, FIX32TOPRINT((*power))); |
247 | |
248 | return 0; |
249 | |
250 | } |
251 | |
252 | static void cpu_fans_tick_split(void) |
253 | { |
254 | int err, cpu; |
255 | s32 intake, temp, power, t_max = 0; |
256 | |
257 | DBG_LOTS("* cpu fans_tick_split()\n"); |
258 | |
259 | for (cpu = 0; cpu < nr_chips; ++cpu) { |
260 | struct wf_cpu_pid_state *sp = &cpu_pid[cpu]; |
261 | |
262 | /* Read current speed */ |
263 | wf_control_get(cpu_rear_fans[cpu], &sp->target); |
264 | |
265 | DBG_LOTS(" CPU%d: cur_target = %d RPM\n", cpu, sp->target); |
266 | |
267 | err = read_one_cpu_vals(cpu, &temp, &power); |
268 | if (err) { |
269 | failure_state |= FAILURE_SENSOR; |
270 | cpu_max_all_fans(); |
271 | return; |
272 | } |
273 | |
274 | /* Keep track of highest temp */ |
275 | t_max = max(t_max, temp); |
276 | |
277 | /* Handle possible overtemps */ |
278 | if (cpu_check_overtemp(t_max)) |
279 | return; |
280 | |
281 | /* Run PID */ |
282 | wf_cpu_pid_run(sp, power, temp); |
283 | |
284 | DBG_LOTS(" CPU%d: target = %d RPM\n", cpu, sp->target); |
285 | |
286 | /* Apply result directly to exhaust fan */ |
287 | err = wf_control_set(cpu_rear_fans[cpu], sp->target); |
288 | if (err) { |
289 | pr_warning("wf_pm72: Fan %s reports error %d\n", |
290 | cpu_rear_fans[cpu]->name, err); |
291 | failure_state |= FAILURE_FAN; |
292 | break; |
293 | } |
294 | |
295 | /* Scale result for intake fan */ |
296 | intake = (sp->target * CPU_INTAKE_SCALE) >> 16; |
297 | DBG_LOTS(" CPU%d: intake = %d RPM\n", cpu, intake); |
298 | err = wf_control_set(cpu_front_fans[cpu], intake); |
299 | if (err) { |
300 | pr_warning("wf_pm72: Fan %s reports error %d\n", |
301 | cpu_front_fans[cpu]->name, err); |
302 | failure_state |= FAILURE_FAN; |
303 | break; |
304 | } |
305 | } |
306 | } |
307 | |
308 | static void cpu_fans_tick_combined(void) |
309 | { |
310 | s32 temp0, power0, temp1, power1, t_max = 0; |
311 | s32 temp, power, intake, pump; |
312 | struct wf_control *pump0, *pump1; |
313 | struct wf_cpu_pid_state *sp = &cpu_pid[0]; |
314 | int err, cpu; |
315 | |
316 | DBG_LOTS("* cpu fans_tick_combined()\n"); |
317 | |
318 | /* Read current speed from cpu 0 */ |
319 | wf_control_get(cpu_rear_fans[0], &sp->target); |
320 | |
321 | DBG_LOTS(" CPUs: cur_target = %d RPM\n", sp->target); |
322 | |
323 | /* Read values for both CPUs */ |
324 | err = read_one_cpu_vals(0, &temp0, &power0); |
325 | if (err) { |
326 | failure_state |= FAILURE_SENSOR; |
327 | cpu_max_all_fans(); |
328 | return; |
329 | } |
330 | err = read_one_cpu_vals(1, &temp1, &power1); |
331 | if (err) { |
332 | failure_state |= FAILURE_SENSOR; |
333 | cpu_max_all_fans(); |
334 | return; |
335 | } |
336 | |
337 | /* Keep track of highest temp */ |
338 | t_max = max(t_max, max(temp0, temp1)); |
339 | |
340 | /* Handle possible overtemps */ |
341 | if (cpu_check_overtemp(t_max)) |
342 | return; |
343 | |
344 | /* Use the max temp & power of both */ |
345 | temp = max(temp0, temp1); |
346 | power = max(power0, power1); |
347 | |
348 | /* Run PID */ |
349 | wf_cpu_pid_run(sp, power, temp); |
350 | |
351 | /* Scale result for intake fan */ |
352 | intake = (sp->target * CPU_INTAKE_SCALE) >> 16; |
353 | |
354 | /* Same deal with pump speed */ |
355 | pump0 = cpu_pumps[0]; |
356 | pump1 = cpu_pumps[1]; |
357 | if (!pump0) { |
358 | pump0 = pump1; |
359 | pump1 = NULL; |
360 | } |
361 | pump = (sp->target * wf_control_get_max(pump0)) / |
362 | cpu_mpu_data[0]->rmaxn_exhaust_fan; |
363 | |
364 | DBG_LOTS(" CPUs: target = %d RPM\n", sp->target); |
365 | DBG_LOTS(" CPUs: intake = %d RPM\n", intake); |
366 | DBG_LOTS(" CPUs: pump = %d RPM\n", pump); |
367 | |
368 | for (cpu = 0; cpu < nr_chips; cpu++) { |
369 | err = wf_control_set(cpu_rear_fans[cpu], sp->target); |
370 | if (err) { |
371 | pr_warning("wf_pm72: Fan %s reports error %d\n", |
372 | cpu_rear_fans[cpu]->name, err); |
373 | failure_state |= FAILURE_FAN; |
374 | } |
375 | err = wf_control_set(cpu_front_fans[cpu], intake); |
376 | if (err) { |
377 | pr_warning("wf_pm72: Fan %s reports error %d\n", |
378 | cpu_front_fans[cpu]->name, err); |
379 | failure_state |= FAILURE_FAN; |
380 | } |
381 | err = 0; |
382 | if (cpu_pumps[cpu]) |
383 | err = wf_control_set(cpu_pumps[cpu], pump); |
384 | if (err) { |
385 | pr_warning("wf_pm72: Pump %s reports error %d\n", |
386 | cpu_pumps[cpu]->name, err); |
387 | failure_state |= FAILURE_FAN; |
388 | } |
389 | } |
390 | } |
391 | |
392 | /* Implementation... */ |
393 | static int cpu_setup_pid(int cpu) |
394 | { |
395 | struct wf_cpu_pid_param pid; |
396 | const struct mpu_data *mpu = cpu_mpu_data[cpu]; |
397 | s32 tmax, ttarget, ptarget; |
398 | int fmin, fmax, hsize; |
399 | |
400 | /* Get PID params from the appropriate MPU EEPROM */ |
401 | tmax = mpu->tmax << 16; |
402 | ttarget = mpu->ttarget << 16; |
403 | ptarget = ((s32)(mpu->pmaxh - mpu->padjmax)) << 16; |
404 | |
405 | DBG("wf_72: CPU%d ttarget = %d.%03d, tmax = %d.%03d\n", |
406 | cpu, FIX32TOPRINT(ttarget), FIX32TOPRINT(tmax)); |
407 | |
408 | /* We keep a global tmax for overtemp calculations */ |
409 | if (tmax < cpu_all_tmax) |
410 | cpu_all_tmax = tmax; |
411 | |
412 | /* Set PID min/max by using the rear fan min/max */ |
413 | fmin = wf_control_get_min(cpu_rear_fans[cpu]); |
414 | fmax = wf_control_get_max(cpu_rear_fans[cpu]); |
415 | DBG("wf_72: CPU%d max RPM range = [%d..%d]\n", cpu, fmin, fmax); |
416 | |
417 | /* History size */ |
418 | hsize = min_t(int, mpu->tguardband, WF_PID_MAX_HISTORY); |
419 | DBG("wf_72: CPU%d history size = %d\n", cpu, hsize); |
420 | |
421 | /* Initialize PID loop */ |
422 | pid.interval = 1; /* seconds */ |
423 | pid.history_len = hsize; |
424 | pid.gd = mpu->pid_gd; |
425 | pid.gp = mpu->pid_gp; |
426 | pid.gr = mpu->pid_gr; |
427 | pid.tmax = tmax; |
428 | pid.ttarget = ttarget; |
429 | pid.pmaxadj = ptarget; |
430 | pid.min = fmin; |
431 | pid.max = fmax; |
432 | |
433 | wf_cpu_pid_init(&cpu_pid[cpu], &pid); |
434 | cpu_pid[cpu].target = 1000; |
435 | |
436 | return 0; |
437 | } |
438 | |
439 | /* Backside/U3 fan */ |
440 | static struct wf_pid_param backside_u3_param = { |
441 | .interval = 5, |
442 | .history_len = 2, |
443 | .gd = 40 << 20, |
444 | .gp = 5 << 20, |
445 | .gr = 0, |
446 | .itarget = 65 << 16, |
447 | .additive = 1, |
448 | .min = 20, |
449 | .max = 100, |
450 | }; |
451 | |
452 | static struct wf_pid_param backside_u3h_param = { |
453 | .interval = 5, |
454 | .history_len = 2, |
455 | .gd = 20 << 20, |
456 | .gp = 5 << 20, |
457 | .gr = 0, |
458 | .itarget = 75 << 16, |
459 | .additive = 1, |
460 | .min = 20, |
461 | .max = 100, |
462 | }; |
463 | |
464 | static void backside_fan_tick(void) |
465 | { |
466 | s32 temp; |
467 | int speed; |
468 | int err; |
469 | |
470 | if (!backside_fan || !backside_temp || !backside_tick) |
471 | return; |
472 | if (--backside_tick > 0) |
473 | return; |
474 | backside_tick = backside_pid.param.interval; |
475 | |
476 | DBG_LOTS("* backside fans tick\n"); |
477 | |
478 | /* Update fan speed from actual fans */ |
479 | err = wf_control_get(backside_fan, &speed); |
480 | if (!err) |
481 | backside_pid.target = speed; |
482 | |
483 | err = wf_sensor_get(backside_temp, &temp); |
484 | if (err) { |
485 | printk(KERN_WARNING "windfarm: U4 temp sensor error %d\n", |
486 | err); |
487 | failure_state |= FAILURE_SENSOR; |
488 | wf_control_set_max(backside_fan); |
489 | return; |
490 | } |
491 | speed = wf_pid_run(&backside_pid, temp); |
492 | |
493 | DBG_LOTS("backside PID temp=%d.%.3d speed=%d\n", |
494 | FIX32TOPRINT(temp), speed); |
495 | |
496 | err = wf_control_set(backside_fan, speed); |
497 | if (err) { |
498 | printk(KERN_WARNING "windfarm: backside fan error %d\n", err); |
499 | failure_state |= FAILURE_FAN; |
500 | } |
501 | } |
502 | |
503 | static void backside_setup_pid(void) |
504 | { |
505 | /* first time initialize things */ |
506 | s32 fmin = wf_control_get_min(backside_fan); |
507 | s32 fmax = wf_control_get_max(backside_fan); |
508 | struct wf_pid_param param; |
509 | struct device_node *u3; |
510 | int u3h = 1; /* conservative by default */ |
511 | |
512 | u3 = of_find_node_by_path("/u3@0,f8000000"); |
513 | if (u3 != NULL) { |
514 | const u32 *vers = of_get_property(u3, "device-rev", NULL); |
515 | if (vers) |
516 | if (((*vers) & 0x3f) < 0x34) |
517 | u3h = 0; |
518 | of_node_put(u3); |
519 | } |
520 | |
521 | param = u3h ? backside_u3h_param : backside_u3_param; |
522 | |
523 | param.min = max(param.min, fmin); |
524 | param.max = min(param.max, fmax); |
525 | wf_pid_init(&backside_pid, ¶m); |
526 | backside_tick = 1; |
527 | |
528 | pr_info("wf_pm72: Backside control loop started.\n"); |
529 | } |
530 | |
531 | /* Drive bay fan */ |
532 | static const struct wf_pid_param drives_param = { |
533 | .interval = 5, |
534 | .history_len = 2, |
535 | .gd = 30 << 20, |
536 | .gp = 5 << 20, |
537 | .gr = 0, |
538 | .itarget = 40 << 16, |
539 | .additive = 1, |
540 | .min = 300, |
541 | .max = 4000, |
542 | }; |
543 | |
544 | static void drives_fan_tick(void) |
545 | { |
546 | s32 temp; |
547 | int speed; |
548 | int err; |
549 | |
550 | if (!drives_fan || !drives_temp || !drives_tick) |
551 | return; |
552 | if (--drives_tick > 0) |
553 | return; |
554 | drives_tick = drives_pid.param.interval; |
555 | |
556 | DBG_LOTS("* drives fans tick\n"); |
557 | |
558 | /* Update fan speed from actual fans */ |
559 | err = wf_control_get(drives_fan, &speed); |
560 | if (!err) |
561 | drives_pid.target = speed; |
562 | |
563 | err = wf_sensor_get(drives_temp, &temp); |
564 | if (err) { |
565 | pr_warning("wf_pm72: drive bay temp sensor error %d\n", err); |
566 | failure_state |= FAILURE_SENSOR; |
567 | wf_control_set_max(drives_fan); |
568 | return; |
569 | } |
570 | speed = wf_pid_run(&drives_pid, temp); |
571 | |
572 | DBG_LOTS("drives PID temp=%d.%.3d speed=%d\n", |
573 | FIX32TOPRINT(temp), speed); |
574 | |
575 | err = wf_control_set(drives_fan, speed); |
576 | if (err) { |
577 | printk(KERN_WARNING "windfarm: drive bay fan error %d\n", err); |
578 | failure_state |= FAILURE_FAN; |
579 | } |
580 | } |
581 | |
582 | static void drives_setup_pid(void) |
583 | { |
584 | /* first time initialize things */ |
585 | s32 fmin = wf_control_get_min(drives_fan); |
586 | s32 fmax = wf_control_get_max(drives_fan); |
587 | struct wf_pid_param param = drives_param; |
588 | |
589 | param.min = max(param.min, fmin); |
590 | param.max = min(param.max, fmax); |
591 | wf_pid_init(&drives_pid, ¶m); |
592 | drives_tick = 1; |
593 | |
594 | pr_info("wf_pm72: Drive bay control loop started.\n"); |
595 | } |
596 | |
597 | static void set_fail_state(void) |
598 | { |
599 | cpu_max_all_fans(); |
600 | |
601 | if (backside_fan) |
602 | wf_control_set_max(backside_fan); |
603 | if (slots_fan) |
604 | wf_control_set_max(slots_fan); |
605 | if (drives_fan) |
606 | wf_control_set_max(drives_fan); |
607 | } |
608 | |
609 | static void pm72_tick(void) |
610 | { |
611 | int i, last_failure; |
612 | |
613 | if (!started) { |
614 | started = 1; |
615 | printk(KERN_INFO "windfarm: CPUs control loops started.\n"); |
616 | for (i = 0; i < nr_chips; ++i) { |
617 | if (cpu_setup_pid(i) < 0) { |
618 | failure_state = FAILURE_PERM; |
619 | set_fail_state(); |
620 | break; |
621 | } |
622 | } |
623 | DBG_LOTS("cpu_all_tmax=%d.%03d\n", FIX32TOPRINT(cpu_all_tmax)); |
624 | |
625 | backside_setup_pid(); |
626 | drives_setup_pid(); |
627 | |
628 | /* |
629 | * We don't have the right stuff to drive the PCI fan |
630 | * so we fix it to a default value |
631 | */ |
632 | wf_control_set(slots_fan, SLOTS_FAN_DEFAULT_PWM); |
633 | |
634 | #ifdef HACKED_OVERTEMP |
635 | cpu_all_tmax = 60 << 16; |
636 | #endif |
637 | } |
638 | |
639 | /* Permanent failure, bail out */ |
640 | if (failure_state & FAILURE_PERM) |
641 | return; |
642 | |
643 | /* |
644 | * Clear all failure bits except low overtemp which will be eventually |
645 | * cleared by the control loop itself |
646 | */ |
647 | last_failure = failure_state; |
648 | failure_state &= FAILURE_LOW_OVERTEMP; |
649 | if (cpu_pid_combined) |
650 | cpu_fans_tick_combined(); |
651 | else |
652 | cpu_fans_tick_split(); |
653 | backside_fan_tick(); |
654 | drives_fan_tick(); |
655 | |
656 | DBG_LOTS(" last_failure: 0x%x, failure_state: %x\n", |
657 | last_failure, failure_state); |
658 | |
659 | /* Check for failures. Any failure causes cpufreq clamping */ |
660 | if (failure_state && last_failure == 0 && cpufreq_clamp) |
661 | wf_control_set_max(cpufreq_clamp); |
662 | if (failure_state == 0 && last_failure && cpufreq_clamp) |
663 | wf_control_set_min(cpufreq_clamp); |
664 | |
665 | /* That's it for now, we might want to deal with other failures |
666 | * differently in the future though |
667 | */ |
668 | } |
669 | |
670 | static void pm72_new_control(struct wf_control *ct) |
671 | { |
672 | bool all_controls; |
673 | bool had_pump = cpu_pumps[0] || cpu_pumps[1]; |
674 | |
675 | if (!strcmp(ct->name, "cpu-front-fan-0")) |
676 | cpu_front_fans[0] = ct; |
677 | else if (!strcmp(ct->name, "cpu-front-fan-1")) |
678 | cpu_front_fans[1] = ct; |
679 | else if (!strcmp(ct->name, "cpu-rear-fan-0")) |
680 | cpu_rear_fans[0] = ct; |
681 | else if (!strcmp(ct->name, "cpu-rear-fan-1")) |
682 | cpu_rear_fans[1] = ct; |
683 | else if (!strcmp(ct->name, "cpu-pump-0")) |
684 | cpu_pumps[0] = ct; |
685 | else if (!strcmp(ct->name, "cpu-pump-1")) |
686 | cpu_pumps[1] = ct; |
687 | else if (!strcmp(ct->name, "backside-fan")) |
688 | backside_fan = ct; |
689 | else if (!strcmp(ct->name, "slots-fan")) |
690 | slots_fan = ct; |
691 | else if (!strcmp(ct->name, "drive-bay-fan")) |
692 | drives_fan = ct; |
693 | else if (!strcmp(ct->name, "cpufreq-clamp")) |
694 | cpufreq_clamp = ct; |
695 | |
696 | all_controls = |
697 | cpu_front_fans[0] && |
698 | cpu_rear_fans[0] && |
699 | backside_fan && |
700 | slots_fan && |
701 | drives_fan; |
702 | if (nr_chips > 1) |
703 | all_controls &= |
704 | cpu_front_fans[1] && |
705 | cpu_rear_fans[1]; |
706 | have_all_controls = all_controls; |
707 | |
708 | if ((cpu_pumps[0] || cpu_pumps[1]) && !had_pump) { |
709 | pr_info("wf_pm72: Liquid cooling pump(s) detected," |
710 | " using new algorithm !\n"); |
711 | cpu_pid_combined = true; |
712 | } |
713 | } |
714 | |
715 | |
716 | static void pm72_new_sensor(struct wf_sensor *sr) |
717 | { |
718 | bool all_sensors; |
719 | |
720 | if (!strcmp(sr->name, "cpu-diode-temp-0")) |
721 | sens_cpu_temp[0] = sr; |
722 | else if (!strcmp(sr->name, "cpu-diode-temp-1")) |
723 | sens_cpu_temp[1] = sr; |
724 | else if (!strcmp(sr->name, "cpu-voltage-0")) |
725 | sens_cpu_volts[0] = sr; |
726 | else if (!strcmp(sr->name, "cpu-voltage-1")) |
727 | sens_cpu_volts[1] = sr; |
728 | else if (!strcmp(sr->name, "cpu-current-0")) |
729 | sens_cpu_amps[0] = sr; |
730 | else if (!strcmp(sr->name, "cpu-current-1")) |
731 | sens_cpu_amps[1] = sr; |
732 | else if (!strcmp(sr->name, "backside-temp")) |
733 | backside_temp = sr; |
734 | else if (!strcmp(sr->name, "hd-temp")) |
735 | drives_temp = sr; |
736 | |
737 | all_sensors = |
738 | sens_cpu_temp[0] && |
739 | sens_cpu_volts[0] && |
740 | sens_cpu_amps[0] && |
741 | backside_temp && |
742 | drives_temp; |
743 | if (nr_chips > 1) |
744 | all_sensors &= |
745 | sens_cpu_temp[1] && |
746 | sens_cpu_volts[1] && |
747 | sens_cpu_amps[1]; |
748 | |
749 | have_all_sensors = all_sensors; |
750 | } |
751 | |
752 | static int pm72_wf_notify(struct notifier_block *self, |
753 | unsigned long event, void *data) |
754 | { |
755 | switch (event) { |
756 | case WF_EVENT_NEW_SENSOR: |
757 | pm72_new_sensor(data); |
758 | break; |
759 | case WF_EVENT_NEW_CONTROL: |
760 | pm72_new_control(data); |
761 | break; |
762 | case WF_EVENT_TICK: |
763 | if (have_all_controls && have_all_sensors) |
764 | pm72_tick(); |
765 | } |
766 | return 0; |
767 | } |
768 | |
769 | static struct notifier_block pm72_events = { |
770 | .notifier_call = pm72_wf_notify, |
771 | }; |
772 | |
773 | static int wf_pm72_probe(struct platform_device *dev) |
774 | { |
775 | wf_register_client(&pm72_events); |
776 | return 0; |
777 | } |
778 | |
779 | static int __devexit wf_pm72_remove(struct platform_device *dev) |
780 | { |
781 | wf_unregister_client(&pm72_events); |
782 | |
783 | /* should release all sensors and controls */ |
784 | return 0; |
785 | } |
786 | |
787 | static struct platform_driver wf_pm72_driver = { |
788 | .probe = wf_pm72_probe, |
789 | .remove = wf_pm72_remove, |
790 | .driver = { |
791 | .name = "windfarm", |
792 | .owner = THIS_MODULE, |
793 | }, |
794 | }; |
795 | |
796 | static int __init wf_pm72_init(void) |
797 | { |
798 | struct device_node *cpu; |
799 | int i; |
800 | |
801 | if (!of_machine_is_compatible("PowerMac7,2") && |
802 | !of_machine_is_compatible("PowerMac7,3")) |
803 | return -ENODEV; |
804 | |
805 | /* Count the number of CPU cores */ |
806 | nr_chips = 0; |
807 | for (cpu = NULL; (cpu = of_find_node_by_type(cpu, "cpu")) != NULL; ) |
808 | ++nr_chips; |
809 | if (nr_chips > NR_CHIPS) |
810 | nr_chips = NR_CHIPS; |
811 | |
812 | pr_info("windfarm: Initializing for desktop G5 with %d chips\n", |
813 | nr_chips); |
814 | |
815 | /* Get MPU data for each CPU */ |
816 | for (i = 0; i < nr_chips; i++) { |
817 | cpu_mpu_data[i] = wf_get_mpu(i); |
818 | if (!cpu_mpu_data[i]) { |
819 | pr_err("wf_pm72: Failed to find MPU data for CPU %d\n", i); |
820 | return -ENXIO; |
821 | } |
822 | } |
823 | |
824 | #ifdef MODULE |
825 | request_module("windfarm_fcu_controls"); |
826 | request_module("windfarm_lm75_sensor"); |
827 | request_module("windfarm_ad7417_sensor"); |
828 | request_module("windfarm_max6690_sensor"); |
829 | request_module("windfarm_cpufreq_clamp"); |
830 | #endif /* MODULE */ |
831 | |
832 | platform_driver_register(&wf_pm72_driver); |
833 | return 0; |
834 | } |
835 | |
836 | static void __exit wf_pm72_exit(void) |
837 | { |
838 | platform_driver_unregister(&wf_pm72_driver); |
839 | } |
840 | |
841 | module_init(wf_pm72_init); |
842 | module_exit(wf_pm72_exit); |
843 | |
844 | MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>"); |
845 | MODULE_DESCRIPTION("Thermal control for AGP PowerMac G5s"); |
846 | MODULE_LICENSE("GPL"); |
847 | MODULE_ALIAS("platform:windfarm"); |
848 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9