Currently we just support fan commands to drive old style fans
with smu(4).  I got some reports from users with new style fans
getting wrong sysctl values therefore.

This diff also adds the commands for new style fans.  Some testing
would be welcome in the way of a) regression testing and b) see if
it fixes broken values on systems with new style fans.


Index: smu.c
===================================================================
RCS file: /cvs/src/sys/arch/macppc/dev/smu.c,v
retrieving revision 1.32
diff -u -p -u -p -r1.32 smu.c
--- smu.c       20 May 2016 21:56:00 -0000      1.32
+++ smu.c       25 May 2016 09:13:49 -0000
@@ -47,6 +47,7 @@ void    smu_attach(struct device *, stru
 struct smu_fan {
        struct thermal_fan fan;
        u_int8_t        reg;
+       u_int8_t        old_style;
        u_int16_t       min_rpm;
        u_int16_t       max_rpm;
        u_int16_t       unmanaged_rpm;
@@ -153,6 +154,7 @@ int smu_do_cmd(struct smu_softc *, int);
 int    smu_time_read(time_t *);
 int    smu_time_write(time_t);
 int    smu_get_datablock(struct smu_softc *sc, u_int8_t, u_int8_t *, size_t);
+void   smu_fan_check_style(struct smu_softc *, struct smu_fan *);
 int    smu_fan_set_rpm(struct smu_softc *, struct smu_fan *, u_int16_t);
 int    smu_fan_set_pwm(struct smu_softc *, struct smu_fan *, u_int16_t);
 int    smu_fan_read_rpm(struct smu_softc *, struct smu_fan *, u_int16_t *);
@@ -194,7 +196,7 @@ smu_attach(struct device *parent, struct
        struct i2cbus_attach_args iba;
        struct smu_fan *fan;
        struct smu_sensor *sensor;
-       int nseg, node;
+       int nseg, node, i;
        char type[32], loc[32];
        u_int32_t reg, intr, gpio, val;
 #ifndef SMALL_KERNEL
@@ -393,6 +395,10 @@ smu_attach(struct device *parent, struct
                return;
        }
 
+       /* Check if we have old or new style fans */
+       for (i = 0; i < sc->sc_num_fans; i++)
+               smu_fan_check_style(sc, &sc->sc_fans[i]);
+
 #ifndef SMALL_KERNEL
        /* Sensors */
        node = OF_getnodebyname(ca->ca_node, "sensors");
@@ -634,6 +640,25 @@ smu_get_datablock(struct smu_softc *sc, 
        return (0);
 }
 
+void
+smu_fan_check_style(struct smu_softc *sc, struct smu_fan *fan)
+{
+       struct smu_cmd *cmd = (struct smu_cmd *)sc->sc_cmd;
+       int error;
+
+       /*
+        * Check if we can read the fan rpm with the new style command.
+        * If not we assume this is an old style fan.
+        */
+       cmd->cmd = SMU_FAN;
+       cmd->len = 2;
+       cmd->data[0] = 0x31;
+       cmd->data[1] = fan->reg;
+       error = smu_do_cmd(sc, 800);
+       if (error)
+               fan->old_style = 1;
+}
+
 int
 smu_fan_set_rpm(struct smu_softc *sc, struct smu_fan *fan, u_int16_t rpm)
 {
@@ -645,12 +670,21 @@ smu_fan_set_rpm(struct smu_softc *sc, st
         * the PowerMac8,1.  We simply store the value at both
         * locations.
         */
-       cmd->cmd = SMU_FAN;
-       cmd->len = 14;
-       cmd->data[0] = 0x00;    /* fan-rpm-control */
-       cmd->data[1] = 0x01 << fan->reg;
-       cmd->data[2] = cmd->data[2 + fan->reg * 2] = (rpm >> 8) & 0xff;
-       cmd->data[3] = cmd->data[3 + fan->reg * 2] = (rpm & 0xff);
+       if (fan->old_style) {
+               cmd->cmd = SMU_FAN;
+               cmd->len = 14;
+               cmd->data[0] = 0x00;    /* fan-rpm-control */
+               cmd->data[1] = 0x01 << fan->reg;
+               cmd->data[2] = cmd->data[2 + fan->reg * 2] = (rpm >> 8) & 0xff;
+               cmd->data[3] = cmd->data[3 + fan->reg * 2] = (rpm & 0xff);
+       } else {
+               cmd->cmd = SMU_FAN;
+               cmd->len = 4;
+               cmd->data[0] = 0x30;
+               cmd->data[1] = fan->reg;
+               cmd->data[2] = (rpm >> 8) & 0xff;
+               cmd->data[3] = rpm & 0xff;
+       }
        return smu_do_cmd(sc, 800);
 }
 
@@ -659,12 +693,21 @@ smu_fan_set_pwm(struct smu_softc *sc, st
 {
        struct smu_cmd *cmd = (struct smu_cmd *)sc->sc_cmd;
 
-       cmd->cmd = SMU_FAN;
-       cmd->len = 14;
-       cmd->data[0] = 0x10;    /* fan-pwm-control */
-       cmd->data[1] = 0x01 << fan->reg;
-       cmd->data[2] = cmd->data[2 + fan->reg * 2] = (pwm >> 8) & 0xff;
-       cmd->data[3] = cmd->data[3 + fan->reg * 2] = (pwm & 0xff);
+       if (fan->old_style) {
+               cmd->cmd = SMU_FAN;
+               cmd->len = 14;
+               cmd->data[0] = 0x10;    /* fan-pwm-control */
+               cmd->data[1] = 0x01 << fan->reg;
+               cmd->data[2] = cmd->data[2 + fan->reg * 2] = (pwm >> 8) & 0xff;
+               cmd->data[3] = cmd->data[3 + fan->reg * 2] = (pwm & 0xff);
+       } else {
+               cmd->cmd = SMU_FAN;
+               cmd->len = 4;
+               cmd->data[0] = 0x30;
+               cmd->data[1] = fan->reg;
+               cmd->data[2] = (pwm >> 8) & 0xff;
+               cmd->data[3] = pwm & 0xff;
+       }
        return smu_do_cmd(sc, 800);
 }
 
@@ -674,13 +717,25 @@ smu_fan_read_rpm(struct smu_softc *sc, s
        struct smu_cmd *cmd = (struct smu_cmd *)sc->sc_cmd;
        int error;
 
-       cmd->cmd = SMU_FAN;
-       cmd->len = 1;
-       cmd->data[0] = 0x01;    /* fan-rpm-control */
-       error = smu_do_cmd(sc, 800);
-       if (error)
-               return (error);
-       *rpm = (cmd->data[fan->reg * 2 + 1] << 8) | cmd->data[fan->reg * 2 + 2];
+       if (fan->old_style) {
+               cmd->cmd = SMU_FAN;
+               cmd->len = 1;
+               cmd->data[0] = 0x01;    /* fan-rpm-control */
+               error = smu_do_cmd(sc, 800);
+               if (error)
+                       return (error);
+               *rpm = (cmd->data[fan->reg * 2 + 1] << 8) |
+                       cmd->data[fan->reg * 2 + 2];
+       } else {
+               cmd->cmd = SMU_FAN;
+               cmd->len = 2;
+               cmd->data[0] = 0x31;
+               cmd->data[1] = fan->reg;
+               error = smu_do_cmd(sc, 800);
+               if (error)
+                       return (error);
+               *rpm = (cmd->data[0] << 8) | cmd->data[1];
+       }
 
        return (0);
 }
@@ -692,24 +747,43 @@ smu_fan_read_pwm(struct smu_softc *sc, s
        struct smu_cmd *cmd = (struct smu_cmd *)sc->sc_cmd;
        int error;
 
-       /* read PWM value */
-       cmd->cmd = SMU_FAN;
-       cmd->len = 14;
-       cmd->data[0] = 0x12;
-       cmd->data[1] = 0x01 << fan->reg;
-       error = smu_do_cmd(sc, 800);
-       if (error)
-               return (error);
-       *pwm = cmd->data[fan->reg * 2 + 2];
+       if (fan->old_style) {
+               /* read PWM value */
+               cmd->cmd = SMU_FAN;
+               cmd->len = 14;
+               cmd->data[0] = 0x12;
+               cmd->data[1] = 0x01 << fan->reg;
+               error = smu_do_cmd(sc, 800);
+               if (error)
+                       return (error);
+               *pwm = cmd->data[fan->reg * 2 + 2];
 
-       /* read RPM value */
-       cmd->cmd = SMU_FAN;
-       cmd->len = 1;
-       cmd->data[0] = 0x11;
-       error = smu_do_cmd(sc, 800);
-       if (error)
-               return (error);
-       *rpm = (cmd->data[fan->reg * 2 + 1] << 8) | cmd->data[fan->reg * 2 + 2];
+               /* read RPM value */
+               cmd->cmd = SMU_FAN;
+               cmd->len = 1;
+               cmd->data[0] = 0x11;
+               error = smu_do_cmd(sc, 800);
+               if (error)
+                       return (error);
+               *rpm = (cmd->data[fan->reg * 2 + 1] << 8) |
+                       cmd->data[fan->reg * 2 + 2];
+       } else {
+               cmd->cmd = SMU_FAN;
+               cmd->len = 2;
+               cmd->data[0] = 0x31;
+               cmd->data[1] = fan->reg;
+               error = smu_do_cmd(sc, 800);
+               if (error)
+                       return (error);
+               *rpm = (cmd->data[0] << 8) | cmd->data[1];
+
+               /* XXX
+                * We don't know currently if there is a read pwm command
+                * for new style fans as well.  Therefore lets calculate
+                * the value for now.
+                */
+               *pwm = *rpm * 100 / fan->max_rpm;
+       }
 
        return (0);
 }

Reply via email to