brintos

brintos / linux-shallow public Read only

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