[RFC] Dynamic fan clock divider changes (long)

From: Jean Delvare
Date: Sun May 16 2004 - 15:28:28 EST


Hi all,

This is a RFC about fan clock dividers in hardware monitoring chips.

### THE PROBLEM

Since the beginning of the lm78 project (now lm_sensors project, and
Linux 2.6 drivers), it has been assumed that users would be required to
manually set "fan divisors" of their hardware monitoring chipset in
order to have correct fan speed readings for their specific
configuration.

This has since become a FAQ, and is still one of the major source of
trouble and questions for fan speed measurements. This is why I am
suggesting that we could change our policy and have the proper clock
selection done by the drivers instead. I don't think I am the first one
to request that. I'm pretty sure I read a similar suggestion on this
list some times ago, but I can't remember who it came from.

The fact that various datasheets and documentation refer to it as "fan
divisors" has obviously added to the confusion. A more correct term
would be "fan clock divider", IMHO.

### ADDITIONAL POINTS TO CONSIDER

A second point to consider is that more and more people are willing to
change the speed of the fan depending of the temperature, most generally
using PWM (pulse width modulation), manual, software-driven or
hardware-driven. This means that a single divider may not be suitable
for the the full operating speed range. One particular point raised here
is that selecting the proper fan clock divider once and for all as the
driver loads is not sufficent. Also think of people plugging a new fan
afterwards, or changing fans. No way we want to force them to reload the
driver (which could be hard-built into the kernel anyway).

To add to complexity, remember that not only the measured fan speed has
to fit with the current clock divider, but the low fan speed limit has
to fit as well.

I have come to three possible implementations of various complexity,
depending on what we want to do, or not.

### WHAT YOU NEED TO KNOW

Here are a few reminders of how fan speed measurement work. It's
somewhat tricky, so even people with good knowledge are easily
mistaking. People with no knowledge wouldn't even have a chance to get
what I'm talking about without this summary ;) I'm voluntarily
simplifying a few things so as not to confuse newcomers.

Fan speeds are not measured directly. Instead, what is measured is how
much periods of clock have passed before the fan did a full revolution.
This value is stored in an 8-bit register. The actual speed (in RPM) is
given by (clock speed)*60/(register value). This means that you cannot
measure fans slower than (clock speed)*60/255. For this reason, it is
usually possible to divide the clock speed by 2, 4 or 8 (or even more)
so as to be able to measure slower fan speeds.

Usually, a low limit can be set by the user. If the fan spins under this
limit, an alarm is raised. This low limit is stored in an 8-bit
register, using a similar convention, so that the chipset can easily
compare the measured speed and the defined low limit. Note that a higher
value in the register means a slower fan, so there is an alarm condition
if the value in the measure register if *greater* than the value in the
low limit register. This may be confusing at first.

Example:
clock speed is 8kHz
the user sets the low limit to 2400 RPM
-> value in low limit register is 200 (8000*60/2400)
value read in the measure register is 150
-> real speed is 3200 RPM (8000*60/150)
-> no alarm is triggered
lower measurable speed is 1882 RPM (8000*60/255)

If we want to be able to measure a fan speed of, say, 1500RPM, we have
to set the clock divider to 2.

You may wonder why we don't directly use the greatest divider then. This
is *not* to be able to measure higher fan speeds. Even with a divider of
8, higher measurable fan speed is 60000 RPM (1000*60). This should be
sufficent for everyone ;) No, the reason is accuracy. It happens that
the measurement accuracy is proportional to the clock speed. More
precisely, the accuracy, defined as the lowest measurable RPM
difference, is computed as (speed*speed)/(clock*60). For a fan speed of
6000 RPM, the accuracy with a divider of 8 is no more than +/- 600 RPM.

This is why the choice of the best divider is important and non-trivial.
This is a lowest-measurable-speed vs accuracy-at-high-speed tradeoff.

Before I go on, please consider the following facts:

For a given fan speed, increasing the clock divider means decreasing the
value stored in the register.

It is always possible to increase the clock divider without losing low
limit value. We may have to round it but it'll fit.

If is not always possible to decrease the clock divider without losing
the low limit value. If the value in the register is >= 128, it won't
fit in an 8-bit register after we multiply it by 2 or more.

### PROPOSED IMPLEMENTATIONS

Implementation #1

Each time the user requests new data (which triggers an update of each
register value), the fan speed measurement register is analyzed. If the
value is too high (arbitrary limit to be defined), or if an overflow
flag has been set (for chipsets with such flags), the next higher clock
divider is selected (unless we already use the greatest available). The
fan min is preserved, possibly rounded. Else, if the value is too low
(arbitrary limit to be defined), the next lower clock divider is
selected (unless we already use the lowest available). The low limit is
preserved if possible, or lost and stored as 255.

This implementation solves all points mentioned above. The user doesn't
have to care, and the divider will change automatically if PWM is used,
or fan is changed. The drawback is that the selected low limit may be
lost is the process.

Concrete example (still using a 8kHz clock):

The user has a fan running at 1500 RPM with PWM, and has set low limit
to 1250 RPM. The driver will select a divider of 2 (neither 1250 nor
1500 RPM do fit with a divider of 1, lowest representable speed being
1882 RPM). Then the system goes hot and the fan goes full speed at 5000
RPM. The divider will be lowered to 1 to increase accuracy, which will
change the low limit to the lowest possible value (register == 255, i.e.
1882 RPM). Then, later, the temperature is low again and the fan returns
to low speed. The divider is back to 2, low limit is preserved to 1882,
and an alarm triggers as the measured speed is 1500 RPM.

An alternate possibility is to consider register == 255 as a special
case, which wouldn't be affected by increasing clock dividers.

In the example above, this would restore the low limit as 941 RPM
(lowest representable value with divider of 2) at the end. This won't
trigger an error, but still changed the value requested by the user.

This implementation is OK for the measured speed, but has side effects
on low limit.

Implementation #2

Same as #1, except that the low limit has to fit with the new clock
divider for a clock change to actually occur. Likewise, if the user
wants to set a new low limit which doesn't fit with the current divider,
the divider is changed.

Since the low limit is normally lower than the measured speed, this
means that the low limit is what will determine the divider. This means
that this implementation doesn't solve all the issues mentioned above.
The user still doesn't have to care, which is fine, but if the user has
a fan speed between 2000 and 5000 RPM, with low limit set to 1500 RPM,
he/she will have a "bad" accuracy at 5000 RPM (+/- 104 RPM). I see this
as the low limit "nailing" the divider ;)

The improvement here is that the clock is also changed if needed to
satisfy a requested low limit. Until now, the lowest representable speed
would have been set instead.

This is what I implemented in my new pc87360 driver (after trying #1). I
use 85 and 224 as the arbitrary limits for changing dividers.

Implementation #3

Same as #2, but we dissociate the requested low limit and the
register-stored low limit.

For example, say that the user requests a low limit of 1000 RPM but the
divider is currently 1 because it is the best tradeoff for measured
speed of 3000RPM. We will set the low limit register to 255, which
corresponds to the lowest measurable value with divider 1. But we
remember that the user wants 1000, and display this value too. If, at a
later time, the fan goes slower and the divider increases to 2, we will
remember that the user wants 1000, and store that value in the register
(now that we can). So the trick is fully invisible to the user.

The point here is that we start lying to the user. The low limit we
present isn't what is stored in the register anymore. He/she will
hopefully never notice it, but there are corner cases where it could
matter. For example, the BIOS could be messing with the chip at the same
time we are (we already saw this) and periodically force the low limit
to a given value. The user wouldn't notice (because we don't display the
speed from the actual register value) and alarms could trigger without a
visible reason. This may be because the BIOS is bad, but this would
still confuse the user. Another case is if fan speeds drops suddenly. By
the time the driver reacts and changes the clock divider, an alarm is
likely to trigger, while the user will not see any limit excess.

Each of the problems above are work-aroundable, but this will probably
significantly increase the amount of code in the driver, which is no
good.

Inplementation #4

Since implementation #2 looks rather good, and will practically result
in the clock divisor being set from the selected low limit, and never
change thereafter, choosing a constant (rather high) divider from the
very beginning may be reasonable after all. With a 8kHz clock, a divider
of 2 lets you measure speeds down to 941 RPM, which is most probably
fine for almost everyone. As far as I know, fans running below 1000 RPM
in normal conditions are quite rare. So we would simply choose an
arbitrary divider depending on the clock speed of each chipset. This is
by far the less code-expensive approach, of course, but may not be
correct in some critical cases (very slow or very fast fans).

### CONCLUSION

I think I'll stick to #2 for now. The extra code is reasonable, and I
don't really see the low accuracy at high speed as a problem. What
matters much to me is that the user shouldn't have to worry about
selecting dividers himself, and #2 does this.

Part of the extra code may be moved to i2c_sensor if several drivers use
it. Also, remember that the new policy will remove some code from the
drivers (reading and setting dividers manually) so this gives us some
margin anyway.

Comments welcome, of course.

Thanks.

--
Jean Delvare
http://khali.linux-fr.org/
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/