Incorrect mdelay() results on Power Managed Machines x86

Woller, Thomas (twoller@crystal.cirrus.com)
Thu, 22 Mar 2001 14:29:48 -0600


Problem: Certain Laptops (IBM Thinkpads is where i see the issue) reduce the
CPU frequency based upon whether the unit is on battery power or direct
power. When the Linux kernel boots up, then the cpu_khz (time.c) value is
determined based upon the current cpu speed. But if the unit's power source
is subsequently changed (plugged into the power outlet from battery power;
or unplugged and moved to battery power), then the delay resulting from
mdelay() (i.e. udelay) is off by the same factor. cpu_khz is only
calculated
during init/boot time, and not on a change in the power source. This seems
to be a serious problem since the result is off by a factor of 4 in some
cases which impacts the mdelay() wait times in the same proportion (130 Mhz
cpu speed on battery and 500 Mhz CPU speed direct power, on an IBM
Thinkpad).

During resume the IBM thinkpad with the cs46xx driver needs to delay 700
milleseconds, so if the machine is booted up on battery power, then to
ensure that the delay is long enough, then a value of 3000 milleseconds is
must be programmed into the driver (3 seconds!). all the mdelay and udelay
wait times are incorrect by the same factor, resulting in some serious
problems when attempting to wait specific delay times in other parts of the
driver.

this issue seems like it would be a problem for quite a few drivers that are
used on laptops that need some fairly precise delays, but maybe this is only
an IBM Thinkpad issue. I know that there have been some DMA timeout errors
when resuming on IBM Thinkpads and maybe these errors that have been seen
are due to the invalid delay times generated.

solutions:
using schedule() during resume is not an option, as it causes an oops under
2.2, and causes a second resume to be entered in the pci_driver resume table
entry for some reason. also, schedule() is not fine enough granularity for
some of the micro second delays needed.

re-initing by reinvoking time_init() on each resume cycle doesn't seem to be
an option that i can see.

Appreciate any responses or thoughts on the subject,

Tom Woller
twoller@crystal.cirrus.com
Cirrus Logic/Crystal Semiconductor
(512) 912-3920

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