/* * This option is "weird" :) Basically, if you define this to 1 * the control loop for the RPMs fans (not PWMs) will apply the * correction factor obtained from the PID to the actual RPM * speed read from the FCU. * * If you define the below constant to 0, then it will be * applied to the setpoint RPM speed, that is basically the * speed we proviously "asked" for. * * I'm using 0 for now which is what therm_pm72 used to do and * what Darwin -apparently- does based on observed behaviour.
*/ #define RPM_PID_USE_ACTUAL_SPEED 0
/* Double check the values, this _IS_ needed as the EEPROM on * some dual 2.5Ghz G5s seem, at least, to have both min & max * same to the same value ... (grrrr)
*/ if (pump_min == pump_max || pump_min == 0 || pump_max == 0xffff) {
pump_min = CPU_PUMP_OUTPUT_MIN;
pump_max = CPU_PUMP_OUTPUT_MAX;
}
fan->min = pump_min;
fan->max = pump_max;
DBG("wf_fcu: pump min/max for %s set to: [%d..%d] RPM\n",
fan->ctrl.name, pump_min, pump_max);
}
/* CPU fans have min/max in MPU */ if (mpu0 && !strcmp(fan->ctrl.name, "cpu-front-fan-0")) {
fan->min = max(fan->min, (s32)mpu0->rminn_intake_fan);
fan->max = min(fan->max, (s32)mpu0->rmaxn_intake_fan); goto bail;
} if (mpu1 && !strcmp(fan->ctrl.name, "cpu-front-fan-1")) {
fan->min = max(fan->min, (s32)mpu1->rminn_intake_fan);
fan->max = min(fan->max, (s32)mpu1->rmaxn_intake_fan); goto bail;
} if (mpu0 && !strcmp(fan->ctrl.name, "cpu-rear-fan-0")) {
fan->min = max(fan->min, (s32)mpu0->rminn_exhaust_fan);
fan->max = min(fan->max, (s32)mpu0->rmaxn_exhaust_fan); goto bail;
} if (mpu1 && !strcmp(fan->ctrl.name, "cpu-rear-fan-1")) {
fan->min = max(fan->min, (s32)mpu1->rminn_exhaust_fan);
fan->max = min(fan->max, (s32)mpu1->rmaxn_exhaust_fan); goto bail;
} /* Rackmac variants, we just use mpu0 intake */ if (!strncmp(fan->ctrl.name, "cpu-fan", 7)) {
fan->min = max(fan->min, (s32)mpu0->rminn_intake_fan);
fan->max = min(fan->max, (s32)mpu0->rmaxn_intake_fan); goto bail;
}
bail:
DBG("wf_fcu: fan min/max for %s set to: [%d..%d] RPM\n",
fan->ctrl.name, fan->min, fan->max);
}
staticvoid wf_fcu_add_fan(struct wf_fcu_priv *pv, constchar *name, int type, int id)
{ struct wf_fcu_fan *fan;
fan = kzalloc(sizeof(*fan), GFP_KERNEL); if (!fan) return;
fan->fcu_priv = pv;
fan->id = id;
fan->ctrl.name = name;
fan->ctrl.priv = fan;
/* min/max is oddball but the code comes from * therm_pm72 which seems to work so ...
*/ if (type == FCU_FAN_RPM) { if (!strncmp(name, "cpu-pump", strlen("cpu-pump")))
wf_fcu_get_pump_minmax(fan); else
wf_fcu_get_rpmfan_minmax(fan);
fan->ctrl.type = WF_CONTROL_RPM_FAN;
fan->ctrl.ops = &wf_fcu_fan_rpm_ops;
} else {
fan->min = 10;
fan->max = 100;
fan->ctrl.type = WF_CONTROL_PWM_FAN;
fan->ctrl.ops = &wf_fcu_fan_pwm_ops;
}
if (wf_register_control(&fan->ctrl)) {
pr_err("wf_fcu: Failed to register fan %s\n", name);
kfree(fan); return;
}
list_add(&fan->link, &pv->fan_list);
kref_get(&pv->ref);
}
staticvoid wf_fcu_lookup_fans(struct wf_fcu_priv *pv)
{ /* Translation of device-tree location properties to * windfarm fan names
*/ staticconststruct { constchar *dt_name; /* Device-tree name */ constchar *ct_name; /* Control name */
} loc_trans[] = {
{ "BACKSIDE", "backside-fan", },
{ "SYS CTRLR FAN", "backside-fan", },
{ "DRIVE BAY", "drive-bay-fan", },
{ "SLOT", "slots-fan", },
{ "PCI FAN", "slots-fan", },
{ "CPU A INTAKE", "cpu-front-fan-0", },
{ "CPU A EXHAUST", "cpu-rear-fan-0", },
{ "CPU B INTAKE", "cpu-front-fan-1", },
{ "CPU B EXHAUST", "cpu-rear-fan-1", },
{ "CPU A PUMP", "cpu-pump-0", },
{ "CPU B PUMP", "cpu-pump-1", },
{ "CPU A 1", "cpu-fan-a-0", },
{ "CPU A 2", "cpu-fan-b-0", },
{ "CPU A 3", "cpu-fan-c-0", },
{ "CPU B 1", "cpu-fan-a-1", },
{ "CPU B 2", "cpu-fan-b-1", },
{ "CPU B 3", "cpu-fan-c-1", },
}; struct device_node *np, *fcu = pv->i2c->dev.of_node; int i;
DBG("Looking up FCU controls in device-tree...\n");
for_each_child_of_node(fcu, np) { int id, type = -1; constchar *loc; constchar *name; const u32 *reg;
/* Detect control type */ if (of_node_is_type(np, "fan-rpm-control") ||
of_node_is_type(np, "fan-rpm"))
type = FCU_FAN_RPM; if (of_node_is_type(np, "fan-pwm-control") ||
of_node_is_type(np, "fan-pwm"))
type = FCU_FAN_PWM; /* Only care about fans for now */ if (type == -1) continue;
/* Lookup for a matching location */
loc = of_get_property(np, "location", NULL);
reg = of_get_property(np, "reg", NULL); if (loc == NULL || reg == NULL) continue;
DBG(" matching location: %s, reg: 0x%08x\n", loc, *reg);
for (i = 0; i < ARRAY_SIZE(loc_trans); i++) { if (strncmp(loc, loc_trans[i].dt_name,
strlen(loc_trans[i].dt_name))) continue;
name = loc_trans[i].ct_name;
DBG(" location match, name: %s\n", name);
if (type == FCU_FAN_RPM)
id = ((*reg) - 0x10) / 2; else
id = ((*reg) - 0x30) / 2; if (id > 7) {
pr_warn("wf_fcu: Can't parse fan ID in device-tree for %pOF\n", np); break;
}
wf_fcu_add_fan(pv, name, type, id); break;
}
}
}
staticvoid wf_fcu_default_fans(struct wf_fcu_priv *pv)
{ /* We only support the default fans for PowerMac7,2 */ if (!of_machine_is_compatible("PowerMac7,2")) return;
/* * First we must start the FCU which will query the * shift value to apply to RPMs
*/ if (wf_fcu_init_chip(pv)) {
pr_err("wf_fcu: Initialization failed !\n");
kfree(pv); return -ENXIO;
}
/* First lookup fans in the device-tree */
wf_fcu_lookup_fans(pv);
/* * Older machines don't have the device-tree entries * we are looking for, just hard code the list
*/ if (list_empty(&pv->fan_list))
wf_fcu_default_fans(pv);
/* Still no fans ? FAIL */ if (list_empty(&pv->fan_list)) {
pr_err("wf_fcu: Failed to find fans for your machine\n");
kfree(pv); return -ENODEV;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.