Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 34025
b: refs/heads/master
c: 861fa77
h: refs/heads/master
i:
  34023: 83bc519
v: v3
  • Loading branch information
Benjamin Herrenschmidt authored and Paul Mackerras committed Jul 7, 2006
1 parent 90d270c commit c59da9c
Show file tree
Hide file tree
Showing 3 changed files with 235 additions and 18 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: e7c1f69d4fa4da47dc995b5de64b6cb76ae32081
refs/heads/master: 861fa7737db889ae1701ba58c083d4a7bd8705d3
218 changes: 203 additions & 15 deletions trunk/drivers/macintosh/therm_pm72.c
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,17 @@
* - Use min/max macros here or there
* - Latest darwin updated U3H min fan speed to 20% PWM
*
* July. 06, 2006 : 1.3
* - Fix setting of RPM fans on Xserve G5 (they were going too fast)
* - Add missing slots fan control loop for Xserve G5
* - Lower fixed slots fan speed from 50% to 40% on desktop G5s. We
* still can't properly implement the control loop for these, so let's
* reduce the noise a little bit, it appears that 40% still gives us
* a pretty good air flow
* - Add code to "tickle" the FCU regulary so it doesn't think that
* we are gone while in fact, the machine just didn't need any fan
* speed change lately
*
*/

#include <linux/types.h>
Expand All @@ -121,7 +132,7 @@

#include "therm_pm72.h"

#define VERSION "1.2b2"
#define VERSION "1.3"

#undef DEBUG

Expand All @@ -146,6 +157,7 @@ static struct basckside_pid_params backside_params;
static struct backside_pid_state backside_state;
static struct drives_pid_state drives_state;
static struct dimm_pid_state dimms_state;
static struct slots_pid_state slots_state;
static int state;
static int cpu_count;
static int cpu_pid_type;
Expand All @@ -154,7 +166,8 @@ static struct completion ctrl_complete;
static int critical_state;
static int rackmac;
static s32 dimm_output_clamp;

static int fcu_rpm_shift;
static int fcu_tickle_ticks;
static DECLARE_MUTEX(driver_lock);

/*
Expand Down Expand Up @@ -495,26 +508,36 @@ static int start_fcu(void)
rc = fan_write_reg(0x2e, &buf, 1);
if (rc < 0)
return -EIO;
rc = fan_read_reg(0, &buf, 1);
if (rc < 0)
return -EIO;
fcu_rpm_shift = (buf == 1) ? 2 : 3;
printk(KERN_DEBUG "FCU Initialized, RPM fan shift is %d\n",
fcu_rpm_shift);

return 0;
}

static int set_rpm_fan(int fan_index, int rpm)
{
unsigned char buf[2];
int rc, id;
int rc, id, min, max;

if (fcu_fans[fan_index].type != FCU_FAN_RPM)
return -EINVAL;
id = fcu_fans[fan_index].id;
if (id == FCU_FAN_ABSENT_ID)
return -EINVAL;

if (rpm < 300)
rpm = 300;
else if (rpm > 8191)
rpm = 8191;
buf[0] = rpm >> 5;
buf[1] = rpm << 3;
min = 2400 >> fcu_rpm_shift;
max = 56000 >> fcu_rpm_shift;

if (rpm < min)
rpm = min;
else if (rpm > max)
rpm = max;
buf[0] = rpm >> (8 - fcu_rpm_shift);
buf[1] = rpm << fcu_rpm_shift;
rc = fan_write_reg(0x10 + (id * 2), buf, 2);
if (rc < 0)
return -EIO;
Expand Down Expand Up @@ -551,7 +574,7 @@ static int get_rpm_fan(int fan_index, int programmed)
if (rc != 2)
return -EIO;

return (buf[0] << 5) | buf[1] >> 3;
return (buf[0] << (8 - fcu_rpm_shift)) | buf[1] >> fcu_rpm_shift;
}

static int set_pwm_fan(int fan_index, int pwm)
Expand Down Expand Up @@ -609,6 +632,26 @@ static int get_pwm_fan(int fan_index)
return (buf[0] * 1000) / 2559;
}

static void tickle_fcu(void)
{
int pwm;

pwm = get_pwm_fan(SLOTS_FAN_PWM_INDEX);

DBG("FCU Tickle, slots fan is: %d\n", pwm);
if (pwm < 0)
pwm = 100;

if (!rackmac) {
pwm = SLOTS_FAN_DEFAULT_PWM;
} else if (pwm < SLOTS_PID_OUTPUT_MIN)
pwm = SLOTS_PID_OUTPUT_MIN;

/* That is hopefully enough to make the FCU happy */
set_pwm_fan(SLOTS_FAN_PWM_INDEX, pwm);
}


/*
* Utility routine to read the CPU calibration EEPROM data
* from the device-tree
Expand Down Expand Up @@ -715,6 +758,9 @@ BUILD_SHOW_FUNC_INT(backside_fan_pwm, backside_state.pwm)
BUILD_SHOW_FUNC_FIX(drives_temperature, drives_state.last_temp)
BUILD_SHOW_FUNC_INT(drives_fan_rpm, drives_state.rpm)

BUILD_SHOW_FUNC_FIX(slots_temperature, slots_state.last_temp)
BUILD_SHOW_FUNC_INT(slots_fan_pwm, slots_state.pwm)

BUILD_SHOW_FUNC_FIX(dimms_temperature, dimms_state.last_temp)

static DEVICE_ATTR(cpu0_temperature,S_IRUGO,show_cpu0_temperature,NULL);
Expand All @@ -735,6 +781,9 @@ static DEVICE_ATTR(backside_fan_pwm,S_IRUGO,show_backside_fan_pwm,NULL);
static DEVICE_ATTR(drives_temperature,S_IRUGO,show_drives_temperature,NULL);
static DEVICE_ATTR(drives_fan_rpm,S_IRUGO,show_drives_fan_rpm,NULL);

static DEVICE_ATTR(slots_temperature,S_IRUGO,show_slots_temperature,NULL);
static DEVICE_ATTR(slots_fan_pwm,S_IRUGO,show_slots_fan_pwm,NULL);

static DEVICE_ATTR(dimms_temperature,S_IRUGO,show_dimms_temperature,NULL);

/*
Expand Down Expand Up @@ -1076,6 +1125,9 @@ static void do_monitor_cpu_rack(struct cpu_pid_state *state)
fan_min = dimm_output_clamp;
fan_min = max(fan_min, (int)state->mpu.rminn_intake_fan);

DBG(" CPU min mpu = %d, min dimm = %d\n",
state->mpu.rminn_intake_fan, dimm_output_clamp);

state->rpm = max(state->rpm, (int)fan_min);
state->rpm = min(state->rpm, (int)state->mpu.rmaxn_intake_fan);
state->intake_rpm = state->rpm;
Expand Down Expand Up @@ -1374,7 +1426,8 @@ static void do_monitor_drives(struct drives_pid_state *state)
DBG(" current rpm: %d\n", state->rpm);

/* Get some sensor readings */
temp = le16_to_cpu(i2c_smbus_read_word_data(state->monitor, DS1775_TEMP)) << 8;
temp = le16_to_cpu(i2c_smbus_read_word_data(state->monitor,
DS1775_TEMP)) << 8;
state->last_temp = temp;
DBG(" temp: %d.%03d, target: %d.%03d\n", FIX32TOPRINT(temp),
FIX32TOPRINT(DRIVES_PID_INPUT_TARGET));
Expand Down Expand Up @@ -1575,7 +1628,7 @@ static int init_dimms_state(struct dimm_pid_state *state)
}

/*
* Dispose of the state data for the drives control loop
* Dispose of the state data for the DIMM control loop
*/
static void dispose_dimms_state(struct dimm_pid_state *state)
{
Expand All @@ -1588,6 +1641,127 @@ static void dispose_dimms_state(struct dimm_pid_state *state)
state->monitor = NULL;
}

/*
* Slots fan control loop
*/
static void do_monitor_slots(struct slots_pid_state *state)
{
s32 temp, integral, derivative;
s64 integ_p, deriv_p, prop_p, sum;
int i, rc;

if (--state->ticks != 0)
return;
state->ticks = SLOTS_PID_INTERVAL;

DBG("slots:\n");

/* Check fan status */
rc = get_pwm_fan(SLOTS_FAN_PWM_INDEX);
if (rc < 0) {
printk(KERN_WARNING "Error %d reading slots fan !\n", rc);
/* XXX What do we do now ? */
} else
state->pwm = rc;
DBG(" current pwm: %d\n", state->pwm);

/* Get some sensor readings */
temp = le16_to_cpu(i2c_smbus_read_word_data(state->monitor,
DS1775_TEMP)) << 8;
state->last_temp = temp;
DBG(" temp: %d.%03d, target: %d.%03d\n", FIX32TOPRINT(temp),
FIX32TOPRINT(SLOTS_PID_INPUT_TARGET));

/* Store temperature and error in history array */
state->cur_sample = (state->cur_sample + 1) % SLOTS_PID_HISTORY_SIZE;
state->sample_history[state->cur_sample] = temp;
state->error_history[state->cur_sample] = temp - SLOTS_PID_INPUT_TARGET;

/* If first loop, fill the history table */
if (state->first) {
for (i = 0; i < (SLOTS_PID_HISTORY_SIZE - 1); i++) {
state->cur_sample = (state->cur_sample + 1) %
SLOTS_PID_HISTORY_SIZE;
state->sample_history[state->cur_sample] = temp;
state->error_history[state->cur_sample] =
temp - SLOTS_PID_INPUT_TARGET;
}
state->first = 0;
}

/* Calculate the integral term */
sum = 0;
integral = 0;
for (i = 0; i < SLOTS_PID_HISTORY_SIZE; i++)
integral += state->error_history[i];
integral *= SLOTS_PID_INTERVAL;
DBG(" integral: %08x\n", integral);
integ_p = ((s64)SLOTS_PID_G_r) * (s64)integral;
DBG(" integ_p: %d\n", (int)(integ_p >> 36));
sum += integ_p;

/* Calculate the derivative term */
derivative = state->error_history[state->cur_sample] -
state->error_history[(state->cur_sample + SLOTS_PID_HISTORY_SIZE - 1)
% SLOTS_PID_HISTORY_SIZE];
derivative /= SLOTS_PID_INTERVAL;
deriv_p = ((s64)SLOTS_PID_G_d) * (s64)derivative;
DBG(" deriv_p: %d\n", (int)(deriv_p >> 36));
sum += deriv_p;

/* Calculate the proportional term */
prop_p = ((s64)SLOTS_PID_G_p) * (s64)(state->error_history[state->cur_sample]);
DBG(" prop_p: %d\n", (int)(prop_p >> 36));
sum += prop_p;

/* Scale sum */
sum >>= 36;

DBG(" sum: %d\n", (int)sum);
state->pwm = (s32)sum;

state->pwm = max(state->pwm, SLOTS_PID_OUTPUT_MIN);
state->pwm = min(state->pwm, SLOTS_PID_OUTPUT_MAX);

DBG("** DRIVES PWM: %d\n", (int)state->pwm);
set_pwm_fan(SLOTS_FAN_PWM_INDEX, state->pwm);
}

/*
* Initialize the state structure for the slots bay fan control loop
*/
static int init_slots_state(struct slots_pid_state *state)
{
state->ticks = 1;
state->first = 1;
state->pwm = 50;

state->monitor = attach_i2c_chip(XSERVE_SLOTS_LM75, "slots_temp");
if (state->monitor == NULL)
return -ENODEV;

device_create_file(&of_dev->dev, &dev_attr_slots_temperature);
device_create_file(&of_dev->dev, &dev_attr_slots_fan_pwm);

return 0;
}

/*
* Dispose of the state data for the slots control loop
*/
static void dispose_slots_state(struct slots_pid_state *state)
{
if (state->monitor == NULL)
return;

device_remove_file(&of_dev->dev, &dev_attr_slots_temperature);
device_remove_file(&of_dev->dev, &dev_attr_slots_fan_pwm);

detach_i2c_chip(state->monitor);
state->monitor = NULL;
}


static int call_critical_overtemp(void)
{
char *argv[] = { critical_overtemp_path, NULL };
Expand Down Expand Up @@ -1617,14 +1791,17 @@ static int main_control_loop(void *x)
goto out;
}

/* Set the PCI fan once for now */
set_pwm_fan(SLOTS_FAN_PWM_INDEX, SLOTS_FAN_DEFAULT_PWM);
/* Set the PCI fan once for now on non-RackMac */
if (!rackmac)
set_pwm_fan(SLOTS_FAN_PWM_INDEX, SLOTS_FAN_DEFAULT_PWM);

/* Initialize ADCs */
initialize_adc(&cpu_state[0]);
if (cpu_state[1].monitor != NULL)
initialize_adc(&cpu_state[1]);

fcu_tickle_ticks = FCU_TICKLE_TICKS;

up(&driver_lock);

while (state == state_attached) {
Expand All @@ -1634,6 +1811,12 @@ static int main_control_loop(void *x)

down(&driver_lock);

/* Tickle the FCU just in case */
if (--fcu_tickle_ticks < 0) {
fcu_tickle_ticks = FCU_TICKLE_TICKS;
tickle_fcu();
}

/* First, we always calculate the new DIMMs state on an Xserve */
if (rackmac)
do_monitor_dimms(&dimms_state);
Expand All @@ -1654,7 +1837,9 @@ static int main_control_loop(void *x)
}
/* Then, the rest */
do_monitor_backside(&backside_state);
if (!rackmac)
if (rackmac)
do_monitor_slots(&slots_state);
else
do_monitor_drives(&drives_state);
up(&driver_lock);

Expand Down Expand Up @@ -1696,6 +1881,7 @@ static void dispose_control_loops(void)
dispose_cpu_state(&cpu_state[1]);
dispose_backside_state(&backside_state);
dispose_drives_state(&drives_state);
dispose_slots_state(&slots_state);
dispose_dimms_state(&dimms_state);
}

Expand Down Expand Up @@ -1745,6 +1931,8 @@ static int create_control_loops(void)
goto fail;
if (rackmac && init_dimms_state(&dimms_state))
goto fail;
if (rackmac && init_slots_state(&slots_state))
goto fail;
if (!rackmac && init_drives_state(&drives_state))
goto fail;

Expand Down
Loading

0 comments on commit c59da9c

Please sign in to comment.