mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* Too much error in __const_udelay() ?
@ 2004-06-05  7:12 john stultz
  2004-06-05 15:23 ` Dominik Brodowski
  0 siblings, 1 reply; 12+ messages in thread
From: john stultz @ 2004-06-05  7:12 UTC (permalink / raw)
  To: lkml; +Cc: george anzinger, Dominik Brodowski, greg kh, Chris McDermott

[-- Attachment #1: Type: text/plain, Size: 2700 bytes --]

[Resending due to lkml bouncing me for having html attachments]

Hey all,
	I've been hunting a bug on one of our systems and it seems to closely
resemble the __delay() issues we saw w/ the ACPI PM time source. 

Earlier when implementing the ACPI PM time source, we found that we
couldn't use the actual ACPI PM time source for the __delay function, or
else various subsystems would break. I chalked it up to the 8Mhz counter
being too low res for some callers of delay(), causing the waits to be
far too long. We backed off to just using the TSC for delay() and things
seemed to get better.

However I've started to see some problems w/ 2.6 and USB on x440/x445s,
both of which use the 100Mhz cyclone time source. Further digging has
pointed to the fact that certain important udelay()s in the USB
subsystem aren't actually waiting long enough. 

So far I've narrowed it down to the scaled math bits in 
__const_udelay() causing too much error for loops_per_jiffy values
around the 100,000 level the cyclone timesource uses. 

To demonstrate this, I wrote the attached demo app using the
__const_udelay code.  For those not wanting to run it themselves, its
output (for HZ=1000) looks like:

  1 usec: LPJ:  100000 __udelay:     0 vs my_udelay:   100
  1 usec: LPJ: 1500000 __udelay:  1000 vs my_udelay:  1500

  2 usec: LPJ:  100000 __udelay:     0 vs my_udelay:   200
  2 usec: LPJ: 1500000 __udelay:  2000 vs my_udelay:  3000

  5 usec: LPJ:  100000 __udelay:     0 vs my_udelay:   500
  5 usec: LPJ: 1500000 __udelay:  7000 vs my_udelay:  7500

 10 usec: LPJ:  100000 __udelay:     0 vs my_udelay:  1000
 10 usec: LPJ: 1500000 __udelay: 14000 vs my_udelay: 15000

 20 usec: LPJ:  100000 __udelay:  1000 vs my_udelay:  2000
 20 usec: LPJ: 1500000 __udelay: 29000 vs my_udelay: 30000

 50 usec: LPJ:  100000 __udelay:  4000 vs my_udelay:  5000
 50 usec: LPJ: 1500000 __udelay: 74000 vs my_udelay: 75000

100 usec: LPJ:  100000 __udelay:  9000 vs my_udelay: 10000
100 usec: LPJ: 1500000 __udelay: 149000 vs my_udelay: 150000



Here you can see __udelay() fails to be even close to accurate until
~50usec and returns zero for values less then 20usec.

I then went and measured the same udelay() values via rdtsc in the
kernel for both the cyclone based delay() as well as the tsc based
delay. The results are attached in the html file. You'll notice this
closely matches the results from the demo app.

This issue hasn't bitten me before w/ 2.4 because (as you can show w/
the demo app) __const_udelay() is more accurate w/ HZ=100. 

I tried replacing __const_udelay w/ my_delay() but it didn't boot
(overflow issues, I'm guessing). 

So I'm no math wiz. What's the proper fix here? 

thanks
-john

[-- Attachment #2: test.c --]
[-- Type: text/x-c, Size: 1291 bytes --]

#include <stdio.h>

#define MILLION 1000000
#define HZ 1000


unsigned long tsc_freq = 1500000000UL;
unsigned long cyclone_freq = 100000000UL;
unsigned long tsc_lpj = 1500000000UL/HZ;
unsigned long cyclone_lpj = 100000000UL/HZ;
unsigned long LPJ;

unsigned long  __delay(unsigned long loops)
{
	return loops;
}

unsigned long  __const_udelay(unsigned long xloops)
{
	int d0;
	__asm__("mull %0"
		:"=d" (xloops), "=&a" (d0)
		:"1" (xloops),"0" (LPJ));
        return __delay(xloops * HZ);
}

unsigned long  my_udelay(unsigned long usec)
{
	unsigned long cyc_per_usec = (LPJ*HZ)/MILLION;
	return __delay(usec*cyc_per_usec);
}


unsigned long __udelay(unsigned long usecs)
{
	return __const_udelay(usecs * 0x000010c6);  /* 2**32 / 1000000 */
}

unsigned long __ndelay(unsigned long nsecs)
{
	return __const_udelay(nsecs * 0x00005);  /* 2**32 / 1000000000 (rounded up) */
}


int main(void)
{
	unsigned long time[7] = {1,2,5,10,20,50,100};
	int i;
	
	for(i=0;i < 7; i++){
		LPJ=cyclone_lpj;
		printf("%3i usec: LPJ: %7lu __udelay: %5lu vs my_udelay: %5lu\n", 
					time[i], LPJ, __udelay(time[i]), my_udelay(time[i]));
		LPJ=tsc_lpj;
		printf("%3i usec: LPJ: %lu __udelay: %5lu vs my_udelay: %5lu\n", 
					time[i], LPJ, __udelay(time[i]), my_udelay(time[i]));
		printf("\n");
	}

	return 0;
}	

[-- Attachment #3: delay-differences.html.gz --]
[-- Type: application/x-gzip, Size: 1343 bytes --]

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2004-06-15  6:13 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2004-06-05  7:12 Too much error in __const_udelay() ? john stultz
2004-06-05 15:23 ` Dominik Brodowski
2004-06-06 19:46   ` Pavel Machek
2004-06-07 19:12   ` john stultz
2004-06-07 20:27     ` john stultz
2004-06-07 21:20     ` [PATCH 1/3] mull'ify multiplication with HZ in __const_udelay() [Was: Re: Too much error in __const_udelay() ?] Dominik Brodowski
2004-06-07 22:00       ` john stultz
2004-06-15  6:11       ` Dominik Brodowski
2004-06-07 21:22     ` [PATCH 2/3] round up in __udelay() " Dominik Brodowski
2004-06-07 21:23     ` [PATCH 3/3] fix for small xloops " Dominik Brodowski
2004-06-09 10:03       ` Pavel Machek
2004-06-07 21:23     ` Too much error in __const_udelay() ? Dominik Brodowski

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®