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