linux/drivers/macintosh/windfarm_pm72.c
<<
>>
Prefs
   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 */
  49static struct wf_sensor *sens_cpu_temp[NR_CHIPS];
  50static struct wf_sensor *sens_cpu_volts[NR_CHIPS];
  51static struct wf_sensor *sens_cpu_amps[NR_CHIPS];
  52static struct wf_sensor *backside_temp;
  53static struct wf_sensor *drives_temp;
  54
  55static struct wf_control *cpu_front_fans[NR_CHIPS];
  56static struct wf_control *cpu_rear_fans[NR_CHIPS];
  57static struct wf_control *cpu_pumps[NR_CHIPS];
  58static struct wf_control *backside_fan;
  59static struct wf_control *drives_fan;
  60static struct wf_control *slots_fan;
  61static 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 */
  73static const struct mpu_data *cpu_mpu_data[NR_CHIPS];
  74static struct wf_cpu_pid_state cpu_pid[NR_CHIPS];
  75static bool cpu_pid_combined;
  76static u32 cpu_thist[CPU_TEMP_HIST_SIZE];
  77static int cpu_thist_pt;
  78static s64 cpu_thist_total;
  79static s32 cpu_all_tmax = 100 << 16;
  80static struct wf_pid_state backside_pid;
  81static int backside_tick;
  82static struct wf_pid_state drives_pid;
  83static int drives_tick;
  84
  85static int nr_chips;
  86static bool have_all_controls;
  87static bool have_all_sensors;
  88static bool started;
  89
  90static 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
 106static 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
 126static 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
 209static 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], &amps);
 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
 252static 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
 308static 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... */
 393static 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 */
 440static 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
 452static 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
 464static 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
 503static 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, &param);
 526        backside_tick = 1;
 527
 528        pr_info("wf_pm72: Backside control loop started.\n");
 529}
 530
 531/* Drive bay fan */
 532static 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
 544static 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
 582static 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, &param);
 592        drives_tick = 1;
 593
 594        pr_info("wf_pm72: Drive bay control loop started.\n");
 595}
 596
 597static 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
 609static 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
 670static 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
 716static 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
 752static 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
 769static struct notifier_block pm72_events = {
 770        .notifier_call = pm72_wf_notify,
 771};
 772
 773static int wf_pm72_probe(struct platform_device *dev)
 774{
 775        wf_register_client(&pm72_events);
 776        return 0;
 777}
 778
 779static 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
 787static 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
 796static 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
 836static void __exit wf_pm72_exit(void)
 837{
 838        platform_driver_unregister(&wf_pm72_driver);
 839}
 840
 841module_init(wf_pm72_init);
 842module_exit(wf_pm72_exit);
 843
 844MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
 845MODULE_DESCRIPTION("Thermal control for AGP PowerMac G5s");
 846MODULE_LICENSE("GPL");
 847MODULE_ALIAS("platform:windfarm");
 848
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.