0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029 #include <linux/types.h>
0030 #include <linux/errno.h>
0031 #include <linux/kernel.h>
0032 #include <linux/delay.h>
0033 #include <linux/slab.h>
0034 #include <linux/init.h>
0035 #include <linux/spinlock.h>
0036 #include <linux/wait.h>
0037 #include <linux/kmod.h>
0038 #include <linux/device.h>
0039 #include <linux/platform_device.h>
0040 #include <linux/of.h>
0041
0042 #include <asm/machdep.h>
0043 #include <asm/io.h>
0044 #include <asm/sections.h>
0045 #include <asm/smu.h>
0046
0047 #include "windfarm.h"
0048 #include "windfarm_pid.h"
0049
0050 #define VERSION "0.4"
0051
0052 #undef DEBUG
0053
0054 #ifdef DEBUG
0055 #define DBG(args...) printk(args)
0056 #else
0057 #define DBG(args...) do { } while(0)
0058 #endif
0059
0060
0061
0062
0063 #undef HACKED_OVERTEMP
0064
0065
0066 static struct wf_sensor *sensor_cpu_power;
0067 static struct wf_sensor *sensor_cpu_temp;
0068 static struct wf_sensor *sensor_hd_temp;
0069 static struct wf_sensor *sensor_slots_power;
0070 static struct wf_control *fan_cpu_main;
0071 static struct wf_control *fan_cpu_second;
0072 static struct wf_control *fan_cpu_third;
0073 static struct wf_control *fan_hd;
0074 static struct wf_control *fan_slots;
0075 static struct wf_control *cpufreq_clamp;
0076
0077
0078 static int wf_smu_all_controls_ok, wf_smu_all_sensors_ok;
0079 static bool wf_smu_started;
0080 static bool wf_smu_overtemp;
0081
0082
0083 #define FAILURE_FAN 0x01
0084 #define FAILURE_SENSOR 0x02
0085 #define FAILURE_OVERTEMP 0x04
0086
0087 static unsigned int wf_smu_failure_state;
0088 static int wf_smu_readjust, wf_smu_skipping;
0089
0090
0091
0092
0093
0094
0095
0096 #define WF_SMU_CPU_FANS_INTERVAL 1
0097 #define WF_SMU_CPU_FANS_MAX_HISTORY 16
0098
0099
0100
0101 struct wf_smu_cpu_fans_state {
0102 int ticks;
0103 s32 cpu_setpoint;
0104 struct wf_cpu_pid_state pid;
0105 };
0106
0107 static struct wf_smu_cpu_fans_state *wf_smu_cpu_fans;
0108
0109
0110
0111
0112
0113
0114
0115
0116 struct wf_smu_drive_fans_state {
0117 int ticks;
0118 s32 setpoint;
0119 struct wf_pid_state pid;
0120 };
0121
0122 static struct wf_smu_drive_fans_state *wf_smu_drive_fans;
0123
0124
0125
0126
0127
0128
0129 struct wf_smu_slots_fans_state {
0130 int ticks;
0131 s32 setpoint;
0132 struct wf_pid_state pid;
0133 };
0134
0135 static struct wf_smu_slots_fans_state *wf_smu_slots_fans;
0136
0137
0138
0139
0140
0141
0142
0143 static void wf_smu_create_cpu_fans(void)
0144 {
0145 struct wf_cpu_pid_param pid_param;
0146 const struct smu_sdbp_header *hdr;
0147 struct smu_sdbp_cpupiddata *piddata;
0148 struct smu_sdbp_fvt *fvt;
0149 s32 tmax, tdelta, maxpow, powadj;
0150
0151
0152 hdr = smu_get_sdb_partition(SMU_SDB_CPUPIDDATA_ID, NULL);
0153 if (hdr == 0) {
0154 printk(KERN_WARNING "windfarm: CPU PID fan config not found "
0155 "max fan speed\n");
0156 goto fail;
0157 }
0158 piddata = (struct smu_sdbp_cpupiddata *)&hdr[1];
0159
0160
0161
0162
0163 hdr = smu_get_sdb_partition(SMU_SDB_FVT_ID, NULL);
0164 if (hdr) {
0165 fvt = (struct smu_sdbp_fvt *)&hdr[1];
0166 tmax = ((s32)fvt->maxtemp) << 16;
0167 } else
0168 tmax = 0x5e0000;
0169
0170
0171 wf_smu_cpu_fans = kmalloc(sizeof(struct wf_smu_cpu_fans_state),
0172 GFP_KERNEL);
0173 if (wf_smu_cpu_fans == NULL)
0174 goto fail;
0175 wf_smu_cpu_fans->ticks = 1;
0176
0177
0178 pid_param.interval = WF_SMU_CPU_FANS_INTERVAL;
0179 pid_param.history_len = piddata->history_len;
0180 if (pid_param.history_len > WF_CPU_PID_MAX_HISTORY) {
0181 printk(KERN_WARNING "windfarm: History size overflow on "
0182 "CPU control loop (%d)\n", piddata->history_len);
0183 pid_param.history_len = WF_CPU_PID_MAX_HISTORY;
0184 }
0185 pid_param.gd = piddata->gd;
0186 pid_param.gp = piddata->gp;
0187 pid_param.gr = piddata->gr / pid_param.history_len;
0188
0189 tdelta = ((s32)piddata->target_temp_delta) << 16;
0190 maxpow = ((s32)piddata->max_power) << 16;
0191 powadj = ((s32)piddata->power_adj) << 16;
0192
0193 pid_param.tmax = tmax;
0194 pid_param.ttarget = tmax - tdelta;
0195 pid_param.pmaxadj = maxpow - powadj;
0196
0197 pid_param.min = wf_control_get_min(fan_cpu_main);
0198 pid_param.max = wf_control_get_max(fan_cpu_main);
0199
0200 wf_cpu_pid_init(&wf_smu_cpu_fans->pid, &pid_param);
0201
0202 DBG("wf: CPU Fan control initialized.\n");
0203 DBG(" ttarget=%d.%03d, tmax=%d.%03d, min=%d RPM, max=%d RPM\n",
0204 FIX32TOPRINT(pid_param.ttarget), FIX32TOPRINT(pid_param.tmax),
0205 pid_param.min, pid_param.max);
0206
0207 return;
0208
0209 fail:
0210 printk(KERN_WARNING "windfarm: CPU fan config not found\n"
0211 "for this machine model, max fan speed\n");
0212
0213 if (cpufreq_clamp)
0214 wf_control_set_max(cpufreq_clamp);
0215 if (fan_cpu_main)
0216 wf_control_set_max(fan_cpu_main);
0217 }
0218
0219 static void wf_smu_cpu_fans_tick(struct wf_smu_cpu_fans_state *st)
0220 {
0221 s32 new_setpoint, temp, power;
0222 int rc;
0223
0224 if (--st->ticks != 0) {
0225 if (wf_smu_readjust)
0226 goto readjust;
0227 return;
0228 }
0229 st->ticks = WF_SMU_CPU_FANS_INTERVAL;
0230
0231 rc = wf_sensor_get(sensor_cpu_temp, &temp);
0232 if (rc) {
0233 printk(KERN_WARNING "windfarm: CPU temp sensor error %d\n",
0234 rc);
0235 wf_smu_failure_state |= FAILURE_SENSOR;
0236 return;
0237 }
0238
0239 rc = wf_sensor_get(sensor_cpu_power, &power);
0240 if (rc) {
0241 printk(KERN_WARNING "windfarm: CPU power sensor error %d\n",
0242 rc);
0243 wf_smu_failure_state |= FAILURE_SENSOR;
0244 return;
0245 }
0246
0247 DBG("wf_smu: CPU Fans tick ! CPU temp: %d.%03d, power: %d.%03d\n",
0248 FIX32TOPRINT(temp), FIX32TOPRINT(power));
0249
0250 #ifdef HACKED_OVERTEMP
0251 if (temp > 0x4a0000)
0252 wf_smu_failure_state |= FAILURE_OVERTEMP;
0253 #else
0254 if (temp > st->pid.param.tmax)
0255 wf_smu_failure_state |= FAILURE_OVERTEMP;
0256 #endif
0257 new_setpoint = wf_cpu_pid_run(&st->pid, power, temp);
0258
0259 DBG("wf_smu: new_setpoint: %d RPM\n", (int)new_setpoint);
0260
0261 if (st->cpu_setpoint == new_setpoint)
0262 return;
0263 st->cpu_setpoint = new_setpoint;
0264 readjust:
0265 if (fan_cpu_main && wf_smu_failure_state == 0) {
0266 rc = wf_control_set(fan_cpu_main, st->cpu_setpoint);
0267 if (rc) {
0268 printk(KERN_WARNING "windfarm: CPU main fan"
0269 " error %d\n", rc);
0270 wf_smu_failure_state |= FAILURE_FAN;
0271 }
0272 }
0273 if (fan_cpu_second && wf_smu_failure_state == 0) {
0274 rc = wf_control_set(fan_cpu_second, st->cpu_setpoint);
0275 if (rc) {
0276 printk(KERN_WARNING "windfarm: CPU second fan"
0277 " error %d\n", rc);
0278 wf_smu_failure_state |= FAILURE_FAN;
0279 }
0280 }
0281 if (fan_cpu_third && wf_smu_failure_state == 0) {
0282 rc = wf_control_set(fan_cpu_third, st->cpu_setpoint);
0283 if (rc) {
0284 printk(KERN_WARNING "windfarm: CPU third fan"
0285 " error %d\n", rc);
0286 wf_smu_failure_state |= FAILURE_FAN;
0287 }
0288 }
0289 }
0290
0291 static void wf_smu_create_drive_fans(void)
0292 {
0293 struct wf_pid_param param = {
0294 .interval = 5,
0295 .history_len = 2,
0296 .gd = 0x01e00000,
0297 .gp = 0x00500000,
0298 .gr = 0x00000000,
0299 .itarget = 0x00200000,
0300 };
0301
0302
0303 wf_smu_drive_fans = kmalloc(sizeof(struct wf_smu_drive_fans_state),
0304 GFP_KERNEL);
0305 if (wf_smu_drive_fans == NULL) {
0306 printk(KERN_WARNING "windfarm: Memory allocation error"
0307 " max fan speed\n");
0308 goto fail;
0309 }
0310 wf_smu_drive_fans->ticks = 1;
0311
0312
0313 param.additive = (fan_hd->type == WF_CONTROL_RPM_FAN);
0314 param.min = wf_control_get_min(fan_hd);
0315 param.max = wf_control_get_max(fan_hd);
0316 wf_pid_init(&wf_smu_drive_fans->pid, ¶m);
0317
0318 DBG("wf: Drive Fan control initialized.\n");
0319 DBG(" itarged=%d.%03d, min=%d RPM, max=%d RPM\n",
0320 FIX32TOPRINT(param.itarget), param.min, param.max);
0321 return;
0322
0323 fail:
0324 if (fan_hd)
0325 wf_control_set_max(fan_hd);
0326 }
0327
0328 static void wf_smu_drive_fans_tick(struct wf_smu_drive_fans_state *st)
0329 {
0330 s32 new_setpoint, temp;
0331 int rc;
0332
0333 if (--st->ticks != 0) {
0334 if (wf_smu_readjust)
0335 goto readjust;
0336 return;
0337 }
0338 st->ticks = st->pid.param.interval;
0339
0340 rc = wf_sensor_get(sensor_hd_temp, &temp);
0341 if (rc) {
0342 printk(KERN_WARNING "windfarm: HD temp sensor error %d\n",
0343 rc);
0344 wf_smu_failure_state |= FAILURE_SENSOR;
0345 return;
0346 }
0347
0348 DBG("wf_smu: Drive Fans tick ! HD temp: %d.%03d\n",
0349 FIX32TOPRINT(temp));
0350
0351 if (temp > (st->pid.param.itarget + 0x50000))
0352 wf_smu_failure_state |= FAILURE_OVERTEMP;
0353
0354 new_setpoint = wf_pid_run(&st->pid, temp);
0355
0356 DBG("wf_smu: new_setpoint: %d\n", (int)new_setpoint);
0357
0358 if (st->setpoint == new_setpoint)
0359 return;
0360 st->setpoint = new_setpoint;
0361 readjust:
0362 if (fan_hd && wf_smu_failure_state == 0) {
0363 rc = wf_control_set(fan_hd, st->setpoint);
0364 if (rc) {
0365 printk(KERN_WARNING "windfarm: HD fan error %d\n",
0366 rc);
0367 wf_smu_failure_state |= FAILURE_FAN;
0368 }
0369 }
0370 }
0371
0372 static void wf_smu_create_slots_fans(void)
0373 {
0374 struct wf_pid_param param = {
0375 .interval = 1,
0376 .history_len = 8,
0377 .gd = 0x00000000,
0378 .gp = 0x00000000,
0379 .gr = 0x00020000,
0380 .itarget = 0x00000000
0381 };
0382
0383
0384 wf_smu_slots_fans = kmalloc(sizeof(struct wf_smu_slots_fans_state),
0385 GFP_KERNEL);
0386 if (wf_smu_slots_fans == NULL) {
0387 printk(KERN_WARNING "windfarm: Memory allocation error"
0388 " max fan speed\n");
0389 goto fail;
0390 }
0391 wf_smu_slots_fans->ticks = 1;
0392
0393
0394 param.additive = (fan_slots->type == WF_CONTROL_RPM_FAN);
0395 param.min = wf_control_get_min(fan_slots);
0396 param.max = wf_control_get_max(fan_slots);
0397 wf_pid_init(&wf_smu_slots_fans->pid, ¶m);
0398
0399 DBG("wf: Slots Fan control initialized.\n");
0400 DBG(" itarged=%d.%03d, min=%d RPM, max=%d RPM\n",
0401 FIX32TOPRINT(param.itarget), param.min, param.max);
0402 return;
0403
0404 fail:
0405 if (fan_slots)
0406 wf_control_set_max(fan_slots);
0407 }
0408
0409 static void wf_smu_slots_fans_tick(struct wf_smu_slots_fans_state *st)
0410 {
0411 s32 new_setpoint, power;
0412 int rc;
0413
0414 if (--st->ticks != 0) {
0415 if (wf_smu_readjust)
0416 goto readjust;
0417 return;
0418 }
0419 st->ticks = st->pid.param.interval;
0420
0421 rc = wf_sensor_get(sensor_slots_power, &power);
0422 if (rc) {
0423 printk(KERN_WARNING "windfarm: Slots power sensor error %d\n",
0424 rc);
0425 wf_smu_failure_state |= FAILURE_SENSOR;
0426 return;
0427 }
0428
0429 DBG("wf_smu: Slots Fans tick ! Slots power: %d.%03d\n",
0430 FIX32TOPRINT(power));
0431
0432 #if 0
0433 if (power > (st->pid.param.itarget + 0x50000))
0434 wf_smu_failure_state |= FAILURE_OVERTEMP;
0435 #endif
0436
0437 new_setpoint = wf_pid_run(&st->pid, power);
0438
0439 DBG("wf_smu: new_setpoint: %d\n", (int)new_setpoint);
0440
0441 if (st->setpoint == new_setpoint)
0442 return;
0443 st->setpoint = new_setpoint;
0444 readjust:
0445 if (fan_slots && wf_smu_failure_state == 0) {
0446 rc = wf_control_set(fan_slots, st->setpoint);
0447 if (rc) {
0448 printk(KERN_WARNING "windfarm: Slots fan error %d\n",
0449 rc);
0450 wf_smu_failure_state |= FAILURE_FAN;
0451 }
0452 }
0453 }
0454
0455
0456
0457
0458
0459
0460
0461 static void wf_smu_tick(void)
0462 {
0463 unsigned int last_failure = wf_smu_failure_state;
0464 unsigned int new_failure;
0465
0466 if (!wf_smu_started) {
0467 DBG("wf: creating control loops !\n");
0468 wf_smu_create_drive_fans();
0469 wf_smu_create_slots_fans();
0470 wf_smu_create_cpu_fans();
0471 wf_smu_started = true;
0472 }
0473
0474
0475 if (wf_smu_skipping && --wf_smu_skipping)
0476 return;
0477
0478 wf_smu_failure_state = 0;
0479 if (wf_smu_drive_fans)
0480 wf_smu_drive_fans_tick(wf_smu_drive_fans);
0481 if (wf_smu_slots_fans)
0482 wf_smu_slots_fans_tick(wf_smu_slots_fans);
0483 if (wf_smu_cpu_fans)
0484 wf_smu_cpu_fans_tick(wf_smu_cpu_fans);
0485
0486 wf_smu_readjust = 0;
0487 new_failure = wf_smu_failure_state & ~last_failure;
0488
0489
0490
0491
0492 if (wf_smu_failure_state && !last_failure) {
0493 if (cpufreq_clamp)
0494 wf_control_set_max(cpufreq_clamp);
0495 if (fan_cpu_main)
0496 wf_control_set_max(fan_cpu_main);
0497 if (fan_cpu_second)
0498 wf_control_set_max(fan_cpu_second);
0499 if (fan_cpu_third)
0500 wf_control_set_max(fan_cpu_third);
0501 if (fan_hd)
0502 wf_control_set_max(fan_hd);
0503 if (fan_slots)
0504 wf_control_set_max(fan_slots);
0505 }
0506
0507
0508
0509
0510 if (!wf_smu_failure_state && last_failure) {
0511 if (cpufreq_clamp)
0512 wf_control_set_min(cpufreq_clamp);
0513 wf_smu_readjust = 1;
0514 }
0515
0516
0517
0518
0519 if (new_failure & FAILURE_OVERTEMP) {
0520 wf_set_overtemp();
0521 wf_smu_skipping = 2;
0522 wf_smu_overtemp = true;
0523 }
0524
0525
0526
0527
0528
0529
0530
0531 if (!wf_smu_failure_state && wf_smu_overtemp) {
0532 wf_clear_overtemp();
0533 wf_smu_overtemp = false;
0534 }
0535 }
0536
0537
0538 static void wf_smu_new_control(struct wf_control *ct)
0539 {
0540 if (wf_smu_all_controls_ok)
0541 return;
0542
0543 if (fan_cpu_main == NULL && !strcmp(ct->name, "cpu-rear-fan-0")) {
0544 if (wf_get_control(ct) == 0)
0545 fan_cpu_main = ct;
0546 }
0547
0548 if (fan_cpu_second == NULL && !strcmp(ct->name, "cpu-rear-fan-1")) {
0549 if (wf_get_control(ct) == 0)
0550 fan_cpu_second = ct;
0551 }
0552
0553 if (fan_cpu_third == NULL && !strcmp(ct->name, "cpu-front-fan-0")) {
0554 if (wf_get_control(ct) == 0)
0555 fan_cpu_third = ct;
0556 }
0557
0558 if (cpufreq_clamp == NULL && !strcmp(ct->name, "cpufreq-clamp")) {
0559 if (wf_get_control(ct) == 0)
0560 cpufreq_clamp = ct;
0561 }
0562
0563 if (fan_hd == NULL && !strcmp(ct->name, "drive-bay-fan")) {
0564 if (wf_get_control(ct) == 0)
0565 fan_hd = ct;
0566 }
0567
0568 if (fan_slots == NULL && !strcmp(ct->name, "slots-fan")) {
0569 if (wf_get_control(ct) == 0)
0570 fan_slots = ct;
0571 }
0572
0573 if (fan_cpu_main && (fan_cpu_second || fan_cpu_third) && fan_hd &&
0574 fan_slots && cpufreq_clamp)
0575 wf_smu_all_controls_ok = 1;
0576 }
0577
0578 static void wf_smu_new_sensor(struct wf_sensor *sr)
0579 {
0580 if (wf_smu_all_sensors_ok)
0581 return;
0582
0583 if (sensor_cpu_power == NULL && !strcmp(sr->name, "cpu-power")) {
0584 if (wf_get_sensor(sr) == 0)
0585 sensor_cpu_power = sr;
0586 }
0587
0588 if (sensor_cpu_temp == NULL && !strcmp(sr->name, "cpu-temp")) {
0589 if (wf_get_sensor(sr) == 0)
0590 sensor_cpu_temp = sr;
0591 }
0592
0593 if (sensor_hd_temp == NULL && !strcmp(sr->name, "hd-temp")) {
0594 if (wf_get_sensor(sr) == 0)
0595 sensor_hd_temp = sr;
0596 }
0597
0598 if (sensor_slots_power == NULL && !strcmp(sr->name, "slots-power")) {
0599 if (wf_get_sensor(sr) == 0)
0600 sensor_slots_power = sr;
0601 }
0602
0603 if (sensor_cpu_power && sensor_cpu_temp &&
0604 sensor_hd_temp && sensor_slots_power)
0605 wf_smu_all_sensors_ok = 1;
0606 }
0607
0608
0609 static int wf_smu_notify(struct notifier_block *self,
0610 unsigned long event, void *data)
0611 {
0612 switch(event) {
0613 case WF_EVENT_NEW_CONTROL:
0614 DBG("wf: new control %s detected\n",
0615 ((struct wf_control *)data)->name);
0616 wf_smu_new_control(data);
0617 wf_smu_readjust = 1;
0618 break;
0619 case WF_EVENT_NEW_SENSOR:
0620 DBG("wf: new sensor %s detected\n",
0621 ((struct wf_sensor *)data)->name);
0622 wf_smu_new_sensor(data);
0623 break;
0624 case WF_EVENT_TICK:
0625 if (wf_smu_all_controls_ok && wf_smu_all_sensors_ok)
0626 wf_smu_tick();
0627 }
0628
0629 return 0;
0630 }
0631
0632 static struct notifier_block wf_smu_events = {
0633 .notifier_call = wf_smu_notify,
0634 };
0635
0636 static int wf_init_pm(void)
0637 {
0638 printk(KERN_INFO "windfarm: Initializing for Desktop G5 model\n");
0639
0640 return 0;
0641 }
0642
0643 static int wf_smu_probe(struct platform_device *ddev)
0644 {
0645 wf_register_client(&wf_smu_events);
0646
0647 return 0;
0648 }
0649
0650 static int wf_smu_remove(struct platform_device *ddev)
0651 {
0652 wf_unregister_client(&wf_smu_events);
0653
0654
0655
0656
0657
0658 msleep(1000);
0659
0660
0661
0662
0663
0664
0665
0666
0667 if (sensor_cpu_power)
0668 wf_put_sensor(sensor_cpu_power);
0669 if (sensor_cpu_temp)
0670 wf_put_sensor(sensor_cpu_temp);
0671 if (sensor_hd_temp)
0672 wf_put_sensor(sensor_hd_temp);
0673 if (sensor_slots_power)
0674 wf_put_sensor(sensor_slots_power);
0675
0676
0677 if (fan_cpu_main)
0678 wf_put_control(fan_cpu_main);
0679 if (fan_cpu_second)
0680 wf_put_control(fan_cpu_second);
0681 if (fan_cpu_third)
0682 wf_put_control(fan_cpu_third);
0683 if (fan_hd)
0684 wf_put_control(fan_hd);
0685 if (fan_slots)
0686 wf_put_control(fan_slots);
0687 if (cpufreq_clamp)
0688 wf_put_control(cpufreq_clamp);
0689
0690
0691 kfree(wf_smu_slots_fans);
0692 kfree(wf_smu_drive_fans);
0693 kfree(wf_smu_cpu_fans);
0694
0695 return 0;
0696 }
0697
0698 static struct platform_driver wf_smu_driver = {
0699 .probe = wf_smu_probe,
0700 .remove = wf_smu_remove,
0701 .driver = {
0702 .name = "windfarm",
0703 },
0704 };
0705
0706
0707 static int __init wf_smu_init(void)
0708 {
0709 int rc = -ENODEV;
0710
0711 if (of_machine_is_compatible("PowerMac9,1"))
0712 rc = wf_init_pm();
0713
0714 if (rc == 0) {
0715 #ifdef MODULE
0716 request_module("windfarm_smu_controls");
0717 request_module("windfarm_smu_sensors");
0718 request_module("windfarm_lm75_sensor");
0719 request_module("windfarm_cpufreq_clamp");
0720
0721 #endif
0722 platform_driver_register(&wf_smu_driver);
0723 }
0724
0725 return rc;
0726 }
0727
0728 static void __exit wf_smu_exit(void)
0729 {
0730
0731 platform_driver_unregister(&wf_smu_driver);
0732 }
0733
0734
0735 module_init(wf_smu_init);
0736 module_exit(wf_smu_exit);
0737
0738 MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
0739 MODULE_DESCRIPTION("Thermal control logic for PowerMac9,1");
0740 MODULE_LICENSE("GPL");
0741
0742 MODULE_ALIAS("platform:windfarm");