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