Merge branch 'merge' of git://git.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc

* 'merge' of git://git.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc:
  [POWERPC] Minor comment fix for misc_64.S
  [POWERPC] Use H_CEDE on non-SMT
  [POWERPC] force 64bit mode in fwnmi handlers to workaround firmware bugs
  [POWERPC] PMAC_APM_EMU should depend on ADB_PMU
  [POWERPC] Fix new interrupt code (MPIC detection)
  [POWERPC] Fix new interrupt code (MPIC endianness)
  [POWERPC] Add cpufreq support for Xserve G5
  [POWERPC] Xserve G5 thermal control fixes
  [POWERPC] Fix mem= handling when the memory limit is > RMO size
  [POWERPC] More offb/bootx fixes
  [POWERPC] Fix legacy_serial.c error handling on 32 bits
  [POWERPC] Fix default clock for udbg_16550
  [POWERPC] Fix non-MPIC CHRPs with CONFIG_SMP set
  [POWERPC] Fix 32 bits warning in prom_init.c
  [POWERPC] Workaround Pegasos incorrect ISA "ranges"
  [POWERPC] fix up front-LED Kconfig
This commit is contained in:
Linus Torvalds 2006-07-31 13:39:52 -07:00
commit 49b1e3ea19
20 changed files with 703 additions and 263 deletions

View file

@ -90,6 +90,15 @@ config ADB_PMU_LED
and the ide-disk LED trigger and configure appropriately through
sysfs.
config ADB_PMU_LED_IDE
bool "Use front LED as IDE LED by default"
depends on ADB_PMU_LED
select LEDS_TRIGGERS
select LEDS_TRIGGER_IDE_DISK
help
This option makes the front LED default to the IDE trigger
so that it blinks on IDE activity.
config PMAC_SMU
bool "Support for SMU based PowerMacs"
depends on PPC_PMAC64
@ -100,7 +109,7 @@ config PMAC_SMU
config PMAC_APM_EMU
tristate "APM emulation"
depends on PPC_PMAC && PPC32 && PM
depends on PPC_PMAC && PPC32 && PM && ADB_PMU
config PMAC_MEDIABAY
bool "Support PowerBook hotswap media bay"

View file

@ -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>
@ -121,7 +132,7 @@
#include "therm_pm72.h"
#define VERSION "1.2b2"
#define VERSION "1.3"
#undef DEBUG
@ -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;
@ -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);
/*
@ -495,13 +508,20 @@ 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;
@ -509,12 +529,15 @@ static int set_rpm_fan(int fan_index, int rpm)
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;
@ -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)
@ -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
@ -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);
@ -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);
/*
@ -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;
@ -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));
@ -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)
{
@ -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 };
@ -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) {
@ -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);
@ -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);
@ -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);
}
@ -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;

View file

@ -105,6 +105,7 @@ static char * critical_overtemp_path = "/sbin/critical_overtemp";
#define DRIVES_DALLAS_ID 0x94
#define BACKSIDE_MAX_ID 0x98
#define XSERVE_DIMMS_LM87 0x25a
#define XSERVE_SLOTS_LM75 0x290
/*
* Some MAX6690, DS1775, LM87 register definitions
@ -198,7 +199,7 @@ struct drives_pid_state
#define SLOTS_FAN_PWM_DEFAULT_ID 2
#define SLOTS_FAN_PWM_INDEX 2
#define SLOTS_FAN_DEFAULT_PWM 50 /* Do better here ! */
#define SLOTS_FAN_DEFAULT_PWM 40 /* Do better here ! */
/*
@ -206,7 +207,7 @@ struct drives_pid_state
*/
#define DIMM_PID_G_d 0
#define DIMM_PID_G_p 0
#define DIMM_PID_G_r 0x6553600
#define DIMM_PID_G_r 0x06553600
#define DIMM_PID_INPUT_TARGET 3276800
#define DIMM_PID_INTERVAL 1
#define DIMM_PID_OUTPUT_MAX 14000
@ -226,6 +227,31 @@ struct dimm_pid_state
};
/*
* PID factors for the Xserve Slots control loop
*/
#define SLOTS_PID_G_d 0
#define SLOTS_PID_G_p 0
#define SLOTS_PID_G_r 0x00100000
#define SLOTS_PID_INPUT_TARGET 3200000
#define SLOTS_PID_INTERVAL 1
#define SLOTS_PID_OUTPUT_MAX 100
#define SLOTS_PID_OUTPUT_MIN 20
#define SLOTS_PID_HISTORY_SIZE 20
struct slots_pid_state
{
int ticks;
struct i2c_client * monitor;
s32 sample_history[SLOTS_PID_HISTORY_SIZE];
s32 error_history[SLOTS_PID_HISTORY_SIZE];
int cur_sample;
s32 last_temp;
int first;
int pwm;
};
/* Desktops */
@ -283,6 +309,9 @@ struct cpu_pid_state
s32 pump_max;
};
/* Tickle FCU every 10 seconds */
#define FCU_TICKLE_TICKS 10
/*
* Driver state
*/

View file

@ -74,7 +74,7 @@ static void pmu_led_set(struct led_classdev *led_cdev,
static struct led_classdev pmu_led = {
.name = "pmu-front-led",
#ifdef CONFIG_BLK_DEV_IDE_PMAC_BLINK
#ifdef CONFIG_ADB_PMU_LED_IDE
.default_trigger = "ide-disk",
#endif
.brightness_set = pmu_led_set,