[lm-sensors] RE: vt8231.c

Roger Lucas roger at planbit.co.uk
Wed Nov 2 15:20:35 CET 2005

Hi Jean,

Updated patch attached.  I love it when you inherit loads of code that you
end up fixing... :-)

I am not so sure I am very keen on the intelligence for the auto-div
calculation moving into the driver.  I think this code should be in the
sensors utility.

On the other hand, however, the way the DIV_TO_REG() function was coded, it
would be almost impossible for any application to determine the legal values
for DIV without knowing the details of the device.  Any illegal value would
end up with DIV set at zero - not very helpful.  As an alternative, this
attached patch includes a code revision that sets DIV to the smallest legal
DIV value that is the same as or larger than the requested DIV value.
Hence, the mapping is as below:

	Requested DIV   Set DIV
		1		1
		2		2
		3		4
		4		4
		5		8
		6		8
		7		8
		8		8
		8+		8

>From this sequence, the DIV returned is predictable and an application can
very quickly determine the legal DIV values and make its calculations

With this revised code, if you ask for a low limit 1000 RPM with a divisor
of 4, you get a low limit of 1285 RPM returned.  If you ask for a low limit
of 1000 RPM with a divisor of 5 then you get a low limit of 999 RPM returned
with a divisor of 8.

Consider the pseudo-code below:

set_div = 1;

while( get_low_limit_rpm() > requested_limit_rpm )
	true_div = get_rpm_div();
	if (set_div > true_div)
		break; // we have exceeded the DIV range
	// Try next div value
	set_div = true_div + 1;

This will iterate through the valid DIV values and stop when it reaches the
best RPM match or the highest valid DIV setting.

I feel that this should be up in the application, however, and not in the
driver.  IMHO, the drivers should be a simple as possible.

- Roger

-----Original Message-----
From: Jean Delvare [mailto:khali at linux-fr.org] 
Sent: 02 November 2005 13:12
To: roger at planbit.co.uk
Cc: 'LM Sensors'; Knut Petersen
Subject: [lm-sensors] RE: vt8231.c

Hi Roger,

On 2005-11-2, Roger Lucas wrote:
> The fan is handled correctly, but you have the nasty condition where if
> you set a minimum speed that is too low, it is set to zero.  The Via
> speed sensor works on period rather than frequency, so there is a 1/x
> conversion done in the driver.

Note that this is pretty standard, almost all fan tachometers work that
way. The only drivers which do not have to invert the register value are
the FSC ones if I remember correctly.

> If you select a frequency that is too low, then the conversion to a
> period creates a period that is too large for the counters and the
> resulting illegal result is rejected.

It's not rejected, it's even worse than that: it's rounded to the
greatest possible value (255), which in turn is read back as 0 RPM.

>                                        If you want very slow fan
> speeds then you must make sure the divider is set high enough so that
> the resulting period is within the limits of the device.
> Personally, I don't like this.  It isn't really a massive amount of work
> to get the driver to automatically either:
> 1) Automatically select the appropriate divider for the minimum speed
> that you have requested (i.e. pick the highest divider ratio that can
> give the speed you want range)
> Or
> 2) Select the lowest possible minimum speed if the one you selected is
> still too low.

I think that most drivers implement solution 2. We have a (low) number of
drivers which implement automatic fan-div switching (pc87360, adm9240),
which is a subset of solution 1.

> A minimum speed of 0 should always disable the minimum speed detection.

We can't always do that, as it depends on what the chip itself does.
Some chips have a dedicated bit to disable the alarm. Some chips disable
the alarm if the limit register is set to 0. Some chips disable the
alarm if the limit register is set to 255. What does the VT8231 do?

> Resetting the minimum speed to zero when you select a non-zero minimum
> speed is just plain wrong, however, as it is not obvious exactly what is
> happening "behind the scenes".  I spent quite a bit of time debugging the
> system to convince myself it was working "correctly".
> (...)
> Anyone else have thoughts on this?

I completely agree with you. Please fix the driver. We should port the
fix back to lm_sensors CVS too. In fact, I think the current behavior is
a bug in the original code. Consider the following code:

> /********* FAN RPM CONVERSIONS ********/
> /* But this chip saturates back at 0, not at 255 like all the other chips.
>    So, 0 means 0 RPM */
> static inline u8 FAN_TO_REG(long rpm, int div)
> {
> 	if (rpm == 0)
> 		return 0;						
> 	rpm = SENSORS_LIMIT(rpm, 1, 1000000);   
> 	return SENSORS_LIMIT((1310720 + rpm * div / 2) / (rpm * div), 1,
>                            255);
> }
> #define MIN_TO_REG(a, b) FAN_TO_REG(a, b)
> #define FAN_FROM_REG(val, div) \
>                  ((val)==0?0:(val)==255?0:1310720/((val)*(div)))

The comment clearly states that the register value will be 0 if the fan
speed is too low to be measured under the currently selected clock
divider. I guess this is true for stopped or missing fan as well (can
you confirm?) Thus there is no reason to consider the register value 255
any differently from other non-zero values, is there? The FAN_TO_REG
function does actually not, but the FAN_FROM_REG macro does, and I
believe this is where the bug is.

Try removing the (val)==255 case in FAN_TO_REG, and I think the driver
will behave like you described above (solution 2).

While you're there, please delete the MIN_TO_REG macro and use
FAN_TO_REG instead.

You could also get rid of the middle SENSORS_LIMIT call in FAN_TO_REG,
providing you use strtoul instead of strtol to read the input value (in
set_fan_min). The lower bound will be handled by strtoul and the == 0
check. The upper bound is redundant with the next SENSORS_LIMIT call.

If you are willing to implement the solution 1, fine with me. This isn't
a requirement for me to accept the driver in Linux 2.6 though.

I will try to review the code further later today. It would be great if
we could integrate this ported driver in Linux 2.6 soon, it has been
around for too long already.

Thanks a lot for your work,
Jean Delvare
-------------- next part --------------
An embedded and charset-unspecified text was scrubbed...
Name: kernel-2.6.14_vt8231_r2.patch.txt
URL: <http://lists.lm-sensors.org/pipermail/lm-sensors/attachments/20051102/68526d43/attachment.txt>

More information about the lm-sensors mailing list