cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

windfarm_pm121.c (25615B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Windfarm PowerMac thermal control. iMac G5 iSight
      4 *
      5 * (c) Copyright 2007 Étienne Bersac <bersace@gmail.com>
      6 *
      7 * Bits & pieces from windfarm_pm81.c by (c) Copyright 2005 Benjamin
      8 * Herrenschmidt, IBM Corp. <benh@kernel.crashing.org>
      9 *
     10 * PowerMac12,1
     11 * ============
     12 *
     13 * The algorithm used is the PID control algorithm, used the same way
     14 * the published Darwin code does, using the same values that are
     15 * present in the Darwin 8.10 snapshot property lists (note however
     16 * that none of the code has been re-used, it's a complete
     17 * re-implementation
     18 *
     19 * There is two models using PowerMac12,1. Model 2 is iMac G5 iSight
     20 * 17" while Model 3 is iMac G5 20". They do have both the same
     21 * controls with a tiny difference. The control-ids of hard-drive-fan
     22 * and cpu-fan is swapped.
     23 *
     24 * Target Correction :
     25 *
     26 * controls have a target correction calculated as :
     27 *
     28 * new_min = ((((average_power * slope) >> 16) + offset) >> 16) + min_value
     29 * new_value = max(new_value, max(new_min, 0))
     30 *
     31 * OD Fan control correction.
     32 *
     33 * # model_id: 2
     34 *   offset		: -19563152
     35 *   slope		:  1956315
     36 *
     37 * # model_id: 3
     38 *   offset		: -15650652
     39 *   slope		:  1565065
     40 *
     41 * HD Fan control correction.
     42 *
     43 * # model_id: 2
     44 *   offset		: -15650652
     45 *   slope		:  1565065
     46 *
     47 * # model_id: 3
     48 *   offset		: -19563152
     49 *   slope		:  1956315
     50 *
     51 * CPU Fan control correction.
     52 *
     53 * # model_id: 2
     54 *   offset		: -25431900
     55 *   slope		:  2543190
     56 *
     57 * # model_id: 3
     58 *   offset		: -15650652
     59 *   slope		:  1565065
     60 *
     61 * Target rubber-banding :
     62 *
     63 * Some controls have a target correction which depends on another
     64 * control value. The correction is computed in the following way :
     65 *
     66 * new_min = ref_value * slope + offset
     67 *
     68 * ref_value is the value of the reference control. If new_min is
     69 * greater than 0, then we correct the target value using :
     70 *
     71 * new_target = max (new_target, new_min >> 16)
     72 *
     73 * # model_id : 2
     74 *   control	: cpu-fan
     75 *   ref	: optical-drive-fan
     76 *   offset	: -15650652
     77 *   slope	: 1565065
     78 *
     79 * # model_id : 3
     80 *   control	: optical-drive-fan
     81 *   ref	: hard-drive-fan
     82 *   offset	: -32768000
     83 *   slope	: 65536
     84 *
     85 * In order to have the moste efficient correction with those
     86 * dependencies, we must trigger HD loop before OD loop before CPU
     87 * loop.
     88 *
     89 * The various control loops found in Darwin config file are:
     90 *
     91 * HD Fan control loop.
     92 *
     93 * # model_id: 2
     94 *   control        : hard-drive-fan
     95 *   sensor         : hard-drive-temp
     96 *   PID params     : G_d = 0x00000000
     97 *                    G_p = 0x002D70A3
     98 *                    G_r = 0x00019999
     99 *                    History = 2 entries
    100 *                    Input target = 0x370000
    101 *                    Interval = 5s
    102 *
    103 * # model_id: 3
    104 *   control        : hard-drive-fan
    105 *   sensor         : hard-drive-temp
    106 *   PID params     : G_d = 0x00000000
    107 *                    G_p = 0x002170A3
    108 *                    G_r = 0x00019999
    109 *                    History = 2 entries
    110 *                    Input target = 0x370000
    111 *                    Interval = 5s
    112 *
    113 * OD Fan control loop.
    114 *
    115 * # model_id: 2
    116 *   control        : optical-drive-fan
    117 *   sensor         : optical-drive-temp
    118 *   PID params     : G_d = 0x00000000
    119 *                    G_p = 0x001FAE14
    120 *                    G_r = 0x00019999
    121 *                    History = 2 entries
    122 *                    Input target = 0x320000
    123 *                    Interval = 5s
    124 *
    125 * # model_id: 3
    126 *   control        : optical-drive-fan
    127 *   sensor         : optical-drive-temp
    128 *   PID params     : G_d = 0x00000000
    129 *                    G_p = 0x001FAE14
    130 *                    G_r = 0x00019999
    131 *                    History = 2 entries
    132 *                    Input target = 0x320000
    133 *                    Interval = 5s
    134 *
    135 * GPU Fan control loop.
    136 *
    137 * # model_id: 2
    138 *   control        : hard-drive-fan
    139 *   sensor         : gpu-temp
    140 *   PID params     : G_d = 0x00000000
    141 *                    G_p = 0x002A6666
    142 *                    G_r = 0x00019999
    143 *                    History = 2 entries
    144 *                    Input target = 0x5A0000
    145 *                    Interval = 5s
    146 *
    147 * # model_id: 3
    148 *   control        : cpu-fan
    149 *   sensor         : gpu-temp
    150 *   PID params     : G_d = 0x00000000
    151 *                    G_p = 0x0010CCCC
    152 *                    G_r = 0x00019999
    153 *                    History = 2 entries
    154 *                    Input target = 0x500000
    155 *                    Interval = 5s
    156 *
    157 * KODIAK (aka northbridge) Fan control loop.
    158 *
    159 * # model_id: 2
    160 *   control        : optical-drive-fan
    161 *   sensor         : north-bridge-temp
    162 *   PID params     : G_d = 0x00000000
    163 *                    G_p = 0x003BD70A
    164 *                    G_r = 0x00019999
    165 *                    History = 2 entries
    166 *                    Input target = 0x550000
    167 *                    Interval = 5s
    168 *
    169 * # model_id: 3
    170 *   control        : hard-drive-fan
    171 *   sensor         : north-bridge-temp
    172 *   PID params     : G_d = 0x00000000
    173 *                    G_p = 0x0030F5C2
    174 *                    G_r = 0x00019999
    175 *                    History = 2 entries
    176 *                    Input target = 0x550000
    177 *                    Interval = 5s
    178 *
    179 * CPU Fan control loop.
    180 *
    181 *   control        : cpu-fan
    182 *   sensors        : cpu-temp, cpu-power
    183 *   PID params     : from SDB partition
    184 *
    185 * CPU Slew control loop.
    186 *
    187 *   control        : cpufreq-clamp
    188 *   sensor         : cpu-temp
    189 */
    190
    191#undef	DEBUG
    192
    193#include <linux/types.h>
    194#include <linux/errno.h>
    195#include <linux/kernel.h>
    196#include <linux/delay.h>
    197#include <linux/slab.h>
    198#include <linux/init.h>
    199#include <linux/spinlock.h>
    200#include <linux/wait.h>
    201#include <linux/kmod.h>
    202#include <linux/device.h>
    203#include <linux/platform_device.h>
    204#include <linux/of.h>
    205
    206#include <asm/machdep.h>
    207#include <asm/io.h>
    208#include <asm/sections.h>
    209#include <asm/smu.h>
    210
    211#include "windfarm.h"
    212#include "windfarm_pid.h"
    213
    214#define VERSION "0.3"
    215
    216static int pm121_mach_model;	/* machine model id */
    217
    218/* Controls & sensors */
    219static struct wf_sensor	*sensor_cpu_power;
    220static struct wf_sensor	*sensor_cpu_temp;
    221static struct wf_sensor	*sensor_cpu_voltage;
    222static struct wf_sensor	*sensor_cpu_current;
    223static struct wf_sensor	*sensor_gpu_temp;
    224static struct wf_sensor	*sensor_north_bridge_temp;
    225static struct wf_sensor	*sensor_hard_drive_temp;
    226static struct wf_sensor	*sensor_optical_drive_temp;
    227static struct wf_sensor	*sensor_incoming_air_temp; /* unused ! */
    228
    229enum {
    230	FAN_CPU,
    231	FAN_HD,
    232	FAN_OD,
    233	CPUFREQ,
    234	N_CONTROLS
    235};
    236static struct wf_control *controls[N_CONTROLS] = {};
    237
    238/* Set to kick the control loop into life */
    239static int pm121_all_controls_ok, pm121_all_sensors_ok;
    240static bool pm121_started;
    241
    242enum {
    243	FAILURE_FAN		= 1 << 0,
    244	FAILURE_SENSOR		= 1 << 1,
    245	FAILURE_OVERTEMP	= 1 << 2
    246};
    247
    248/* All sys loops. Note the HD before the OD loop in order to have it
    249   run before. */
    250enum {
    251	LOOP_GPU,		/* control = hd or cpu, but luckily,
    252				   it doesn't matter */
    253	LOOP_HD,		/* control = hd */
    254	LOOP_KODIAK,		/* control = hd or od */
    255	LOOP_OD,		/* control = od */
    256	N_LOOPS
    257};
    258
    259static const char *loop_names[N_LOOPS] = {
    260	"GPU",
    261	"HD",
    262	"KODIAK",
    263	"OD",
    264};
    265
    266#define	PM121_NUM_CONFIGS	2
    267
    268static unsigned int pm121_failure_state;
    269static int pm121_readjust, pm121_skipping;
    270static bool pm121_overtemp;
    271static s32 average_power;
    272
    273struct pm121_correction {
    274	int	offset;
    275	int	slope;
    276};
    277
    278static struct pm121_correction corrections[N_CONTROLS][PM121_NUM_CONFIGS] = {
    279	/* FAN_OD */
    280	{
    281		/* MODEL 2 */
    282		{ .offset	= -19563152,
    283		  .slope	=  1956315
    284		},
    285		/* MODEL 3 */
    286		{ .offset	= -15650652,
    287		  .slope	=  1565065
    288		},
    289	},
    290	/* FAN_HD */
    291	{
    292		/* MODEL 2 */
    293		{ .offset	= -15650652,
    294		  .slope	=  1565065
    295		},
    296		/* MODEL 3 */
    297		{ .offset	= -19563152,
    298		  .slope	=  1956315
    299		},
    300	},
    301	/* FAN_CPU */
    302	{
    303		/* MODEL 2 */
    304		{ .offset	= -25431900,
    305		  .slope	=  2543190
    306		},
    307		/* MODEL 3 */
    308		{ .offset	= -15650652,
    309		  .slope	=  1565065
    310		},
    311	},
    312	/* CPUFREQ has no correction (and is not implemented at all) */
    313};
    314
    315struct pm121_connection {
    316	unsigned int	control_id;
    317	unsigned int	ref_id;
    318	struct pm121_correction	correction;
    319};
    320
    321static struct pm121_connection pm121_connections[] = {
    322	/* MODEL 2 */
    323	{ .control_id	= FAN_CPU,
    324	  .ref_id	= FAN_OD,
    325	  { .offset	= -32768000,
    326	    .slope	=  65536
    327	  }
    328	},
    329	/* MODEL 3 */
    330	{ .control_id	= FAN_OD,
    331	  .ref_id	= FAN_HD,
    332	  { .offset	= -32768000,
    333	    .slope	=  65536
    334	  }
    335	},
    336};
    337
    338/* pointer to the current model connection */
    339static struct pm121_connection *pm121_connection;
    340
    341/*
    342 * ****** System Fans Control Loop ******
    343 *
    344 */
    345
    346/* Since each loop handles only one control and we want to avoid
    347 * writing virtual control, we store the control correction with the
    348 * loop params. Some data are not set, there are common to all loop
    349 * and thus, hardcoded.
    350 */
    351struct pm121_sys_param {
    352	/* purely informative since we use mach_model-2 as index */
    353	int			model_id;
    354	struct wf_sensor	**sensor; /* use sensor_id instead ? */
    355	s32			gp, itarget;
    356	unsigned int		control_id;
    357};
    358
    359static struct pm121_sys_param
    360pm121_sys_all_params[N_LOOPS][PM121_NUM_CONFIGS] = {
    361	/* GPU Fan control loop */
    362	{
    363		{ .model_id	= 2,
    364		  .sensor	= &sensor_gpu_temp,
    365		  .gp		= 0x002A6666,
    366		  .itarget	= 0x5A0000,
    367		  .control_id	= FAN_HD,
    368		},
    369		{ .model_id	= 3,
    370		  .sensor	= &sensor_gpu_temp,
    371		  .gp		= 0x0010CCCC,
    372		  .itarget	= 0x500000,
    373		  .control_id	= FAN_CPU,
    374		},
    375	},
    376	/* HD Fan control loop */
    377	{
    378		{ .model_id	= 2,
    379		  .sensor	= &sensor_hard_drive_temp,
    380		  .gp		= 0x002D70A3,
    381		  .itarget	= 0x370000,
    382		  .control_id	= FAN_HD,
    383		},
    384		{ .model_id	= 3,
    385		  .sensor	= &sensor_hard_drive_temp,
    386		  .gp		= 0x002170A3,
    387		  .itarget	= 0x370000,
    388		  .control_id	= FAN_HD,
    389		},
    390	},
    391	/* KODIAK Fan control loop */
    392	{
    393		{ .model_id	= 2,
    394		  .sensor	= &sensor_north_bridge_temp,
    395		  .gp		= 0x003BD70A,
    396		  .itarget	= 0x550000,
    397		  .control_id	= FAN_OD,
    398		},
    399		{ .model_id	= 3,
    400		  .sensor	= &sensor_north_bridge_temp,
    401		  .gp		= 0x0030F5C2,
    402		  .itarget	= 0x550000,
    403		  .control_id	= FAN_HD,
    404		},
    405	},
    406	/* OD Fan control loop */
    407	{
    408		{ .model_id	= 2,
    409		  .sensor	= &sensor_optical_drive_temp,
    410		  .gp		= 0x001FAE14,
    411		  .itarget	= 0x320000,
    412		  .control_id	= FAN_OD,
    413		},
    414		{ .model_id	= 3,
    415		  .sensor	= &sensor_optical_drive_temp,
    416		  .gp		= 0x001FAE14,
    417		  .itarget	= 0x320000,
    418		  .control_id	= FAN_OD,
    419		},
    420	},
    421};
    422
    423/* the hardcoded values */
    424#define	PM121_SYS_GD		0x00000000
    425#define	PM121_SYS_GR		0x00019999
    426#define	PM121_SYS_HISTORY_SIZE	2
    427#define	PM121_SYS_INTERVAL	5
    428
    429/* State data used by the system fans control loop
    430 */
    431struct pm121_sys_state {
    432	int			ticks;
    433	s32			setpoint;
    434	struct wf_pid_state	pid;
    435};
    436
    437static struct pm121_sys_state *pm121_sys_state[N_LOOPS] = {};
    438
    439/*
    440 * ****** CPU Fans Control Loop ******
    441 *
    442 */
    443
    444#define PM121_CPU_INTERVAL	1
    445
    446/* State data used by the cpu fans control loop
    447 */
    448struct pm121_cpu_state {
    449	int			ticks;
    450	s32			setpoint;
    451	struct wf_cpu_pid_state	pid;
    452};
    453
    454static struct pm121_cpu_state *pm121_cpu_state;
    455
    456
    457
    458/*
    459 * ***** Implementation *****
    460 *
    461 */
    462
    463/* correction the value using the output-low-bound correction algo */
    464static s32 pm121_correct(s32 new_setpoint,
    465			 unsigned int control_id,
    466			 s32 min)
    467{
    468	s32 new_min;
    469	struct pm121_correction *correction;
    470	correction = &corrections[control_id][pm121_mach_model - 2];
    471
    472	new_min = (average_power * correction->slope) >> 16;
    473	new_min += correction->offset;
    474	new_min = (new_min >> 16) + min;
    475
    476	return max3(new_setpoint, new_min, 0);
    477}
    478
    479static s32 pm121_connect(unsigned int control_id, s32 setpoint)
    480{
    481	s32 new_min, value, new_setpoint;
    482
    483	if (pm121_connection->control_id == control_id) {
    484		controls[control_id]->ops->get_value(controls[control_id],
    485						     &value);
    486		new_min = value * pm121_connection->correction.slope;
    487		new_min += pm121_connection->correction.offset;
    488		if (new_min > 0) {
    489			new_setpoint = max(setpoint, (new_min >> 16));
    490			if (new_setpoint != setpoint) {
    491				pr_debug("pm121: %s depending on %s, "
    492					 "corrected from %d to %d RPM\n",
    493					 controls[control_id]->name,
    494					 controls[pm121_connection->ref_id]->name,
    495					 (int) setpoint, (int) new_setpoint);
    496			}
    497		} else
    498			new_setpoint = setpoint;
    499	}
    500	/* no connection */
    501	else
    502		new_setpoint = setpoint;
    503
    504	return new_setpoint;
    505}
    506
    507/* FAN LOOPS */
    508static void pm121_create_sys_fans(int loop_id)
    509{
    510	struct pm121_sys_param *param = NULL;
    511	struct wf_pid_param pid_param;
    512	struct wf_control *control = NULL;
    513	int i;
    514
    515	/* First, locate the params for this model */
    516	for (i = 0; i < PM121_NUM_CONFIGS; i++) {
    517		if (pm121_sys_all_params[loop_id][i].model_id == pm121_mach_model) {
    518			param = &(pm121_sys_all_params[loop_id][i]);
    519			break;
    520		}
    521	}
    522
    523	/* No params found, put fans to max */
    524	if (param == NULL) {
    525		printk(KERN_WARNING "pm121: %s fan config not found "
    526		       " for this machine model\n",
    527		       loop_names[loop_id]);
    528		goto fail;
    529	}
    530
    531	control = controls[param->control_id];
    532
    533	/* Alloc & initialize state */
    534	pm121_sys_state[loop_id] = kmalloc(sizeof(struct pm121_sys_state),
    535					   GFP_KERNEL);
    536	if (pm121_sys_state[loop_id] == NULL) {
    537		printk(KERN_WARNING "pm121: Memory allocation error\n");
    538		goto fail;
    539	}
    540	pm121_sys_state[loop_id]->ticks = 1;
    541
    542	/* Fill PID params */
    543	pid_param.gd		= PM121_SYS_GD;
    544	pid_param.gp		= param->gp;
    545	pid_param.gr		= PM121_SYS_GR;
    546	pid_param.interval	= PM121_SYS_INTERVAL;
    547	pid_param.history_len	= PM121_SYS_HISTORY_SIZE;
    548	pid_param.itarget	= param->itarget;
    549	if(control)
    550	{
    551		pid_param.min		= control->ops->get_min(control);
    552		pid_param.max		= control->ops->get_max(control);
    553	} else {
    554		/*
    555		 * This is probably not the right!?
    556		 * Perhaps goto fail  if control == NULL  above?
    557		 */
    558		pid_param.min		= 0;
    559		pid_param.max		= 0;
    560	}
    561
    562	wf_pid_init(&pm121_sys_state[loop_id]->pid, &pid_param);
    563
    564	pr_debug("pm121: %s Fan control loop initialized.\n"
    565		 "       itarged=%d.%03d, min=%d RPM, max=%d RPM\n",
    566		 loop_names[loop_id], FIX32TOPRINT(pid_param.itarget),
    567		 pid_param.min, pid_param.max);
    568	return;
    569
    570 fail:
    571	/* note that this is not optimal since another loop may still
    572	   control the same control */
    573	printk(KERN_WARNING "pm121: failed to set up %s loop "
    574	       "setting \"%s\" to max speed.\n",
    575	       loop_names[loop_id], control ? control->name : "uninitialized value");
    576
    577	if (control)
    578		wf_control_set_max(control);
    579}
    580
    581static void pm121_sys_fans_tick(int loop_id)
    582{
    583	struct pm121_sys_param *param;
    584	struct pm121_sys_state *st;
    585	struct wf_sensor *sensor;
    586	struct wf_control *control;
    587	s32 temp, new_setpoint;
    588	int rc;
    589
    590	param = &(pm121_sys_all_params[loop_id][pm121_mach_model-2]);
    591	st = pm121_sys_state[loop_id];
    592	sensor = *(param->sensor);
    593	control = controls[param->control_id];
    594
    595	if (--st->ticks != 0) {
    596		if (pm121_readjust)
    597			goto readjust;
    598		return;
    599	}
    600	st->ticks = PM121_SYS_INTERVAL;
    601
    602	rc = sensor->ops->get_value(sensor, &temp);
    603	if (rc) {
    604		printk(KERN_WARNING "windfarm: %s sensor error %d\n",
    605		       sensor->name, rc);
    606		pm121_failure_state |= FAILURE_SENSOR;
    607		return;
    608	}
    609
    610	pr_debug("pm121: %s Fan tick ! %s: %d.%03d\n",
    611		 loop_names[loop_id], sensor->name,
    612		 FIX32TOPRINT(temp));
    613
    614	new_setpoint = wf_pid_run(&st->pid, temp);
    615
    616	/* correction */
    617	new_setpoint = pm121_correct(new_setpoint,
    618				     param->control_id,
    619				     st->pid.param.min);
    620	/* linked corretion */
    621	new_setpoint = pm121_connect(param->control_id, new_setpoint);
    622
    623	if (new_setpoint == st->setpoint)
    624		return;
    625	st->setpoint = new_setpoint;
    626	pr_debug("pm121: %s corrected setpoint: %d RPM\n",
    627		 control->name, (int)new_setpoint);
    628 readjust:
    629	if (control && pm121_failure_state == 0) {
    630		rc = control->ops->set_value(control, st->setpoint);
    631		if (rc) {
    632			printk(KERN_WARNING "windfarm: %s fan error %d\n",
    633			       control->name, rc);
    634			pm121_failure_state |= FAILURE_FAN;
    635		}
    636	}
    637}
    638
    639
    640/* CPU LOOP */
    641static void pm121_create_cpu_fans(void)
    642{
    643	struct wf_cpu_pid_param pid_param;
    644	const struct smu_sdbp_header *hdr;
    645	struct smu_sdbp_cpupiddata *piddata;
    646	struct smu_sdbp_fvt *fvt;
    647	struct wf_control *fan_cpu;
    648	s32 tmax, tdelta, maxpow, powadj;
    649
    650	fan_cpu = controls[FAN_CPU];
    651
    652	/* First, locate the PID params in SMU SBD */
    653	hdr = smu_get_sdb_partition(SMU_SDB_CPUPIDDATA_ID, NULL);
    654	if (hdr == 0) {
    655		printk(KERN_WARNING "pm121: CPU PID fan config not found.\n");
    656		goto fail;
    657	}
    658	piddata = (struct smu_sdbp_cpupiddata *)&hdr[1];
    659
    660	/* Get the FVT params for operating point 0 (the only supported one
    661	 * for now) in order to get tmax
    662	 */
    663	hdr = smu_get_sdb_partition(SMU_SDB_FVT_ID, NULL);
    664	if (hdr) {
    665		fvt = (struct smu_sdbp_fvt *)&hdr[1];
    666		tmax = ((s32)fvt->maxtemp) << 16;
    667	} else
    668		tmax = 0x5e0000; /* 94 degree default */
    669
    670	/* Alloc & initialize state */
    671	pm121_cpu_state = kmalloc(sizeof(struct pm121_cpu_state),
    672				  GFP_KERNEL);
    673	if (pm121_cpu_state == NULL)
    674		goto fail;
    675	pm121_cpu_state->ticks = 1;
    676
    677	/* Fill PID params */
    678	pid_param.interval = PM121_CPU_INTERVAL;
    679	pid_param.history_len = piddata->history_len;
    680	if (pid_param.history_len > WF_CPU_PID_MAX_HISTORY) {
    681		printk(KERN_WARNING "pm121: History size overflow on "
    682		       "CPU control loop (%d)\n", piddata->history_len);
    683		pid_param.history_len = WF_CPU_PID_MAX_HISTORY;
    684	}
    685	pid_param.gd = piddata->gd;
    686	pid_param.gp = piddata->gp;
    687	pid_param.gr = piddata->gr / pid_param.history_len;
    688
    689	tdelta = ((s32)piddata->target_temp_delta) << 16;
    690	maxpow = ((s32)piddata->max_power) << 16;
    691	powadj = ((s32)piddata->power_adj) << 16;
    692
    693	pid_param.tmax = tmax;
    694	pid_param.ttarget = tmax - tdelta;
    695	pid_param.pmaxadj = maxpow - powadj;
    696
    697	pid_param.min = fan_cpu->ops->get_min(fan_cpu);
    698	pid_param.max = fan_cpu->ops->get_max(fan_cpu);
    699
    700	wf_cpu_pid_init(&pm121_cpu_state->pid, &pid_param);
    701
    702	pr_debug("pm121: CPU Fan control initialized.\n");
    703	pr_debug("       ttarget=%d.%03d, tmax=%d.%03d, min=%d RPM, max=%d RPM,\n",
    704		 FIX32TOPRINT(pid_param.ttarget), FIX32TOPRINT(pid_param.tmax),
    705		 pid_param.min, pid_param.max);
    706
    707	return;
    708
    709 fail:
    710	printk(KERN_WARNING "pm121: CPU fan config not found, max fan speed\n");
    711
    712	if (controls[CPUFREQ])
    713		wf_control_set_max(controls[CPUFREQ]);
    714	if (fan_cpu)
    715		wf_control_set_max(fan_cpu);
    716}
    717
    718
    719static void pm121_cpu_fans_tick(struct pm121_cpu_state *st)
    720{
    721	s32 new_setpoint, temp, power;
    722	struct wf_control *fan_cpu = NULL;
    723	int rc;
    724
    725	if (--st->ticks != 0) {
    726		if (pm121_readjust)
    727			goto readjust;
    728		return;
    729	}
    730	st->ticks = PM121_CPU_INTERVAL;
    731
    732	fan_cpu = controls[FAN_CPU];
    733
    734	rc = sensor_cpu_temp->ops->get_value(sensor_cpu_temp, &temp);
    735	if (rc) {
    736		printk(KERN_WARNING "pm121: CPU temp sensor error %d\n",
    737		       rc);
    738		pm121_failure_state |= FAILURE_SENSOR;
    739		return;
    740	}
    741
    742	rc = sensor_cpu_power->ops->get_value(sensor_cpu_power, &power);
    743	if (rc) {
    744		printk(KERN_WARNING "pm121: CPU power sensor error %d\n",
    745		       rc);
    746		pm121_failure_state |= FAILURE_SENSOR;
    747		return;
    748	}
    749
    750	pr_debug("pm121: CPU Fans tick ! CPU temp: %d.%03d°C, power: %d.%03d\n",
    751		 FIX32TOPRINT(temp), FIX32TOPRINT(power));
    752
    753	if (temp > st->pid.param.tmax)
    754		pm121_failure_state |= FAILURE_OVERTEMP;
    755
    756	new_setpoint = wf_cpu_pid_run(&st->pid, power, temp);
    757
    758	/* correction */
    759	new_setpoint = pm121_correct(new_setpoint,
    760				     FAN_CPU,
    761				     st->pid.param.min);
    762
    763	/* connected correction */
    764	new_setpoint = pm121_connect(FAN_CPU, new_setpoint);
    765
    766	if (st->setpoint == new_setpoint)
    767		return;
    768	st->setpoint = new_setpoint;
    769	pr_debug("pm121: CPU corrected setpoint: %d RPM\n", (int)new_setpoint);
    770
    771 readjust:
    772	if (fan_cpu && pm121_failure_state == 0) {
    773		rc = fan_cpu->ops->set_value(fan_cpu, st->setpoint);
    774		if (rc) {
    775			printk(KERN_WARNING "pm121: %s fan error %d\n",
    776			       fan_cpu->name, rc);
    777			pm121_failure_state |= FAILURE_FAN;
    778		}
    779	}
    780}
    781
    782/*
    783 * ****** Common ******
    784 *
    785 */
    786
    787static void pm121_tick(void)
    788{
    789	unsigned int last_failure = pm121_failure_state;
    790	unsigned int new_failure;
    791	s32 total_power;
    792	int i;
    793
    794	if (!pm121_started) {
    795		pr_debug("pm121: creating control loops !\n");
    796		for (i = 0; i < N_LOOPS; i++)
    797			pm121_create_sys_fans(i);
    798
    799		pm121_create_cpu_fans();
    800		pm121_started = true;
    801	}
    802
    803	/* skipping ticks */
    804	if (pm121_skipping && --pm121_skipping)
    805		return;
    806
    807	/* compute average power */
    808	total_power = 0;
    809	for (i = 0; i < pm121_cpu_state->pid.param.history_len; i++)
    810		total_power += pm121_cpu_state->pid.powers[i];
    811
    812	average_power = total_power / pm121_cpu_state->pid.param.history_len;
    813
    814
    815	pm121_failure_state = 0;
    816	for (i = 0 ; i < N_LOOPS; i++) {
    817		if (pm121_sys_state[i])
    818			pm121_sys_fans_tick(i);
    819	}
    820
    821	if (pm121_cpu_state)
    822		pm121_cpu_fans_tick(pm121_cpu_state);
    823
    824	pm121_readjust = 0;
    825	new_failure = pm121_failure_state & ~last_failure;
    826
    827	/* If entering failure mode, clamp cpufreq and ramp all
    828	 * fans to full speed.
    829	 */
    830	if (pm121_failure_state && !last_failure) {
    831		for (i = 0; i < N_CONTROLS; i++) {
    832			if (controls[i])
    833				wf_control_set_max(controls[i]);
    834		}
    835	}
    836
    837	/* If leaving failure mode, unclamp cpufreq and readjust
    838	 * all fans on next iteration
    839	 */
    840	if (!pm121_failure_state && last_failure) {
    841		if (controls[CPUFREQ])
    842			wf_control_set_min(controls[CPUFREQ]);
    843		pm121_readjust = 1;
    844	}
    845
    846	/* Overtemp condition detected, notify and start skipping a couple
    847	 * ticks to let the temperature go down
    848	 */
    849	if (new_failure & FAILURE_OVERTEMP) {
    850		wf_set_overtemp();
    851		pm121_skipping = 2;
    852		pm121_overtemp = true;
    853	}
    854
    855	/* We only clear the overtemp condition if overtemp is cleared
    856	 * _and_ no other failure is present. Since a sensor error will
    857	 * clear the overtemp condition (can't measure temperature) at
    858	 * the control loop levels, but we don't want to keep it clear
    859	 * here in this case
    860	 */
    861	if (!pm121_failure_state && pm121_overtemp) {
    862		wf_clear_overtemp();
    863		pm121_overtemp = false;
    864	}
    865}
    866
    867
    868static struct wf_control* pm121_register_control(struct wf_control *ct,
    869						 const char *match,
    870						 unsigned int id)
    871{
    872	if (controls[id] == NULL && !strcmp(ct->name, match)) {
    873		if (wf_get_control(ct) == 0)
    874			controls[id] = ct;
    875	}
    876	return controls[id];
    877}
    878
    879static void pm121_new_control(struct wf_control *ct)
    880{
    881	int all = 1;
    882
    883	if (pm121_all_controls_ok)
    884		return;
    885
    886	all = pm121_register_control(ct, "optical-drive-fan", FAN_OD) && all;
    887	all = pm121_register_control(ct, "hard-drive-fan", FAN_HD) && all;
    888	all = pm121_register_control(ct, "cpu-fan", FAN_CPU) && all;
    889	all = pm121_register_control(ct, "cpufreq-clamp", CPUFREQ) && all;
    890
    891	if (all)
    892		pm121_all_controls_ok = 1;
    893}
    894
    895
    896
    897
    898static struct wf_sensor* pm121_register_sensor(struct wf_sensor *sensor,
    899					       const char *match,
    900					       struct wf_sensor **var)
    901{
    902	if (*var == NULL && !strcmp(sensor->name, match)) {
    903		if (wf_get_sensor(sensor) == 0)
    904			*var = sensor;
    905	}
    906	return *var;
    907}
    908
    909static void pm121_new_sensor(struct wf_sensor *sr)
    910{
    911	int all = 1;
    912
    913	if (pm121_all_sensors_ok)
    914		return;
    915
    916	all = pm121_register_sensor(sr, "cpu-temp",
    917				    &sensor_cpu_temp) && all;
    918	all = pm121_register_sensor(sr, "cpu-current",
    919				    &sensor_cpu_current) && all;
    920	all = pm121_register_sensor(sr, "cpu-voltage",
    921				    &sensor_cpu_voltage) && all;
    922	all = pm121_register_sensor(sr, "cpu-power",
    923				    &sensor_cpu_power) && all;
    924	all = pm121_register_sensor(sr, "hard-drive-temp",
    925				    &sensor_hard_drive_temp) && all;
    926	all = pm121_register_sensor(sr, "optical-drive-temp",
    927				    &sensor_optical_drive_temp) && all;
    928	all = pm121_register_sensor(sr, "incoming-air-temp",
    929				    &sensor_incoming_air_temp) && all;
    930	all = pm121_register_sensor(sr, "north-bridge-temp",
    931				    &sensor_north_bridge_temp) && all;
    932	all = pm121_register_sensor(sr, "gpu-temp",
    933				    &sensor_gpu_temp) && all;
    934
    935	if (all)
    936		pm121_all_sensors_ok = 1;
    937}
    938
    939
    940
    941static int pm121_notify(struct notifier_block *self,
    942			unsigned long event, void *data)
    943{
    944	switch (event) {
    945	case WF_EVENT_NEW_CONTROL:
    946		pr_debug("pm121: new control %s detected\n",
    947			 ((struct wf_control *)data)->name);
    948		pm121_new_control(data);
    949		break;
    950	case WF_EVENT_NEW_SENSOR:
    951		pr_debug("pm121: new sensor %s detected\n",
    952			 ((struct wf_sensor *)data)->name);
    953		pm121_new_sensor(data);
    954		break;
    955	case WF_EVENT_TICK:
    956		if (pm121_all_controls_ok && pm121_all_sensors_ok)
    957			pm121_tick();
    958		break;
    959	}
    960
    961	return 0;
    962}
    963
    964static struct notifier_block pm121_events = {
    965	.notifier_call	= pm121_notify,
    966};
    967
    968static int pm121_init_pm(void)
    969{
    970	const struct smu_sdbp_header *hdr;
    971
    972	hdr = smu_get_sdb_partition(SMU_SDB_SENSORTREE_ID, NULL);
    973	if (hdr != 0) {
    974		struct smu_sdbp_sensortree *st =
    975			(struct smu_sdbp_sensortree *)&hdr[1];
    976		pm121_mach_model = st->model_id;
    977	}
    978
    979	pm121_connection = &pm121_connections[pm121_mach_model - 2];
    980
    981	printk(KERN_INFO "pm121: Initializing for iMac G5 iSight model ID %d\n",
    982	       pm121_mach_model);
    983
    984	return 0;
    985}
    986
    987
    988static int pm121_probe(struct platform_device *ddev)
    989{
    990	wf_register_client(&pm121_events);
    991
    992	return 0;
    993}
    994
    995static int pm121_remove(struct platform_device *ddev)
    996{
    997	wf_unregister_client(&pm121_events);
    998	return 0;
    999}
   1000
   1001static struct platform_driver pm121_driver = {
   1002	.probe = pm121_probe,
   1003	.remove = pm121_remove,
   1004	.driver = {
   1005		.name = "windfarm",
   1006		.bus = &platform_bus_type,
   1007	},
   1008};
   1009
   1010
   1011static int __init pm121_init(void)
   1012{
   1013	int rc = -ENODEV;
   1014
   1015	if (of_machine_is_compatible("PowerMac12,1"))
   1016		rc = pm121_init_pm();
   1017
   1018	if (rc == 0) {
   1019		request_module("windfarm_smu_controls");
   1020		request_module("windfarm_smu_sensors");
   1021		request_module("windfarm_smu_sat");
   1022		request_module("windfarm_lm75_sensor");
   1023		request_module("windfarm_max6690_sensor");
   1024		request_module("windfarm_cpufreq_clamp");
   1025		platform_driver_register(&pm121_driver);
   1026	}
   1027
   1028	return rc;
   1029}
   1030
   1031static void __exit pm121_exit(void)
   1032{
   1033
   1034	platform_driver_unregister(&pm121_driver);
   1035}
   1036
   1037
   1038module_init(pm121_init);
   1039module_exit(pm121_exit);
   1040
   1041MODULE_AUTHOR("Étienne Bersac <bersace@gmail.com>");
   1042MODULE_DESCRIPTION("Thermal control logic for iMac G5 (iSight)");
   1043MODULE_LICENSE("GPL");
   1044