tech-kern archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: 4.0/i386 auich_calibrate() and GENERIC.NOACPI failure



> On Sat, Jan 12, 2008 at 11:07:51AM -0500, Chuck Cranor wrote:
> > The i8254 may be slow, but it seemed to work just fine before this...?
> > 
> > At any rate, Joerg suggested I put the auich_calibrate() loop in an 
> > splvm(), so I did that plus your curcpu()->ci_ilevel suggestion.   
> > The results:
> > 
> >  1. splvm() didn't help
> >  2. splclock() _did_ fix the problem!
> >  3. the value of curcpu()->ci_ilevel is 0 (zero) before the loop.
> >     Are you sure we are supposed to be at IPL_HIGH?   I thought zero
> >     was IPL_NONE?


hi- 

    I did even more debugging and I think I discovered the root cause
to this timer problem!!   The spl() thing turned out to be a symptom
of the problem rather than the cause.


    The problem was inadverently introduced in 1.98 of 
src/sys/arch/i386/isa/clock.c when the variable "clkintr_pending"
was removed because it was "unused" ... that's not really true.
It was always zero (because it was never set) thus permanently
short-circuited out part of an if statement in the function
i8254_get_timecount():

@@ -195,8 +195,6 @@
 
 static inline int gettick_broken_latch(void);
 
-int clkintr_pending;
-
 static volatile uint32_t i8254_lastcount;
 static volatile uint32_t i8254_offset;
 static volatile int i8254_ticked;
@@ -434,7 +432,7 @@
        high = inb(IO_TIMER1 + TIMER_CNTR0);
        count = rtclock_tval - ((high << 8) | low);
 
-       if (rtclock_tval && (count < i8254_lastcount || (!i8254_ticked && 
clkintr_pending))) {
+       if (rtclock_tval && (count < i8254_lastcount || !i8254_ticked)) {
                i8254_ticked = 1;
                i8254_offset += rtclock_tval;
        }



Since clkintr_pending is always zero, what really happened here was that
the "if" statement changed from:

OLD:  if (rtclock_tval && count < i8254_lastcount) {

NEW:  if (rtclock_tval && (count < i8254_lastcount || !i8254_ticked)) {



To test this, I checked out a source tree from 2006.09.03.20.00.00 
(auich works properly), and then rolled clock.c forward from 1.97 to
1.98 (auich fails).


Furthermore, if you take a netbsd-4-0-RELEASE source tree, patch 
src/sys/arch/x86/isa/clock.c like this:

--- clock.c_ORIG        2008-01-14 16:30:01.000000000 -0500
+++ clock.c     2008-01-14 16:30:31.000000000 -0500
@@ -439,7 +439,7 @@
        high = inb(IO_TIMER1 + TIMER_CNTR0);
        count = rtclock_tval - ((high << 8) | low);
 
-       if (rtclock_tval && (count < i8254_lastcount || !i8254_ticked)) {
+       if (rtclock_tval && (count < i8254_lastcount /*|| !i8254_ticked*/)) {
                i8254_ticked = 1;
                i8254_offset += rtclock_tval;
        }


and compile a GENERIC.NOACPI with that change, then the auich_calibrate()
probe works just fine:

auich0 at pci0 dev 31 function 5: i82801BA (ICH2) AC-97 Audio
auich0: interrupting at irq 10
auich0: ac97: Analog Devices AD1885 codec; headphone, Analog Devices Phat Stereo
auich0: ac97: ext id 1<VRA>
auich0: measured ac97 link rate at 55071 Hz, will use 55000 Hz
audio0 at auich0: full duplex, mmap, independent



My theory on the spls is that they were blocking rtclock_tval and 
friends from being used during the test, so it masked out both
the interrupts and the bug (?).


So, do we need !i8254_ticked?


chuck



Home | Main Index | Thread Index | Old Index