aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2006-02-08 00:42:51 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2006-02-08 01:05:14 -0500
commitac171c46667c1cb2ee9e22312291df6ed78e1b6e (patch)
tree86ca722abc1ddceb0887b3ed6a195d77bb200dc2
parent746f956beb534ddf73da4346de81f2941c8573f8 (diff)
[PATCH] powerpc: Thermal control for dual core G5s
This patch adds a windfarm module, windfarm_pm112, for the dual core G5s (both 2 and 4 core models), keeping the machine from getting into vacuum-cleaner mode ;) For proper credits, the patch was initially written by Paul Mackerras, and slightly reworked by me to add overtemp handling among others. The patch also removes the sysfs attributes from windfarm_pm81 and windfarm_pm91 and instead adds code to the windfarm core to automagically expose attributes for sensor & controls. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--drivers/macintosh/Kconfig8
-rw-r--r--drivers/macintosh/Makefile5
-rw-r--r--drivers/macintosh/windfarm.h3
-rw-r--r--drivers/macintosh/windfarm_core.c69
-rw-r--r--drivers/macintosh/windfarm_max6690_sensor.c169
-rw-r--r--drivers/macintosh/windfarm_pid.c8
-rw-r--r--drivers/macintosh/windfarm_pid.h1
-rw-r--r--drivers/macintosh/windfarm_pm112.c698
-rw-r--r--drivers/macintosh/windfarm_pm81.c87
-rw-r--r--drivers/macintosh/windfarm_pm91.c95
-rw-r--r--drivers/macintosh/windfarm_smu_controls.c69
-rw-r--r--drivers/macintosh/windfarm_smu_sat.c418
-rw-r--r--drivers/macintosh/windfarm_smu_sensors.c43
-rw-r--r--include/asm-powerpc/smu.h5
14 files changed, 1479 insertions, 199 deletions
diff --git a/drivers/macintosh/Kconfig b/drivers/macintosh/Kconfig
index 7d4a0ac28c0..b11cd31d8d2 100644
--- a/drivers/macintosh/Kconfig
+++ b/drivers/macintosh/Kconfig
@@ -187,6 +187,14 @@ config WINDFARM_PM91
187 This driver provides thermal control for the PowerMac9,1 187 This driver provides thermal control for the PowerMac9,1
188 which is the recent (SMU based) single CPU desktop G5 188 which is the recent (SMU based) single CPU desktop G5
189 189
190config WINDFARM_PM112
191 tristate "Support for thermal management on PowerMac11,2"
192 depends on WINDFARM && I2C && PMAC_SMU
193 select I2C_PMAC_SMU
194 help
195 This driver provides thermal control for the PowerMac11,2
196 which are the recent dual and quad G5 machines using the
197 970MP dual-core processor.
190 198
191config ANSLCD 199config ANSLCD
192 tristate "Support for ANS LCD display" 200 tristate "Support for ANS LCD display"
diff --git a/drivers/macintosh/Makefile b/drivers/macintosh/Makefile
index f4657aa81fb..6081acdea40 100644
--- a/drivers/macintosh/Makefile
+++ b/drivers/macintosh/Makefile
@@ -35,3 +35,8 @@ obj-$(CONFIG_WINDFARM_PM91) += windfarm_smu_controls.o \
35 windfarm_smu_sensors.o \ 35 windfarm_smu_sensors.o \
36 windfarm_lm75_sensor.o windfarm_pid.o \ 36 windfarm_lm75_sensor.o windfarm_pid.o \
37 windfarm_cpufreq_clamp.o windfarm_pm91.o 37 windfarm_cpufreq_clamp.o windfarm_pm91.o
38obj-$(CONFIG_WINDFARM_PM112) += windfarm_pm112.o windfarm_smu_sat.o \
39 windfarm_smu_controls.o \
40 windfarm_smu_sensors.o \
41 windfarm_max6690_sensor.o \
42 windfarm_lm75_sensor.o windfarm_pid.o
diff --git a/drivers/macintosh/windfarm.h b/drivers/macintosh/windfarm.h
index 3f0cb0312ea..7a2482cc26a 100644
--- a/drivers/macintosh/windfarm.h
+++ b/drivers/macintosh/windfarm.h
@@ -14,6 +14,7 @@
14#include <linux/list.h> 14#include <linux/list.h>
15#include <linux/module.h> 15#include <linux/module.h>
16#include <linux/notifier.h> 16#include <linux/notifier.h>
17#include <linux/device.h>
17 18
18/* Display a 16.16 fixed point value */ 19/* Display a 16.16 fixed point value */
19#define FIX32TOPRINT(f) ((f) >> 16),((((f) & 0xffff) * 1000) >> 16) 20#define FIX32TOPRINT(f) ((f) >> 16),((((f) & 0xffff) * 1000) >> 16)
@@ -39,6 +40,7 @@ struct wf_control {
39 char *name; 40 char *name;
40 int type; 41 int type;
41 struct kref ref; 42 struct kref ref;
43 struct device_attribute attr;
42}; 44};
43 45
44#define WF_CONTROL_TYPE_GENERIC 0 46#define WF_CONTROL_TYPE_GENERIC 0
@@ -87,6 +89,7 @@ struct wf_sensor {
87 struct wf_sensor_ops *ops; 89 struct wf_sensor_ops *ops;
88 char *name; 90 char *name;
89 struct kref ref; 91 struct kref ref;
92 struct device_attribute attr;
90}; 93};
91 94
92/* Same lifetime rules as controls */ 95/* Same lifetime rules as controls */
diff --git a/drivers/macintosh/windfarm_core.c b/drivers/macintosh/windfarm_core.c
index 32d466441ac..bb8d5efe19b 100644
--- a/drivers/macintosh/windfarm_core.c
+++ b/drivers/macintosh/windfarm_core.c
@@ -56,6 +56,10 @@ static unsigned int wf_overtemp;
56static unsigned int wf_overtemp_counter; 56static unsigned int wf_overtemp_counter;
57struct task_struct *wf_thread; 57struct task_struct *wf_thread;
58 58
59static struct platform_device wf_platform_device = {
60 .name = "windfarm",
61};
62
59/* 63/*
60 * Utilities & tick thread 64 * Utilities & tick thread
61 */ 65 */
@@ -157,6 +161,40 @@ static void wf_control_release(struct kref *kref)
157 kfree(ct); 161 kfree(ct);
158} 162}
159 163
164static ssize_t wf_show_control(struct device *dev,
165 struct device_attribute *attr, char *buf)
166{
167 struct wf_control *ctrl = container_of(attr, struct wf_control, attr);
168 s32 val = 0;
169 int err;
170
171 err = ctrl->ops->get_value(ctrl, &val);
172 if (err < 0)
173 return err;
174 return sprintf(buf, "%d\n", val);
175}
176
177/* This is really only for debugging... */
178static ssize_t wf_store_control(struct device *dev,
179 struct device_attribute *attr,
180 const char *buf, size_t count)
181{
182 struct wf_control *ctrl = container_of(attr, struct wf_control, attr);
183 int val;
184 int err;
185 char *endp;
186
187 val = simple_strtoul(buf, &endp, 0);
188 while (endp < buf + count && (*endp == ' ' || *endp == '\n'))
189 ++endp;
190 if (endp - buf < count)
191 return -EINVAL;
192 err = ctrl->ops->set_value(ctrl, val);
193 if (err < 0)
194 return err;
195 return count;
196}
197
160int wf_register_control(struct wf_control *new_ct) 198int wf_register_control(struct wf_control *new_ct)
161{ 199{
162 struct wf_control *ct; 200 struct wf_control *ct;
@@ -173,6 +211,13 @@ int wf_register_control(struct wf_control *new_ct)
173 kref_init(&new_ct->ref); 211 kref_init(&new_ct->ref);
174 list_add(&new_ct->link, &wf_controls); 212 list_add(&new_ct->link, &wf_controls);
175 213
214 new_ct->attr.attr.name = new_ct->name;
215 new_ct->attr.attr.owner = THIS_MODULE;
216 new_ct->attr.attr.mode = 0644;
217 new_ct->attr.show = wf_show_control;
218 new_ct->attr.store = wf_store_control;
219 device_create_file(&wf_platform_device.dev, &new_ct->attr);
220
176 DBG("wf: Registered control %s\n", new_ct->name); 221 DBG("wf: Registered control %s\n", new_ct->name);
177 222
178 wf_notify(WF_EVENT_NEW_CONTROL, new_ct); 223 wf_notify(WF_EVENT_NEW_CONTROL, new_ct);
@@ -247,6 +292,19 @@ static void wf_sensor_release(struct kref *kref)
247 kfree(sr); 292 kfree(sr);
248} 293}
249 294
295static ssize_t wf_show_sensor(struct device *dev,
296 struct device_attribute *attr, char *buf)
297{
298 struct wf_sensor *sens = container_of(attr, struct wf_sensor, attr);
299 s32 val = 0;
300 int err;
301
302 err = sens->ops->get_value(sens, &val);
303 if (err < 0)
304 return err;
305 return sprintf(buf, "%d.%03d\n", FIX32TOPRINT(val));
306}
307
250int wf_register_sensor(struct wf_sensor *new_sr) 308int wf_register_sensor(struct wf_sensor *new_sr)
251{ 309{
252 struct wf_sensor *sr; 310 struct wf_sensor *sr;
@@ -263,6 +321,13 @@ int wf_register_sensor(struct wf_sensor *new_sr)
263 kref_init(&new_sr->ref); 321 kref_init(&new_sr->ref);
264 list_add(&new_sr->link, &wf_sensors); 322 list_add(&new_sr->link, &wf_sensors);
265 323
324 new_sr->attr.attr.name = new_sr->name;
325 new_sr->attr.attr.owner = THIS_MODULE;
326 new_sr->attr.attr.mode = 0444;
327 new_sr->attr.show = wf_show_sensor;
328 new_sr->attr.store = NULL;
329 device_create_file(&wf_platform_device.dev, &new_sr->attr);
330
266 DBG("wf: Registered sensor %s\n", new_sr->name); 331 DBG("wf: Registered sensor %s\n", new_sr->name);
267 332
268 wf_notify(WF_EVENT_NEW_SENSOR, new_sr); 333 wf_notify(WF_EVENT_NEW_SENSOR, new_sr);
@@ -396,10 +461,6 @@ int wf_is_overtemp(void)
396} 461}
397EXPORT_SYMBOL_GPL(wf_is_overtemp); 462EXPORT_SYMBOL_GPL(wf_is_overtemp);
398 463
399static struct platform_device wf_platform_device = {
400 .name = "windfarm",
401};
402
403static int __init windfarm_core_init(void) 464static int __init windfarm_core_init(void)
404{ 465{
405 DBG("wf: core loaded\n"); 466 DBG("wf: core loaded\n");
diff --git a/drivers/macintosh/windfarm_max6690_sensor.c b/drivers/macintosh/windfarm_max6690_sensor.c
new file mode 100644
index 00000000000..5b9ad6ca7cb
--- /dev/null
+++ b/drivers/macintosh/windfarm_max6690_sensor.c
@@ -0,0 +1,169 @@
1/*
2 * Windfarm PowerMac thermal control. MAX6690 sensor.
3 *
4 * Copyright (C) 2005 Paul Mackerras, IBM Corp. <paulus@samba.org>
5 *
6 * Use and redistribute under the terms of the GNU GPL v2.
7 */
8#include <linux/types.h>
9#include <linux/errno.h>
10#include <linux/kernel.h>
11#include <linux/init.h>
12#include <linux/slab.h>
13#include <linux/i2c.h>
14#include <linux/i2c-dev.h>
15#include <asm/prom.h>
16#include <asm/pmac_low_i2c.h>
17
18#include "windfarm.h"
19
20#define VERSION "0.1"
21
22/* This currently only exports the external temperature sensor,
23 since that's all the control loops need. */
24
25/* Some MAX6690 register numbers */
26#define MAX6690_INTERNAL_TEMP 0
27#define MAX6690_EXTERNAL_TEMP 1
28
29struct wf_6690_sensor {
30 struct i2c_client i2c;
31 struct wf_sensor sens;
32};
33
34#define wf_to_6690(x) container_of((x), struct wf_6690_sensor, sens)
35#define i2c_to_6690(x) container_of((x), struct wf_6690_sensor, i2c)
36
37static int wf_max6690_attach(struct i2c_adapter *adapter);
38static int wf_max6690_detach(struct i2c_client *client);
39
40static struct i2c_driver wf_max6690_driver = {
41 .driver = {
42 .name = "wf_max6690",
43 },
44 .attach_adapter = wf_max6690_attach,
45 .detach_client = wf_max6690_detach,
46};
47
48static int wf_max6690_get(struct wf_sensor *sr, s32 *value)
49{
50 struct wf_6690_sensor *max = wf_to_6690(sr);
51 s32 data;
52
53 if (max->i2c.adapter == NULL)
54 return -ENODEV;
55
56 /* chip gets initialized by firmware */
57 data = i2c_smbus_read_byte_data(&max->i2c, MAX6690_EXTERNAL_TEMP);
58 if (data < 0)
59 return data;
60 *value = data << 16;
61 return 0;
62}
63
64static void wf_max6690_release(struct wf_sensor *sr)
65{
66 struct wf_6690_sensor *max = wf_to_6690(sr);
67
68 if (max->i2c.adapter) {
69 i2c_detach_client(&max->i2c);
70 max->i2c.adapter = NULL;
71 }
72 kfree(max);
73}
74
75static struct wf_sensor_ops wf_max6690_ops = {
76 .get_value = wf_max6690_get,
77 .release = wf_max6690_release,
78 .owner = THIS_MODULE,
79};
80
81static void wf_max6690_create(struct i2c_adapter *adapter, u8 addr)
82{
83 struct wf_6690_sensor *max;
84 char *name = "u4-temp";
85
86 max = kzalloc(sizeof(struct wf_6690_sensor), GFP_KERNEL);
87 if (max == NULL) {
88 printk(KERN_ERR "windfarm: Couldn't create MAX6690 sensor %s: "
89 "no memory\n", name);
90 return;
91 }
92
93 max->sens.ops = &wf_max6690_ops;
94 max->sens.name = name;
95 max->i2c.addr = addr >> 1;
96 max->i2c.adapter = adapter;
97 max->i2c.driver = &wf_max6690_driver;
98 strncpy(max->i2c.name, name, I2C_NAME_SIZE-1);
99
100 if (i2c_attach_client(&max->i2c)) {
101 printk(KERN_ERR "windfarm: failed to attach MAX6690 sensor\n");
102 goto fail;
103 }
104
105 if (wf_register_sensor(&max->sens)) {
106 i2c_detach_client(&max->i2c);
107 goto fail;
108 }
109
110 return;
111
112 fail:
113 kfree(max);
114}
115
116static int wf_max6690_attach(struct i2c_adapter *adapter)
117{
118 struct device_node *busnode, *dev = NULL;
119 struct pmac_i2c_bus *bus;
120 const char *loc;
121 u32 *reg;
122
123 bus = pmac_i2c_adapter_to_bus(adapter);
124 if (bus == NULL)
125 return -ENODEV;
126 busnode = pmac_i2c_get_bus_node(bus);
127
128 while ((dev = of_get_next_child(busnode, dev)) != NULL) {
129 if (!device_is_compatible(dev, "max6690"))
130 continue;
131 loc = get_property(dev, "hwsensor-location", NULL);
132 reg = (u32 *) get_property(dev, "reg", NULL);
133 if (!loc || !reg)
134 continue;
135 printk("found max6690, loc=%s reg=%x\n", loc, *reg);
136 if (strcmp(loc, "BACKSIDE"))
137 continue;
138 wf_max6690_create(adapter, *reg);
139 }
140
141 return 0;
142}
143
144static int wf_max6690_detach(struct i2c_client *client)
145{
146 struct wf_6690_sensor *max = i2c_to_6690(client);
147
148 max->i2c.adapter = NULL;
149 wf_unregister_sensor(&max->sens);
150
151 return 0;
152}
153
154static int __init wf_max6690_sensor_init(void)
155{
156 return i2c_add_driver(&wf_max6690_driver);
157}
158
159static void __exit wf_max6690_sensor_exit(void)
160{
161 i2c_del_driver(&wf_max6690_driver);
162}
163
164module_init(wf_max6690_sensor_init);
165module_exit(wf_max6690_sensor_exit);
166
167MODULE_AUTHOR("Paul Mackerras <paulus@samba.org>");
168MODULE_DESCRIPTION("MAX6690 sensor objects for PowerMac thermal control");
169MODULE_LICENSE("GPL");
diff --git a/drivers/macintosh/windfarm_pid.c b/drivers/macintosh/windfarm_pid.c
index 2e803b36875..0842432e27a 100644
--- a/drivers/macintosh/windfarm_pid.c
+++ b/drivers/macintosh/windfarm_pid.c
@@ -88,8 +88,8 @@ EXPORT_SYMBOL_GPL(wf_cpu_pid_init);
88 88
89s32 wf_cpu_pid_run(struct wf_cpu_pid_state *st, s32 new_power, s32 new_temp) 89s32 wf_cpu_pid_run(struct wf_cpu_pid_state *st, s32 new_power, s32 new_temp)
90{ 90{
91 s64 error, integ, deriv, prop; 91 s64 integ, deriv, prop;
92 s32 target, sval, adj; 92 s32 error, target, sval, adj;
93 int i, hlen = st->param.history_len; 93 int i, hlen = st->param.history_len;
94 94
95 /* Calculate error term */ 95 /* Calculate error term */
@@ -117,7 +117,7 @@ s32 wf_cpu_pid_run(struct wf_cpu_pid_state *st, s32 new_power, s32 new_temp)
117 integ += st->errors[(st->index + hlen - i) % hlen]; 117 integ += st->errors[(st->index + hlen - i) % hlen];
118 integ *= st->param.interval; 118 integ *= st->param.interval;
119 integ *= st->param.gr; 119 integ *= st->param.gr;
120 sval = st->param.tmax - ((integ >> 20) & 0xffffffff); 120 sval = st->param.tmax - (s32)(integ >> 20);
121 adj = min(st->param.ttarget, sval); 121 adj = min(st->param.ttarget, sval);
122 122
123 DBG("integ: %lx, sval: %lx, adj: %lx\n", integ, sval, adj); 123 DBG("integ: %lx, sval: %lx, adj: %lx\n", integ, sval, adj);
@@ -129,7 +129,7 @@ s32 wf_cpu_pid_run(struct wf_cpu_pid_state *st, s32 new_power, s32 new_temp)
129 deriv *= st->param.gd; 129 deriv *= st->param.gd;
130 130
131 /* Calculate proportional term */ 131 /* Calculate proportional term */
132 prop = (new_temp - adj); 132 prop = st->last_delta = (new_temp - adj);
133 prop *= st->param.gp; 133 prop *= st->param.gp;
134 134
135 DBG("deriv: %lx, prop: %lx\n", deriv, prop); 135 DBG("deriv: %lx, prop: %lx\n", deriv, prop);
diff --git a/drivers/macintosh/windfarm_pid.h b/drivers/macintosh/windfarm_pid.h
index a364c2a2499..bbccc22d42b 100644
--- a/drivers/macintosh/windfarm_pid.h
+++ b/drivers/macintosh/windfarm_pid.h
@@ -72,6 +72,7 @@ struct wf_cpu_pid_state {
72 int index; /* index of current power */ 72 int index; /* index of current power */
73 int tindex; /* index of current temp */ 73 int tindex; /* index of current temp */
74 s32 target; /* current target value */ 74 s32 target; /* current target value */
75 s32 last_delta; /* last Tactual - Ttarget */
75 s32 powers[WF_PID_MAX_HISTORY]; /* power history buffer */ 76 s32 powers[WF_PID_MAX_HISTORY]; /* power history buffer */
76 s32 errors[WF_PID_MAX_HISTORY]; /* error history buffer */ 77 s32 errors[WF_PID_MAX_HISTORY]; /* error history buffer */
77 s32 temps[2]; /* temp. history buffer */ 78 s32 temps[2]; /* temp. history buffer */
diff --git a/drivers/macintosh/windfarm_pm112.c b/drivers/macintosh/windfarm_pm112.c
new file mode 100644
index 00000000000..c2a4e689c78
--- /dev/null
+++ b/drivers/macintosh/windfarm_pm112.c
@@ -0,0 +1,698 @@
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 backside_param.min = backside_fan->ops->get_min(backside_fan);
362 backside_param.max = backside_fan->ops->get_max(backside_fan);
363 wf_pid_init(&backside_pid, &backside_param);
364 backside_tick = 1;
365 }
366 if (--backside_tick > 0)
367 return;
368 backside_tick = backside_pid.param.interval;
369
370 err = u4_temp->ops->get_value(u4_temp, &temp);
371 if (err) {
372 printk(KERN_WARNING "windfarm: U4 temp sensor error %d\n",
373 err);
374 failure_state |= FAILURE_SENSOR;
375 wf_control_set_max(backside_fan);
376 return;
377 }
378 speed = wf_pid_run(&backside_pid, temp);
379 DBG_LOTS("backside PID temp=%d.%.3d speed=%d\n",
380 FIX32TOPRINT(temp), speed);
381
382 err = backside_fan->ops->set_value(backside_fan, speed);
383 if (err) {
384 printk(KERN_WARNING "windfarm: backside fan error %d\n", err);
385 failure_state |= FAILURE_FAN;
386 }
387}
388
389/* Drive bay fan */
390static struct wf_pid_param drive_bay_prm = {
391 .interval = 5,
392 .history_len = 2,
393 .gd = 30 << 20,
394 .gp = 5 << 20,
395 .gr = 0,
396 .itarget = 40 << 16,
397 .additive = 1,
398};
399
400static void drive_bay_fan_tick(void)
401{
402 s32 temp;
403 int speed;
404 int err;
405
406 if (!drive_bay_fan || !hd_temp)
407 return;
408 if (!drive_bay_tick) {
409 /* first time; initialize things */
410 drive_bay_prm.min = drive_bay_fan->ops->get_min(drive_bay_fan);
411 drive_bay_prm.max = drive_bay_fan->ops->get_max(drive_bay_fan);
412 wf_pid_init(&drive_bay_pid, &drive_bay_prm);
413 drive_bay_tick = 1;
414 }
415 if (--drive_bay_tick > 0)
416 return;
417 drive_bay_tick = drive_bay_pid.param.interval;
418
419 err = hd_temp->ops->get_value(hd_temp, &temp);
420 if (err) {
421 printk(KERN_WARNING "windfarm: drive bay temp sensor "
422 "error %d\n", err);
423 failure_state |= FAILURE_SENSOR;
424 wf_control_set_max(drive_bay_fan);
425 return;
426 }
427 speed = wf_pid_run(&drive_bay_pid, temp);
428 DBG_LOTS("drive_bay PID temp=%d.%.3d speed=%d\n",
429 FIX32TOPRINT(temp), speed);
430
431 err = drive_bay_fan->ops->set_value(drive_bay_fan, speed);
432 if (err) {
433 printk(KERN_WARNING "windfarm: drive bay fan error %d\n", err);
434 failure_state |= FAILURE_FAN;
435 }
436}
437
438/* PCI slots area fan */
439/* This makes the fan speed proportional to the power consumed */
440static struct wf_pid_param slots_param = {
441 .interval = 1,
442 .history_len = 2,
443 .gd = 0,
444 .gp = 0,
445 .gr = 0x1277952,
446 .itarget = 0,
447 .min = 1560,
448 .max = 3510,
449};
450
451static void slots_fan_tick(void)
452{
453 s32 power;
454 int speed;
455 int err;
456
457 if (!slots_fan || !slots_power)
458 return;
459 if (!slots_started) {
460 /* first time; initialize things */
461 wf_pid_init(&slots_pid, &slots_param);
462 slots_started = 1;
463 }
464
465 err = slots_power->ops->get_value(slots_power, &power);
466 if (err) {
467 printk(KERN_WARNING "windfarm: slots power sensor error %d\n",
468 err);
469 failure_state |= FAILURE_SENSOR;
470 wf_control_set_max(slots_fan);
471 return;
472 }
473 speed = wf_pid_run(&slots_pid, power);
474 DBG_LOTS("slots PID power=%d.%.3d speed=%d\n",
475 FIX32TOPRINT(power), speed);
476
477 err = slots_fan->ops->set_value(slots_fan, speed);
478 if (err) {
479 printk(KERN_WARNING "windfarm: slots fan error %d\n", err);
480 failure_state |= FAILURE_FAN;
481 }
482}
483
484static void set_fail_state(void)
485{
486 int i;
487
488 if (cpufreq_clamp)
489 wf_control_set_max(cpufreq_clamp);
490 for (i = 0; i < NR_CPU_FANS; ++i)
491 if (cpu_fans[i])
492 wf_control_set_max(cpu_fans[i]);
493 if (backside_fan)
494 wf_control_set_max(backside_fan);
495 if (slots_fan)
496 wf_control_set_max(slots_fan);
497 if (drive_bay_fan)
498 wf_control_set_max(drive_bay_fan);
499}
500
501static void pm112_tick(void)
502{
503 int i, last_failure;
504
505 if (!started) {
506 started = 1;
507 for (i = 0; i < nr_cores; ++i) {
508 if (create_cpu_loop(i) < 0) {
509 failure_state = FAILURE_PERM;
510 set_fail_state();
511 break;
512 }
513 }
514 DBG_LOTS("cpu_all_tmax=%d.%03d\n", FIX32TOPRINT(cpu_all_tmax));
515
516#ifdef HACKED_OVERTEMP
517 cpu_all_tmax = 60 << 16;
518#endif
519 }
520
521 /* Permanent failure, bail out */
522 if (failure_state & FAILURE_PERM)
523 return;
524 /* Clear all failure bits except low overtemp which will be eventually
525 * cleared by the control loop itself
526 */
527 last_failure = failure_state;
528 failure_state &= FAILURE_LOW_OVERTEMP;
529 cpu_fans_tick();
530 backside_fan_tick();
531 slots_fan_tick();
532 drive_bay_fan_tick();
533
534 DBG_LOTS("last_failure: 0x%x, failure_state: %x\n",
535 last_failure, failure_state);
536
537 /* Check for failures. Any failure causes cpufreq clamping */
538 if (failure_state && last_failure == 0 && cpufreq_clamp)
539 wf_control_set_max(cpufreq_clamp);
540 if (failure_state == 0 && last_failure && cpufreq_clamp)
541 wf_control_set_min(cpufreq_clamp);
542
543 /* That's it for now, we might want to deal with other failures
544 * differently in the future though
545 */
546}
547
548static void pm112_new_control(struct wf_control *ct)
549{
550 int i, max_exhaust;
551
552 if (cpufreq_clamp == NULL && !strcmp(ct->name, "cpufreq-clamp")) {
553 if (wf_get_control(ct) == 0)
554 cpufreq_clamp = ct;
555 }
556
557 for (i = 0; i < NR_CPU_FANS; ++i) {
558 if (!strcmp(ct->name, cpu_fan_names[i])) {
559 if (cpu_fans[i] == NULL && wf_get_control(ct) == 0)
560 cpu_fans[i] = ct;
561 break;
562 }
563 }
564 if (i >= NR_CPU_FANS) {
565 /* not a CPU fan, try the others */
566 if (!strcmp(ct->name, "backside-fan")) {
567 if (backside_fan == NULL && wf_get_control(ct) == 0)
568 backside_fan = ct;
569 } else if (!strcmp(ct->name, "slots-fan")) {
570 if (slots_fan == NULL && wf_get_control(ct) == 0)
571 slots_fan = ct;
572 } else if (!strcmp(ct->name, "drive-bay-fan")) {
573 if (drive_bay_fan == NULL && wf_get_control(ct) == 0)
574 drive_bay_fan = ct;
575 }
576 return;
577 }
578
579 for (i = 0; i < CPU_FANS_REQD; ++i)
580 if (cpu_fans[i] == NULL)
581 return;
582
583 /* work out pump scaling factors */
584 max_exhaust = cpu_fans[0]->ops->get_max(cpu_fans[0]);
585 for (i = FIRST_PUMP; i <= LAST_PUMP; ++i)
586 if ((ct = cpu_fans[i]) != NULL)
587 cpu_fan_scale[i] =
588 ct->ops->get_max(ct) * 100 / max_exhaust;
589
590 have_all_controls = 1;
591}
592
593static void pm112_new_sensor(struct wf_sensor *sr)
594{
595 unsigned int i;
596
597 if (have_all_sensors)
598 return;
599 if (!strncmp(sr->name, "cpu-temp-", 9)) {
600 i = sr->name[9] - '0';
601 if (sr->name[10] == 0 && i < NR_CORES &&
602 sens_cpu_temp[i] == NULL && wf_get_sensor(sr) == 0)
603 sens_cpu_temp[i] = sr;
604
605 } else if (!strncmp(sr->name, "cpu-power-", 10)) {
606 i = sr->name[10] - '0';
607 if (sr->name[11] == 0 && i < NR_CORES &&
608 sens_cpu_power[i] == NULL && wf_get_sensor(sr) == 0)
609 sens_cpu_power[i] = sr;
610 } else if (!strcmp(sr->name, "hd-temp")) {
611 if (hd_temp == NULL && wf_get_sensor(sr) == 0)
612 hd_temp = sr;
613 } else if (!strcmp(sr->name, "slots-power")) {
614 if (slots_power == NULL && wf_get_sensor(sr) == 0)
615 slots_power = sr;
616 } else if (!strcmp(sr->name, "u4-temp")) {
617 if (u4_temp == NULL && wf_get_sensor(sr) == 0)
618 u4_temp = sr;
619 } else
620 return;
621
622 /* check if we have all the sensors we need */
623 for (i = 0; i < nr_cores; ++i)
624 if (sens_cpu_temp[i] == NULL || sens_cpu_power[i] == NULL)
625 return;
626
627 have_all_sensors = 1;
628}
629
630static int pm112_wf_notify(struct notifier_block *self,
631 unsigned long event, void *data)
632{
633 switch (event) {
634 case WF_EVENT_NEW_SENSOR:
635 pm112_new_sensor(data);
636 break;
637 case WF_EVENT_NEW_CONTROL:
638 pm112_new_control(data);
639 break;
640 case WF_EVENT_TICK:
641 if (have_all_controls && have_all_sensors)
642 pm112_tick();
643 }
644 return 0;
645}
646
647static struct notifier_block pm112_events = {
648 .notifier_call = pm112_wf_notify,
649};
650
651static int wf_pm112_probe(struct device *dev)
652{
653 wf_register_client(&pm112_events);
654 return 0;
655}
656
657static int wf_pm112_remove(struct device *dev)
658{
659 wf_unregister_client(&pm112_events);
660 /* should release all sensors and controls */
661 return 0;
662}
663
664static struct device_driver wf_pm112_driver = {
665 .name = "windfarm",
666 .bus = &platform_bus_type,
667 .probe = wf_pm112_probe,
668 .remove = wf_pm112_remove,
669};
670
671static int __init wf_pm112_init(void)
672{
673 struct device_node *cpu;
674
675 if (!machine_is_compatible("PowerMac11,2"))
676 return -ENODEV;
677
678 /* Count the number of CPU cores */
679 nr_cores = 0;
680 for (cpu = NULL; (cpu = of_find_node_by_type(cpu, "cpu")) != NULL; )
681 ++nr_cores;
682
683 printk(KERN_INFO "windfarm: initializing for dual-core desktop G5\n");
684 driver_register(&wf_pm112_driver);
685 return 0;
686}
687
688static void __exit wf_pm112_exit(void)
689{
690 driver_unregister(&wf_pm112_driver);
691}
692
693module_init(wf_pm112_init);
694module_exit(wf_pm112_exit);
695
696MODULE_AUTHOR("Paul Mackerras <paulus@samba.org>");
697MODULE_DESCRIPTION("Thermal control for PowerMac11,2");
698MODULE_LICENSE("GPL");
diff --git a/drivers/macintosh/windfarm_pm81.c b/drivers/macintosh/windfarm_pm81.c
index eb69a601e76..f1df6efcbe6 100644
--- a/drivers/macintosh/windfarm_pm81.c
+++ b/drivers/macintosh/windfarm_pm81.c
@@ -538,45 +538,6 @@ static void wf_smu_cpu_fans_tick(struct wf_smu_cpu_fans_state *st)
538 } 538 }
539} 539}
540 540
541
542/*
543 * ****** Attributes ******
544 *
545 */
546
547#define BUILD_SHOW_FUNC_FIX(name, data) \
548static ssize_t show_##name(struct device *dev, \
549 struct device_attribute *attr, \
550 char *buf) \
551{ \
552 ssize_t r; \
553 s32 val = 0; \
554 data->ops->get_value(data, &val); \
555 r = sprintf(buf, "%d.%03d", FIX32TOPRINT(val)); \
556 return r; \
557} \
558static DEVICE_ATTR(name,S_IRUGO,show_##name, NULL);
559
560
561#define BUILD_SHOW_FUNC_INT(name, data) \
562static ssize_t show_##name(struct device *dev, \
563 struct device_attribute *attr, \
564 char *buf) \
565{ \
566 s32 val = 0; \
567 data->ops->get_value(data, &val); \
568 return sprintf(buf, "%d", val); \
569} \
570static DEVICE_ATTR(name,S_IRUGO,show_##name, NULL);
571
572BUILD_SHOW_FUNC_INT(cpu_fan, fan_cpu_main);
573BUILD_SHOW_FUNC_INT(sys_fan, fan_system);
574BUILD_SHOW_FUNC_INT(hd_fan, fan_hd);
575
576BUILD_SHOW_FUNC_FIX(cpu_temp, sensor_cpu_temp);
577BUILD_SHOW_FUNC_FIX(cpu_power, sensor_cpu_power);
578BUILD_SHOW_FUNC_FIX(hd_temp, sensor_hd_temp);
579
580/* 541/*
581 * ****** Setup / Init / Misc ... ****** 542 * ****** Setup / Init / Misc ... ******
582 * 543 *
@@ -654,17 +615,13 @@ static void wf_smu_new_control(struct wf_control *ct)
654 return; 615 return;
655 616
656 if (fan_cpu_main == NULL && !strcmp(ct->name, "cpu-fan")) { 617 if (fan_cpu_main == NULL && !strcmp(ct->name, "cpu-fan")) {
657 if (wf_get_control(ct) == 0) { 618 if (wf_get_control(ct) == 0)
658 fan_cpu_main = ct; 619 fan_cpu_main = ct;
659 device_create_file(wf_smu_dev, &dev_attr_cpu_fan);
660 }
661 } 620 }
662 621
663 if (fan_system == NULL && !strcmp(ct->name, "system-fan")) { 622 if (fan_system == NULL && !strcmp(ct->name, "system-fan")) {
664 if (wf_get_control(ct) == 0) { 623 if (wf_get_control(ct) == 0)
665 fan_system = ct; 624 fan_system = ct;
666 device_create_file(wf_smu_dev, &dev_attr_sys_fan);
667 }
668 } 625 }
669 626
670 if (cpufreq_clamp == NULL && !strcmp(ct->name, "cpufreq-clamp")) { 627 if (cpufreq_clamp == NULL && !strcmp(ct->name, "cpufreq-clamp")) {
@@ -683,10 +640,8 @@ static void wf_smu_new_control(struct wf_control *ct)
683 } 640 }
684 641
685 if (fan_hd == NULL && !strcmp(ct->name, "drive-bay-fan")) { 642 if (fan_hd == NULL && !strcmp(ct->name, "drive-bay-fan")) {
686 if (wf_get_control(ct) == 0) { 643 if (wf_get_control(ct) == 0)
687 fan_hd = ct; 644 fan_hd = ct;
688 device_create_file(wf_smu_dev, &dev_attr_hd_fan);
689 }
690 } 645 }
691 646
692 if (fan_system && fan_hd && fan_cpu_main && cpufreq_clamp) 647 if (fan_system && fan_hd && fan_cpu_main && cpufreq_clamp)
@@ -699,24 +654,18 @@ static void wf_smu_new_sensor(struct wf_sensor *sr)
699 return; 654 return;
700 655
701 if (sensor_cpu_power == NULL && !strcmp(sr->name, "cpu-power")) { 656 if (sensor_cpu_power == NULL && !strcmp(sr->name, "cpu-power")) {
702 if (wf_get_sensor(sr) == 0) { 657 if (wf_get_sensor(sr) == 0)
703 sensor_cpu_power = sr; 658 sensor_cpu_power = sr;
704 device_create_file(wf_smu_dev, &dev_attr_cpu_power);
705 }
706 } 659 }
707 660
708 if (sensor_cpu_temp == NULL && !strcmp(sr->name, "cpu-temp")) { 661 if (sensor_cpu_temp == NULL && !strcmp(sr->name, "cpu-temp")) {
709 if (wf_get_sensor(sr) == 0) { 662 if (wf_get_sensor(sr) == 0)
710 sensor_cpu_temp = sr; 663 sensor_cpu_temp = sr;
711 device_create_file(wf_smu_dev, &dev_attr_cpu_temp);
712 }
713 } 664 }
714 665
715 if (sensor_hd_temp == NULL && !strcmp(sr->name, "hd-temp")) { 666 if (sensor_hd_temp == NULL && !strcmp(sr->name, "hd-temp")) {
716 if (wf_get_sensor(sr) == 0) { 667 if (wf_get_sensor(sr) == 0)
717 sensor_hd_temp = sr; 668 sensor_hd_temp = sr;
718 device_create_file(wf_smu_dev, &dev_attr_hd_temp);
719 }
720 } 669 }
721 670
722 if (sensor_cpu_power && sensor_cpu_temp && sensor_hd_temp) 671 if (sensor_cpu_power && sensor_cpu_temp && sensor_hd_temp)
@@ -794,32 +743,20 @@ static int wf_smu_remove(struct device *ddev)
794 * with that except by adding locks all over... I'll do that 743 * with that except by adding locks all over... I'll do that
795 * eventually but heh, who ever rmmod this module anyway ? 744 * eventually but heh, who ever rmmod this module anyway ?
796 */ 745 */
797 if (sensor_cpu_power) { 746 if (sensor_cpu_power)
798 device_remove_file(wf_smu_dev, &dev_attr_cpu_power);
799 wf_put_sensor(sensor_cpu_power); 747 wf_put_sensor(sensor_cpu_power);
800 } 748 if (sensor_cpu_temp)
801 if (sensor_cpu_temp) {
802 device_remove_file(wf_smu_dev, &dev_attr_cpu_temp);
803 wf_put_sensor(sensor_cpu_temp); 749 wf_put_sensor(sensor_cpu_temp);
804 } 750 if (sensor_hd_temp)
805 if (sensor_hd_temp) {
806 device_remove_file(wf_smu_dev, &dev_attr_hd_temp);
807 wf_put_sensor(sensor_hd_temp); 751 wf_put_sensor(sensor_hd_temp);
808 }
809 752
810 /* Release all controls */ 753 /* Release all controls */
811 if (fan_cpu_main) { 754 if (fan_cpu_main)
812 device_remove_file(wf_smu_dev, &dev_attr_cpu_fan);
813 wf_put_control(fan_cpu_main); 755 wf_put_control(fan_cpu_main);
814 } 756 if (fan_hd)
815 if (fan_hd) {
816 device_remove_file(wf_smu_dev, &dev_attr_hd_fan);
817 wf_put_control(fan_hd); 757 wf_put_control(fan_hd);
818 } 758 if (fan_system)
819 if (fan_system) {
820 device_remove_file(wf_smu_dev, &dev_attr_sys_fan);
821 wf_put_control(fan_system); 759 wf_put_control(fan_system);
822 }
823 if (cpufreq_clamp) 760 if (cpufreq_clamp)
824 wf_put_control(cpufreq_clamp); 761 wf_put_control(cpufreq_clamp);
825 762
diff --git a/drivers/macintosh/windfarm_pm91.c b/drivers/macintosh/windfarm_pm91.c
index 43243cf7410..0d6372e96d3 100644
--- a/drivers/macintosh/windfarm_pm91.c
+++ b/drivers/macintosh/windfarm_pm91.c
@@ -458,45 +458,6 @@ static void wf_smu_slots_fans_tick(struct wf_smu_slots_fans_state *st)
458 458
459 459
460/* 460/*
461 * ****** Attributes ******
462 *
463 */
464
465#define BUILD_SHOW_FUNC_FIX(name, data) \
466static ssize_t show_##name(struct device *dev, \
467 struct device_attribute *attr, \
468 char *buf) \
469{ \
470 ssize_t r; \
471 s32 val = 0; \
472 data->ops->get_value(data, &val); \
473 r = sprintf(buf, "%d.%03d", FIX32TOPRINT(val)); \
474 return r; \
475} \
476static DEVICE_ATTR(name,S_IRUGO,show_##name, NULL);
477
478
479#define BUILD_SHOW_FUNC_INT(name, data) \
480static ssize_t show_##name(struct device *dev, \
481 struct device_attribute *attr, \
482 char *buf) \
483{ \
484 s32 val = 0; \
485 data->ops->get_value(data, &val); \
486 return sprintf(buf, "%d", val); \
487} \
488static DEVICE_ATTR(name,S_IRUGO,show_##name, NULL);
489
490BUILD_SHOW_FUNC_INT(cpu_fan, fan_cpu_main);
491BUILD_SHOW_FUNC_INT(hd_fan, fan_hd);
492BUILD_SHOW_FUNC_INT(slots_fan, fan_slots);
493
494BUILD_SHOW_FUNC_FIX(cpu_temp, sensor_cpu_temp);
495BUILD_SHOW_FUNC_FIX(cpu_power, sensor_cpu_power);
496BUILD_SHOW_FUNC_FIX(hd_temp, sensor_hd_temp);
497BUILD_SHOW_FUNC_FIX(slots_power, sensor_slots_power);
498
499/*
500 * ****** Setup / Init / Misc ... ****** 461 * ****** Setup / Init / Misc ... ******
501 * 462 *
502 */ 463 */
@@ -581,10 +542,8 @@ static void wf_smu_new_control(struct wf_control *ct)
581 return; 542 return;
582 543
583 if (fan_cpu_main == NULL && !strcmp(ct->name, "cpu-rear-fan-0")) { 544 if (fan_cpu_main == NULL && !strcmp(ct->name, "cpu-rear-fan-0")) {
584 if (wf_get_control(ct) == 0) { 545 if (wf_get_control(ct) == 0)
585 fan_cpu_main = ct; 546 fan_cpu_main = ct;
586 device_create_file(wf_smu_dev, &dev_attr_cpu_fan);
587 }
588 } 547 }
589 548
590 if (fan_cpu_second == NULL && !strcmp(ct->name, "cpu-rear-fan-1")) { 549 if (fan_cpu_second == NULL && !strcmp(ct->name, "cpu-rear-fan-1")) {
@@ -603,17 +562,13 @@ static void wf_smu_new_control(struct wf_control *ct)
603 } 562 }
604 563
605 if (fan_hd == NULL && !strcmp(ct->name, "drive-bay-fan")) { 564 if (fan_hd == NULL && !strcmp(ct->name, "drive-bay-fan")) {
606 if (wf_get_control(ct) == 0) { 565 if (wf_get_control(ct) == 0)
607 fan_hd = ct; 566 fan_hd = ct;
608 device_create_file(wf_smu_dev, &dev_attr_hd_fan);
609 }
610 } 567 }
611 568
612 if (fan_slots == NULL && !strcmp(ct->name, "slots-fan")) { 569 if (fan_slots == NULL && !strcmp(ct->name, "slots-fan")) {
613 if (wf_get_control(ct) == 0) { 570 if (wf_get_control(ct) == 0)
614 fan_slots = ct; 571 fan_slots = ct;
615 device_create_file(wf_smu_dev, &dev_attr_slots_fan);
616 }
617 } 572 }
618 573
619 if (fan_cpu_main && (fan_cpu_second || fan_cpu_third) && fan_hd && 574 if (fan_cpu_main && (fan_cpu_second || fan_cpu_third) && fan_hd &&
@@ -627,31 +582,23 @@ static void wf_smu_new_sensor(struct wf_sensor *sr)
627 return; 582 return;
628 583
629 if (sensor_cpu_power == NULL && !strcmp(sr->name, "cpu-power")) { 584 if (sensor_cpu_power == NULL && !strcmp(sr->name, "cpu-power")) {
630 if (wf_get_sensor(sr) == 0) { 585 if (wf_get_sensor(sr) == 0)
631 sensor_cpu_power = sr; 586 sensor_cpu_power = sr;
632 device_create_file(wf_smu_dev, &dev_attr_cpu_power);
633 }
634 } 587 }
635 588
636 if (sensor_cpu_temp == NULL && !strcmp(sr->name, "cpu-temp")) { 589 if (sensor_cpu_temp == NULL && !strcmp(sr->name, "cpu-temp")) {
637 if (wf_get_sensor(sr) == 0) { 590 if (wf_get_sensor(sr) == 0)
638 sensor_cpu_temp = sr; 591 sensor_cpu_temp = sr;
639 device_create_file(wf_smu_dev, &dev_attr_cpu_temp);
640 }
641 } 592 }
642 593
643 if (sensor_hd_temp == NULL && !strcmp(sr->name, "hd-temp")) { 594 if (sensor_hd_temp == NULL && !strcmp(sr->name, "hd-temp")) {
644 if (wf_get_sensor(sr) == 0) { 595 if (wf_get_sensor(sr) == 0)
645 sensor_hd_temp = sr; 596 sensor_hd_temp = sr;
646 device_create_file(wf_smu_dev, &dev_attr_hd_temp);
647 }
648 } 597 }
649 598
650 if (sensor_slots_power == NULL && !strcmp(sr->name, "slots-power")) { 599 if (sensor_slots_power == NULL && !strcmp(sr->name, "slots-power")) {
651 if (wf_get_sensor(sr) == 0) { 600 if (wf_get_sensor(sr) == 0)
652 sensor_slots_power = sr; 601 sensor_slots_power = sr;
653 device_create_file(wf_smu_dev, &dev_attr_slots_power);
654 }
655 } 602 }
656 603
657 if (sensor_cpu_power && sensor_cpu_temp && 604 if (sensor_cpu_power && sensor_cpu_temp &&
@@ -720,40 +667,26 @@ static int wf_smu_remove(struct device *ddev)
720 * with that except by adding locks all over... I'll do that 667 * with that except by adding locks all over... I'll do that
721 * eventually but heh, who ever rmmod this module anyway ? 668 * eventually but heh, who ever rmmod this module anyway ?
722 */ 669 */
723 if (sensor_cpu_power) { 670 if (sensor_cpu_power)
724 device_remove_file(wf_smu_dev, &dev_attr_cpu_power);
725 wf_put_sensor(sensor_cpu_power); 671 wf_put_sensor(sensor_cpu_power);
726 } 672 if (sensor_cpu_temp)
727 if (sensor_cpu_temp) {
728 device_remove_file(wf_smu_dev, &dev_attr_cpu_temp);
729 wf_put_sensor(sensor_cpu_temp); 673 wf_put_sensor(sensor_cpu_temp);
730 } 674 if (sensor_hd_temp)
731 if (sensor_hd_temp) {
732 device_remove_file(wf_smu_dev, &dev_attr_hd_temp);
733 wf_put_sensor(sensor_hd_temp); 675 wf_put_sensor(sensor_hd_temp);
734 } 676 if (sensor_slots_power)
735 if (sensor_slots_power) {
736 device_remove_file(wf_smu_dev, &dev_attr_slots_power);
737 wf_put_sensor(sensor_slots_power); 677 wf_put_sensor(sensor_slots_power);
738 }
739 678
740 /* Release all controls */ 679 /* Release all controls */
741 if (fan_cpu_main) { 680 if (fan_cpu_main)
742 device_remove_file(wf_smu_dev, &dev_attr_cpu_fan);
743 wf_put_control(fan_cpu_main); 681 wf_put_control(fan_cpu_main);
744 }
745 if (fan_cpu_second) 682 if (fan_cpu_second)
746 wf_put_control(fan_cpu_second); 683 wf_put_control(fan_cpu_second);
747 if (fan_cpu_third) 684 if (fan_cpu_third)
748 wf_put_control(fan_cpu_third); 685 wf_put_control(fan_cpu_third);
749 if (fan_hd) { 686 if (fan_hd)
750 device_remove_file(wf_smu_dev, &dev_attr_hd_fan);
751 wf_put_control(fan_hd); 687 wf_put_control(fan_hd);
752 } 688 if (fan_slots)
753 if (fan_slots) {
754 device_remove_file(wf_smu_dev, &dev_attr_slots_fan);
755 wf_put_control(fan_slots); 689 wf_put_control(fan_slots);
756 }
757 if (cpufreq_clamp) 690 if (cpufreq_clamp)
758 wf_put_control(cpufreq_clamp); 691 wf_put_control(cpufreq_clamp);
759 692
diff --git a/drivers/macintosh/windfarm_smu_controls.c b/drivers/macintosh/windfarm_smu_controls.c
index 4d811600bda..a9e88edc0c7 100644
--- a/drivers/macintosh/windfarm_smu_controls.c
+++ b/drivers/macintosh/windfarm_smu_controls.c
@@ -24,7 +24,7 @@
24 24
25#include "windfarm.h" 25#include "windfarm.h"
26 26
27#define VERSION "0.3" 27#define VERSION "0.4"
28 28
29#undef DEBUG 29#undef DEBUG
30 30
@@ -34,6 +34,8 @@
34#define DBG(args...) do { } while(0) 34#define DBG(args...) do { } while(0)
35#endif 35#endif
36 36
37static int smu_supports_new_fans_ops = 1;
38
37/* 39/*
38 * SMU fans control object 40 * SMU fans control object
39 */ 41 */
@@ -59,23 +61,49 @@ static int smu_set_fan(int pwm, u8 id, u16 value)
59 61
60 /* Fill SMU command structure */ 62 /* Fill SMU command structure */
61 cmd.cmd = SMU_CMD_FAN_COMMAND; 63 cmd.cmd = SMU_CMD_FAN_COMMAND;
62 cmd.data_len = 14; 64
65 /* The SMU has an "old" and a "new" way of setting the fan speed
66 * Unfortunately, I found no reliable way to know which one works
67 * on a given machine model. After some investigations it appears
68 * that MacOS X just tries the new one, and if it fails fallbacks
69 * to the old ones ... Ugh.
70 */
71 retry:
72 if (smu_supports_new_fans_ops) {
73 buffer[0] = 0x30;
74 buffer[1] = id;
75 *((u16 *)(&buffer[2])) = value;
76 cmd.data_len = 4;
77 } else {
78 if (id > 7)
79 return -EINVAL;
80 /* Fill argument buffer */
81 memset(buffer, 0, 16);
82 buffer[0] = pwm ? 0x10 : 0x00;
83 buffer[1] = 0x01 << id;
84 *((u16 *)&buffer[2 + id * 2]) = value;
85 cmd.data_len = 14;
86 }
87
63 cmd.reply_len = 16; 88 cmd.reply_len = 16;
64 cmd.data_buf = cmd.reply_buf = buffer; 89 cmd.data_buf = cmd.reply_buf = buffer;
65 cmd.status = 0; 90 cmd.status = 0;
66 cmd.done = smu_done_complete; 91 cmd.done = smu_done_complete;
67 cmd.misc = &comp; 92 cmd.misc = &comp;
68 93
69 /* Fill argument buffer */
70 memset(buffer, 0, 16);
71 buffer[0] = pwm ? 0x10 : 0x00;
72 buffer[1] = 0x01 << id;
73 *((u16 *)&buffer[2 + id * 2]) = value;
74
75 rc = smu_queue_cmd(&cmd); 94 rc = smu_queue_cmd(&cmd);
76 if (rc) 95 if (rc)
77 return rc; 96 return rc;
78 wait_for_completion(&comp); 97 wait_for_completion(&comp);
98
99 /* Handle fallback (see coment above) */
100 if (cmd.status != 0 && smu_supports_new_fans_ops) {
101 printk(KERN_WARNING "windfarm: SMU failed new fan command "
102 "falling back to old method\n");
103 smu_supports_new_fans_ops = 0;
104 goto retry;
105 }
106
79 return cmd.status; 107 return cmd.status;
80} 108}
81 109
@@ -158,19 +186,29 @@ static struct smu_fan_control *smu_fan_create(struct device_node *node,
158 186
159 /* Names used on desktop models */ 187 /* Names used on desktop models */
160 if (!strcmp(l, "Rear Fan 0") || !strcmp(l, "Rear Fan") || 188 if (!strcmp(l, "Rear Fan 0") || !strcmp(l, "Rear Fan") ||
161 !strcmp(l, "Rear fan 0") || !strcmp(l, "Rear fan")) 189 !strcmp(l, "Rear fan 0") || !strcmp(l, "Rear fan") ||
190 !strcmp(l, "CPU A EXHAUST"))
162 fct->ctrl.name = "cpu-rear-fan-0"; 191 fct->ctrl.name = "cpu-rear-fan-0";
163 else if (!strcmp(l, "Rear Fan 1") || !strcmp(l, "Rear fan 1")) 192 else if (!strcmp(l, "Rear Fan 1") || !strcmp(l, "Rear fan 1") ||
193 !strcmp(l, "CPU B EXHAUST"))
164 fct->ctrl.name = "cpu-rear-fan-1"; 194 fct->ctrl.name = "cpu-rear-fan-1";
165 else if (!strcmp(l, "Front Fan 0") || !strcmp(l, "Front Fan") || 195 else if (!strcmp(l, "Front Fan 0") || !strcmp(l, "Front Fan") ||
166 !strcmp(l, "Front fan 0") || !strcmp(l, "Front fan")) 196 !strcmp(l, "Front fan 0") || !strcmp(l, "Front fan") ||
197 !strcmp(l, "CPU A INTAKE"))
167 fct->ctrl.name = "cpu-front-fan-0"; 198 fct->ctrl.name = "cpu-front-fan-0";
168 else if (!strcmp(l, "Front Fan 1") || !strcmp(l, "Front fan 1")) 199 else if (!strcmp(l, "Front Fan 1") || !strcmp(l, "Front fan 1") ||
200 !strcmp(l, "CPU B INTAKE"))
169 fct->ctrl.name = "cpu-front-fan-1"; 201 fct->ctrl.name = "cpu-front-fan-1";
170 else if (!strcmp(l, "Slots Fan") || !strcmp(l, "Slots fan")) 202 else if (!strcmp(l, "CPU A PUMP"))
203 fct->ctrl.name = "cpu-pump-0";
204 else if (!strcmp(l, "Slots Fan") || !strcmp(l, "Slots fan") ||
205 !strcmp(l, "EXPANSION SLOTS INTAKE"))
171 fct->ctrl.name = "slots-fan"; 206 fct->ctrl.name = "slots-fan";
172 else if (!strcmp(l, "Drive Bay") || !strcmp(l, "Drive bay")) 207 else if (!strcmp(l, "Drive Bay") || !strcmp(l, "Drive bay") ||
208 !strcmp(l, "DRIVE BAY A INTAKE"))
173 fct->ctrl.name = "drive-bay-fan"; 209 fct->ctrl.name = "drive-bay-fan";
210 else if (!strcmp(l, "BACKSIDE"))
211 fct->ctrl.name = "backside-fan";
174 212
175 /* Names used on iMac models */ 213 /* Names used on iMac models */
176 if (!strcmp(l, "System Fan") || !strcmp(l, "System fan")) 214 if (!strcmp(l, "System Fan") || !strcmp(l, "System fan"))
@@ -223,7 +261,8 @@ static int __init smu_controls_init(void)
223 261
224 /* Look for RPM fans */ 262 /* Look for RPM fans */
225 for (fans = NULL; (fans = of_get_next_child(smu, fans)) != NULL;) 263 for (fans = NULL; (fans = of_get_next_child(smu, fans)) != NULL;)
226 if (!strcmp(fans->name, "rpm-fans")) 264 if (!strcmp(fans->name, "rpm-fans") ||
265 device_is_compatible(fans, "smu-rpm-fans"))
227 break; 266 break;
228 for (fan = NULL; 267 for (fan = NULL;
229 fans && (fan = of_get_next_child(fans, fan)) != NULL;) { 268 fans && (fan = of_get_next_child(fans, fan)) != NULL;) {
diff --git a/drivers/macintosh/windfarm_smu_sat.c b/drivers/macintosh/windfarm_smu_sat.c
new file mode 100644
index 00000000000..3a32c59494f
--- /dev/null
+++ b/drivers/macintosh/windfarm_smu_sat.c
@@ -0,0 +1,418 @@
1/*
2 * Windfarm PowerMac thermal control. SMU "satellite" controller sensors.
3 *
4 * Copyright (C) 2005 Paul Mackerras, IBM Corp. <paulus@samba.org>
5 *
6 * Released under the terms of the GNU GPL v2.
7 */
8
9#include <linux/types.h>
10#include <linux/errno.h>
11#include <linux/kernel.h>
12#include <linux/slab.h>
13#include <linux/init.h>
14#include <linux/wait.h>
15#include <linux/i2c.h>
16#include <linux/i2c-dev.h>
17#include <asm/semaphore.h>
18#include <asm/prom.h>
19#include <asm/smu.h>
20#include <asm/pmac_low_i2c.h>
21
22#include "windfarm.h"
23
24#define VERSION "0.2"
25
26#define DEBUG
27
28#ifdef DEBUG
29#define DBG(args...) printk(args)
30#else
31#define DBG(args...) do { } while(0)
32#endif
33
34/* If the cache is older than 800ms we'll refetch it */
35#define MAX_AGE msecs_to_jiffies(800)
36
37struct wf_sat {
38 int nr;
39 atomic_t refcnt;
40 struct semaphore mutex;
41 unsigned long last_read; /* jiffies when cache last updated */
42 u8 cache[16];
43 struct i2c_client i2c;
44 struct device_node *node;
45};
46
47static struct wf_sat *sats[2];
48
49struct wf_sat_sensor {
50 int index;
51 int index2; /* used for power sensors */
52 int shift;
53 struct wf_sat *sat;
54 struct wf_sensor sens;
55};
56
57#define wf_to_sat(c) container_of(c, struct wf_sat_sensor, sens)
58#define i2c_to_sat(c) container_of(c, struct wf_sat, i2c)
59
60static int wf_sat_attach(struct i2c_adapter *adapter);
61static int wf_sat_detach(struct i2c_client *client);
62
63static struct i2c_driver wf_sat_driver = {
64 .driver = {
65 .name = "wf_smu_sat",
66 },
67 .attach_adapter = wf_sat_attach,
68 .detach_client = wf_sat_detach,
69};
70
71/*
72 * XXX i2c_smbus_read_i2c_block_data doesn't pass the requested
73 * length down to the low-level driver, so we use this, which
74 * works well enough with the SMU i2c driver code...
75 */
76static int sat_read_block(struct i2c_client *client, u8 command,
77 u8 *values, int len)
78{
79 union i2c_smbus_data data;
80 int err;
81
82 data.block[0] = len;
83 err = i2c_smbus_xfer(client->adapter, client->addr, client->flags,
84 I2C_SMBUS_READ, command, I2C_SMBUS_I2C_BLOCK_DATA,
85 &data);
86 if (!err)
87 memcpy(values, data.block, len);
88 return err;
89}
90
91struct smu_sdbp_header *smu_sat_get_sdb_partition(unsigned int sat_id, int id,
92 unsigned int *size)
93{
94 struct wf_sat *sat;
95 int err;
96 unsigned int i, len;
97 u8 *buf;
98 u8 data[4];
99
100 /* TODO: Add the resulting partition to the device-tree */
101
102 if (sat_id > 1 || (sat = sats[sat_id]) == NULL)
103 return NULL;
104
105 err = i2c_smbus_write_word_data(&sat->i2c, 8, id << 8);
106 if (err) {
107 printk(KERN_ERR "smu_sat_get_sdb_part wr error %d\n", err);
108 return NULL;
109 }
110
111 len = i2c_smbus_read_word_data(&sat->i2c, 9);
112 if (len < 0) {
113 printk(KERN_ERR "smu_sat_get_sdb_part rd len error\n");
114 return NULL;
115 }
116 if (len == 0) {
117 printk(KERN_ERR "smu_sat_get_sdb_part no partition %x\n", id);
118 return NULL;
119 }
120
121 len = le16_to_cpu(len);
122 len = (len + 3) & ~3;
123 buf = kmalloc(len, GFP_KERNEL);
124 if (buf == NULL)
125 return NULL;
126
127 for (i = 0; i < len; i += 4) {
128 err = sat_read_block(&sat->i2c, 0xa, data, 4);
129 if (err) {
130 printk(KERN_ERR "smu_sat_get_sdb_part rd err %d\n",
131 err);
132 goto fail;
133 }
134 buf[i] = data[1];
135 buf[i+1] = data[0];
136 buf[i+2] = data[3];
137 buf[i+3] = data[2];
138 }
139#ifdef DEBUG
140 DBG(KERN_DEBUG "sat %d partition %x:", sat_id, id);
141 for (i = 0; i < len; ++i)
142 DBG(" %x", buf[i]);
143 DBG("\n");
144#endif
145
146 if (size)
147 *size = len;
148 return (struct smu_sdbp_header *) buf;
149
150 fail:
151 kfree(buf);
152 return NULL;
153}
154
155/* refresh the cache */
156static int wf_sat_read_cache(struct wf_sat *sat)
157{
158 int err;
159
160 err = sat_read_block(&sat->i2c, 0x3f, sat->cache, 16);
161 if (err)
162 return err;
163 sat->last_read = jiffies;
164#ifdef LOTSA_DEBUG
165 {
166 int i;
167 DBG(KERN_DEBUG "wf_sat_get: data is");
168 for (i = 0; i < 16; ++i)
169 DBG(" %.2x", sat->cache[i]);
170 DBG("\n");
171 }
172#endif
173 return 0;
174}
175
176static int wf_sat_get(struct wf_sensor *sr, s32 *value)
177{
178 struct wf_sat_sensor *sens = wf_to_sat(sr);
179 struct wf_sat *sat = sens->sat;
180 int i, err;
181 s32 val;
182
183 if (sat->i2c.adapter == NULL)
184 return -ENODEV;
185
186 down(&sat->mutex);
187 if (time_after(jiffies, (sat->last_read + MAX_AGE))) {
188 err = wf_sat_read_cache(sat);
189 if (err)
190 goto fail;
191 }
192
193 i = sens->index * 2;
194 val = ((sat->cache[i] << 8) + sat->cache[i+1]) << sens->shift;
195 if (sens->index2 >= 0) {
196 i = sens->index2 * 2;
197 /* 4.12 * 8.8 -> 12.20; shift right 4 to get 16.16 */
198 val = (val * ((sat->cache[i] << 8) + sat->cache[i+1])) >> 4;
199 }
200
201 *value = val;
202 err = 0;
203
204 fail:
205 up(&sat->mutex);
206 return err;
207}
208
209static void wf_sat_release(struct wf_sensor *sr)
210{
211 struct wf_sat_sensor *sens = wf_to_sat(sr);
212 struct wf_sat *sat = sens->sat;
213
214 if (atomic_dec_and_test(&sat->refcnt)) {
215 if (sat->i2c.adapter) {
216 i2c_detach_client(&sat->i2c);
217 sat->i2c.adapter = NULL;
218 }
219 if (sat->nr >= 0)
220 sats[sat->nr] = NULL;
221 kfree(sat);
222 }
223 kfree(sens);
224}
225
226static struct wf_sensor_ops wf_sat_ops = {
227 .get_value = wf_sat_get,
228 .release = wf_sat_release,
229 .owner = THIS_MODULE,
230};
231
232static void wf_sat_create(struct i2c_adapter *adapter, struct device_node *dev)
233{
234 struct wf_sat *sat;
235 struct wf_sat_sensor *sens;
236 u32 *reg;
237 char *loc, *type;
238 u8 addr, chip, core;
239 struct device_node *child;
240 int shift, cpu, index;
241 char *name;
242 int vsens[2], isens[2];
243
244 reg = (u32 *) get_property(dev, "reg", NULL);
245 if (reg == NULL)
246 return;
247 addr = *reg;
248 DBG(KERN_DEBUG "wf_sat: creating sat at address %x\n", addr);
249
250 sat = kzalloc(sizeof(struct wf_sat), GFP_KERNEL);
251 if (sat == NULL)
252 return;
253 sat->nr = -1;
254 sat->node = of_node_get(dev);
255 atomic_set(&sat->refcnt, 0);
256 init_MUTEX(&sat->mutex);
257 sat->i2c.addr = (addr >> 1) & 0x7f;
258 sat->i2c.adapter = adapter;
259 sat->i2c.driver = &wf_sat_driver;
260 strncpy(sat->i2c.name, "smu-sat", I2C_NAME_SIZE-1);
261
262 if (i2c_attach_client(&sat->i2c)) {
263 printk(KERN_ERR "windfarm: failed to attach smu-sat to i2c\n");
264 goto fail;
265 }
266
267 vsens[0] = vsens[1] = -1;
268 isens[0] = isens[1] = -1;
269 child = NULL;
270 while ((child = of_get_next_child(dev, child)) != NULL) {
271 reg = (u32 *) get_property(child, "reg", NULL);
272 type = get_property(child, "device_type", NULL);
273 loc = get_property(child, "location", NULL);
274 if (reg == NULL || loc == NULL)
275 continue;
276
277 /* the cooked sensors are between 0x30 and 0x37 */
278 if (*reg < 0x30 || *reg > 0x37)
279 continue;
280 index = *reg - 0x30;
281
282 /* expect location to be CPU [AB][01] ... */
283 if (strncmp(loc, "CPU ", 4) != 0)
284 continue;
285 chip = loc[4] - 'A';
286 core = loc[5] - '0';
287 if (chip > 1 || core > 1) {
288 printk(KERN_ERR "wf_sat_create: don't understand "
289 "location %s for %s\n", loc, child->full_name);
290 continue;
291 }
292 cpu = 2 * chip + core;
293 if (sat->nr < 0)
294 sat->nr = chip;
295 else if (sat->nr != chip) {
296 printk(KERN_ERR "wf_sat_create: can't cope with "
297 "multiple CPU chips on one SAT (%s)\n", loc);
298 continue;
299 }
300
301 if (strcmp(type, "voltage-sensor") == 0) {
302 name = "cpu-voltage";
303 shift = 4;
304 vsens[core] = index;
305 } else if (strcmp(type, "current-sensor") == 0) {
306 name = "cpu-current";
307 shift = 8;
308 isens[core] = index;
309 } else if (strcmp(type, "temp-sensor") == 0) {
310 name = "cpu-temp";
311 shift = 10;
312 } else
313 continue; /* hmmm shouldn't happen */
314
315 /* the +16 is enough for "cpu-voltage-n" */
316 sens = kzalloc(sizeof(struct wf_sat_sensor) + 16, GFP_KERNEL);
317 if (sens == NULL) {
318 printk(KERN_ERR "wf_sat_create: couldn't create "
319 "%s sensor %d (no memory)\n", name, cpu);
320 continue;
321 }
322 sens->index = index;
323 sens->index2 = -1;
324 sens->shift = shift;
325 sens->sat = sat;
326 atomic_inc(&sat->refcnt);
327 sens->sens.ops = &wf_sat_ops;
328 sens->sens.name = (char *) (sens + 1);
329 snprintf(sens->sens.name, 16, "%s-%d", name, cpu);
330
331 if (wf_register_sensor(&sens->sens)) {
332 atomic_dec(&sat->refcnt);
333 kfree(sens);
334 }
335 }
336
337 /* make the power sensors */
338 for (core = 0; core < 2; ++core) {
339 if (vsens[core] < 0 || isens[core] < 0)
340 continue;
341 cpu = 2 * sat->nr + core;
342 sens = kzalloc(sizeof(struct wf_sat_sensor) + 16, GFP_KERNEL);
343 if (sens == NULL) {
344 printk(KERN_ERR "wf_sat_create: couldn't create power "
345 "sensor %d (no memory)\n", cpu);
346 continue;
347 }
348 sens->index = vsens[core];
349 sens->index2 = isens[core];
350 sens->shift = 0;
351 sens->sat = sat;
352 atomic_inc(&sat->refcnt);
353 sens->sens.ops = &wf_sat_ops;
354 sens->sens.name = (char *) (sens + 1);
355 snprintf(sens->sens.name, 16, "cpu-power-%d", cpu);
356
357 if (wf_register_sensor(&sens->sens)) {
358 atomic_dec(&sat->refcnt);
359 kfree(sens);
360 }
361 }
362
363 if (sat->nr >= 0)
364 sats[sat->nr] = sat;
365
366 return;
367
368 fail:
369 kfree(sat);
370}
371
372static int wf_sat_attach(struct i2c_adapter *adapter)
373{
374 struct device_node *busnode, *dev = NULL;
375 struct pmac_i2c_bus *bus;
376
377 bus = pmac_i2c_adapter_to_bus(adapter);
378 if (bus == NULL)
379 return -ENODEV;
380 busnode = pmac_i2c_get_bus_node(bus);
381
382 while ((dev = of_get_next_child(busnode, dev)) != NULL)
383 if (device_is_compatible(dev, "smu-sat"))
384 wf_sat_create(adapter, dev);
385 return 0;
386}
387
388static int wf_sat_detach(struct i2c_client *client)
389{
390 struct wf_sat *sat = i2c_to_sat(client);
391
392 /* XXX TODO */
393
394 sat->i2c.adapter = NULL;
395 return 0;
396}
397
398static int __init sat_sensors_init(void)
399{
400 int err;
401
402 err = i2c_add_driver(&wf_sat_driver);
403 if (err < 0)
404 return err;
405 return 0;
406}
407
408static void __exit sat_sensors_exit(void)
409{
410 i2c_del_driver(&wf_sat_driver);
411}
412
413module_init(sat_sensors_init);
414/*module_exit(sat_sensors_exit); Uncomment when cleanup is implemented */
415
416MODULE_AUTHOR("Paul Mackerras <paulus@samba.org>");
417MODULE_DESCRIPTION("SMU satellite sensors for PowerMac thermal control");
418MODULE_LICENSE("GPL");
diff --git a/drivers/macintosh/windfarm_smu_sensors.c b/drivers/macintosh/windfarm_smu_sensors.c
index 1a00d9c75a2..bed25dcf8a1 100644
--- a/drivers/macintosh/windfarm_smu_sensors.c
+++ b/drivers/macintosh/windfarm_smu_sensors.c
@@ -220,14 +220,29 @@ static struct smu_ad_sensor *smu_ads_create(struct device_node *node)
220 !strcmp(l, "CPU T-Diode")) { 220 !strcmp(l, "CPU T-Diode")) {
221 ads->sens.ops = &smu_cputemp_ops; 221 ads->sens.ops = &smu_cputemp_ops;
222 ads->sens.name = "cpu-temp"; 222 ads->sens.name = "cpu-temp";
223 if (cpudiode == NULL) {
224 DBG("wf: cpudiode partition (%02x) not found\n",
225 SMU_SDB_CPUDIODE_ID);
226 goto fail;
227 }
223 } else if (!strcmp(c, "current-sensor") && 228 } else if (!strcmp(c, "current-sensor") &&
224 !strcmp(l, "CPU Current")) { 229 !strcmp(l, "CPU Current")) {
225 ads->sens.ops = &smu_cpuamp_ops; 230 ads->sens.ops = &smu_cpuamp_ops;
226 ads->sens.name = "cpu-current"; 231 ads->sens.name = "cpu-current";
232 if (cpuvcp == NULL) {
233 DBG("wf: cpuvcp partition (%02x) not found\n",
234 SMU_SDB_CPUVCP_ID);
235 goto fail;
236 }
227 } else if (!strcmp(c, "voltage-sensor") && 237 } else if (!strcmp(c, "voltage-sensor") &&
228 !strcmp(l, "CPU Voltage")) { 238 !strcmp(l, "CPU Voltage")) {
229 ads->sens.ops = &smu_cpuvolt_ops; 239 ads->sens.ops = &smu_cpuvolt_ops;
230 ads->sens.name = "cpu-voltage"; 240 ads->sens.name = "cpu-voltage";
241 if (cpuvcp == NULL) {
242 DBG("wf: cpuvcp partition (%02x) not found\n",
243 SMU_SDB_CPUVCP_ID);
244 goto fail;
245 }
231 } else if (!strcmp(c, "power-sensor") && 246 } else if (!strcmp(c, "power-sensor") &&
232 !strcmp(l, "Slots Power")) { 247 !strcmp(l, "Slots Power")) {
233 ads->sens.ops = &smu_slotspow_ops; 248 ads->sens.ops = &smu_slotspow_ops;
@@ -365,29 +380,22 @@ smu_cpu_power_create(struct wf_sensor *volts, struct wf_sensor *amps)
365 return NULL; 380 return NULL;
366} 381}
367 382
368static int smu_fetch_param_partitions(void) 383static void smu_fetch_param_partitions(void)
369{ 384{
370 struct smu_sdbp_header *hdr; 385 struct smu_sdbp_header *hdr;
371 386
372 /* Get CPU voltage/current/power calibration data */ 387 /* Get CPU voltage/current/power calibration data */
373 hdr = smu_get_sdb_partition(SMU_SDB_CPUVCP_ID, NULL); 388 hdr = smu_get_sdb_partition(SMU_SDB_CPUVCP_ID, NULL);
374 if (hdr == NULL) { 389 if (hdr != NULL) {
375 DBG("wf: cpuvcp partition (%02x) not found\n", 390 cpuvcp = (struct smu_sdbp_cpuvcp *)&hdr[1];
376 SMU_SDB_CPUVCP_ID); 391 /* Keep version around */
377 return -ENODEV; 392 cpuvcp_version = hdr->version;
378 } 393 }
379 cpuvcp = (struct smu_sdbp_cpuvcp *)&hdr[1];
380 /* Keep version around */
381 cpuvcp_version = hdr->version;
382 394
383 /* Get CPU diode calibration data */ 395 /* Get CPU diode calibration data */
384 hdr = smu_get_sdb_partition(SMU_SDB_CPUDIODE_ID, NULL); 396 hdr = smu_get_sdb_partition(SMU_SDB_CPUDIODE_ID, NULL);
385 if (hdr == NULL) { 397 if (hdr != NULL)
386 DBG("wf: cpudiode partition (%02x) not found\n", 398 cpudiode = (struct smu_sdbp_cpudiode *)&hdr[1];
387 SMU_SDB_CPUDIODE_ID);
388 return -ENODEV;
389 }
390 cpudiode = (struct smu_sdbp_cpudiode *)&hdr[1];
391 399
392 /* Get slots power calibration data if any */ 400 /* Get slots power calibration data if any */
393 hdr = smu_get_sdb_partition(SMU_SDB_SLOTSPOW_ID, NULL); 401 hdr = smu_get_sdb_partition(SMU_SDB_SLOTSPOW_ID, NULL);
@@ -398,23 +406,18 @@ static int smu_fetch_param_partitions(void)
398 hdr = smu_get_sdb_partition(SMU_SDB_DEBUG_SWITCHES_ID, NULL); 406 hdr = smu_get_sdb_partition(SMU_SDB_DEBUG_SWITCHES_ID, NULL);
399 if (hdr != NULL) 407 if (hdr != NULL)
400 debugswitches = (u8 *)&hdr[1]; 408 debugswitches = (u8 *)&hdr[1];
401
402 return 0;
403} 409}
404 410
405static int __init smu_sensors_init(void) 411static int __init smu_sensors_init(void)
406{ 412{
407 struct device_node *smu, *sensors, *s; 413 struct device_node *smu, *sensors, *s;
408 struct smu_ad_sensor *volt_sensor = NULL, *curr_sensor = NULL; 414 struct smu_ad_sensor *volt_sensor = NULL, *curr_sensor = NULL;
409 int rc;
410 415
411 if (!smu_present()) 416 if (!smu_present())
412 return -ENODEV; 417 return -ENODEV;
413 418
414 /* Get parameters partitions */ 419 /* Get parameters partitions */
415 rc = smu_fetch_param_partitions(); 420 smu_fetch_param_partitions();
416 if (rc)
417 return rc;
418 421
419 smu = of_find_node_by_type(NULL, "smu"); 422 smu = of_find_node_by_type(NULL, "smu");
420 if (smu == NULL) 423 if (smu == NULL)
diff --git a/include/asm-powerpc/smu.h b/include/asm-powerpc/smu.h
index 82ce4760777..2dc93632f21 100644
--- a/include/asm-powerpc/smu.h
+++ b/include/asm-powerpc/smu.h
@@ -521,6 +521,11 @@ struct smu_sdbp_cpupiddata {
521extern struct smu_sdbp_header *smu_get_sdb_partition(int id, 521extern struct smu_sdbp_header *smu_get_sdb_partition(int id,
522 unsigned int *size); 522 unsigned int *size);
523 523
524/* Get "sdb" partition data from an SMU satellite */
525extern struct smu_sdbp_header *smu_sat_get_sdb_partition(unsigned int sat_id,
526 int id, unsigned int *size);
527
528
524#endif /* __KERNEL__ */ 529#endif /* __KERNEL__ */
525 530
526 531