Subject: Re: kernel sources?

From: "Kevin D. Kissell" <[email-masked]>
Date: Sat, 15 Jan 2000 18:28:40 +0100

-----Original Message-----
From: Ralf Baechle <[email-masked]>
To: Geert Uytterhoeven <[email-masked]>
Cc: Linux/MIPS <[email-masked]>
Date: Saturday, January 15, 2000 1:56 AM
Subject: Re: kernel sources?

>On Thu, Jan 13, 2000 at 05:03:39PM +0100, Geert Uytterhoeven wrote:
>
>> I used the R5000 CP0_COUNTER/CP0_COMPARE registers for the timer interrupt. I
>> know it's not accurate, but it's better than nothing. I still have to figure
>> out how more complex interrupts work in the MIPS source tree.
>
>It is accurate as driven by the CPU's clock.  It is just somewhat tricky to
>handle and even more tricky on some broken CPUs.  From an old email written
>by Bill Earl:
>
>[...]
>As far as I know, all R4000 processors, and possibly some R4400 processors,
>are affected.  The bug is that, if you read $count exactly when it equals
>$compare, the count/compare interrupt for that count/compare crossing is
>discarded.  The workaround from IRIX is appended.  The variable
>r4000_clock_war is set to 1 if the system is an Indy with an R4000 processor.
>The r4k_compare_shadow is set to the same value as $compare whenever $compare
>is updated (with interrupts masked while the variable and $compare are
>updated together).
>[...]

There is also a race condition inherent in many implementations of
the timer interrupt handler, and the main stream of the current
MIPS/Linux distributions is no exception.   The SGI code looks
a bit like this:

void indy_timer_interrupt(struct pt_regs *regs)
{
        unsigned long count;
        int irq = 7;

        /* Ack timer and compute new compare. */
        count = read_32bit_cp0_register(CP0_COUNT);
        /* This has races.  */
        if ((count - r4k_cur) >= r4k_offset) {
                /* If this happens to often we'll need to compensate.  */
                missed_heart_beats++;
                r4k_cur = count + r4k_offset;
        }
        else
            r4k_cur += r4k_offset;
        ack_r4ktimer(r4k_cur);
        kstat.irqs[0][irq]++;
        do_timer(regs);

        /* We update the Dallas time of day approx. every 11 minutes,
         * because of how the numbers work out we need to make
         * absolutely sure we do this update within 500ms before the
         * next second starts, thus the following code.
         */
        if ((time_status & STA_UNSYNC) == 0 &&
            xtime.tv_sec > last_rtc_update + 660 &&
            xtime.tv_usec >= 500000 - (tick >> 1) &&
            xtime.tv_usec <= 500000 + (tick >> 1)) {
                if (set_rtc_mmss(xtime.tv_sec) == 0)
                        last_rtc_update = xtime.tv_sec;
                else
                        /* do it again in 60 s */
                        last_rtc_update = xtime.tv_sec - 600;
        }
}

The inherent race is in the fact that the count is sampled
once at the beginnning of the routine and used throughout.
It is possible (with bad luck and sloppy drivers) to be very
late into the handler, so much so that the new time-out time
can be reached between the sample and the programming
of the compare register.  If that happens, one gets no timer
interrupt for a full wrap of the count register.   I first observed
this in OpenBSD, where the problem was worse, but Linux
has the same conceptual hole.  A more robust handler
looks a bit like this:

void p5064_timer_interrupt(struct pt_regs *regs)
{
        int irq = 7;

        if(r4k_offset != 0) {
                do {
                        kstat.irqs[0][irq]++;
                        do_timer(regs);

                        /* Historical comment/code:
                        * RTC time of day s updated approx. every 11
                        * minutes.  Because of how the numbers work out
                        * we need to make absolutely sure we do this update
                        * within 500ms before the * next second starts,
                        * thus the following code.
                        */
                        if ((time_status & STA_UNSYNC) == 0
                        && xtime.tv_sec > last_rtc_update + 660
                        && xtime.tv_usec >= 500000 - (tick >> 1)
                        && xtime.tv_usec <= 500000 + (tick >> 1))
                            if (set_rtc_mmss(xtime.tv_sec) == 0)
                                last_rtc_update = xtime.tv_sec;
                            else
                                /* do it again in 60 s */
                                last_rtc_update = xtime.tv_sec - 600;

                        r4k_cur += r4k_offset;
                        ack_r4ktimer(r4k_cur);
                } while (((unsigned long)read_32bit_cp0_register(CP0_COUNT)
                        - r4k_cur) < 0x7fffffff);
        } else ack_r4ktimer(0);
}

As Ralf says, it's very accurate *if* you have an accurate picture of
the CPU's clock frequency.  The usual mechanism of measuring
the progress of the count register against elapsed time on a TOD
clock has been known to be inaccurate on some platforms due
to skew between the visibility to software and the actual timing
event, so be careful.

            Kevin K.
__

Kevin D. Kissell
MIPS Technologies European Architecture Lab
[email-masked]
Tel. +33.4.78.38.70.67
FAX. +33.4.78.38.70.68

---

From: Richard Dubrawsk <[email-masked]>
Date: Sat, 15 Jan 2000 14:06:09 -0600 (CST)

Hi all, I have just successfully installed the hardhat distro on 2 sgi
indy machines, and have been reading everything I can find to get up to
speed on the port.  The web pages seem terribly out of date.  Could you
point me to some information about the current state of things.  I have
scanned the archive of this mailing list, but it is hard to get a feel for
things from such disjoint information.
I have been using linux since 1995, mostly on intel, and recently have
been maintinaing several LinuxPPC and UltraLinux machines.  I would like
to assist in the SGI port as time permits.  My first desire is updated
tools.  According to what I can find, there is not currently recent enough
tools available to support the 2.2.x series of kernels, I assume that is
not correct since I see indication that people are running 2.2.x kernels.
wheree can I find the latest stable(?) (reasonably stable?) versions of
libraries and compilers, etc.
Thank you

Richard Dubrawski

University of Illinois 
Urbana-Champaign

(web page: http://www.students.uiuc.edu/~dubrawsk/)

---

From: Ralf Baechle <[email-masked]>
Date: Sun, 16 Jan 2000 02:20:45 +0100

> to skew between the visibility to software and the actual timing

The only machine where we actually calibrate the CPU counter is the Indy
where due to a hardware bug we cannot use the external timers as source
of interrupts.

In fact the current Linux kernel would even panic if it ever would find
an Indy working as per spec ;-)

We could improve that meassurement by rounding to the nearest crystal
known to be used on IP22 CPU modules plus maybe add an eventual user /
xntpd suplied fudge factor for deviations of the exact crystal frequency.

  Ralf

---

From: Geert Uytterhoeven <[email-masked]>
Date: Sun, 16 Jan 2000 13:32:46 +0100 (CET)

[...]

> has the same conceptual hole.  A more robust handler

I noticed this as well, especially if I put serial debug code in the interrupt
handler. Then it's safer to always reset count to 0 in the interrupt handler.
Of course it's very inaccurate then, but at least you keep on getting
interrupts in a reasonable time frame.

Now I'm using one of the timers in the host bridge to generate the actual timer
interrupt, which seems to work fine. I could also use the normal PC RTC, but
then I have to get the i8259 interrupts working first. Fortunately PCI
interrupts are handled by the host bridge as well, so I see no hurry in getting
the i8259 interrupts working too soon :-)

Gr{oetje,eeting}s,
--
Geert Uytterhoeven -- Linux/{m68k~Amiga,PPC~CHRP} -- [email-masked]

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
							    -- Linus Torvalds