On Tue, Aug 09, 2022 at 06:02:10PM +0000, Miod Vallat wrote:
> > Other platforms (architectures?) (powerpc, powerpc64, arm64, riscv64)
> > multiplex their singular interrupt clock to schedule both a
> > fixed-period hardclock and a pseudorandom statclock.
> > 
> > This is the direction I intend to take every platform, mips64
> > included, after the next release.
> > 
> > In that context, would there be any reason to prefer glxclk to
> > CP0.count?
> 
> No. The cop0 timer is supposed to be the most reliable timer available.
> (although one may argue that, on sgi, the xbow timer on some systems is
> even better quality)

Alright, got it.  If glxclk provides no other utility aside from an
interrupt clock on loongson, then you and I can coordinate unhooking
it when we switch loongson to the new clockintr code in the Fall.

If I'm missing something and it does other work, then nevermind.

Does the latest patch work on any loongson machines you have?

I didn't see any other splx(9) implementations aside from bonito and
the one for loongson3.

Index: mips64/mips64/clock.c
===================================================================
RCS file: /cvs/src/sys/arch/mips64/mips64/clock.c,v
retrieving revision 1.45
diff -u -p -r1.45 clock.c
--- mips64/mips64/clock.c       6 Apr 2022 18:59:26 -0000       1.45
+++ mips64/mips64/clock.c       9 Aug 2022 14:48:47 -0000
@@ -60,6 +60,7 @@ const struct cfattach clock_ca = {
 };
 
 void   cp0_startclock(struct cpu_info *);
+void   cp0_trigger_int5(void);
 uint32_t cp0_int5(uint32_t, struct trapframe *);
 
 int
@@ -86,19 +87,20 @@ clockattach(struct device *parent, struc
        cp0_set_compare(cp0_get_count() - 1);
 
        md_startclock = cp0_startclock;
+       md_triggerclock = cp0_trigger_int5;
 }
 
 /*
  *  Interrupt handler for targets using the internal count register
  *  as interval clock. Normally the system is run with the clock
  *  interrupt always enabled. Masking is done here and if the clock
- *  can not be run the tick is just counted and handled later when
- *  the clock is logically unmasked again.
+ *  cannot be run the tick is handled later when the clock is logically
+ *  unmasked again.
  */
 uint32_t
 cp0_int5(uint32_t mask, struct trapframe *tf)
 {
-       u_int32_t clkdiff;
+       u_int32_t clkdiff, pendingticks = 0;
        struct cpu_info *ci = curcpu();
 
        /*
@@ -113,15 +115,26 @@ cp0_int5(uint32_t mask, struct trapframe
        }
 
        /*
+        * If the clock interrupt is masked, defer any work until it
+        * is unmasked from splx(9).
+        */
+       if (tf->ipl >= IPL_CLOCK) {
+               ci->ci_clock_deferred = 1;
+               cp0_set_compare(cp0_get_count() - 1);
+               return CR_INT_5;
+       }
+       ci->ci_clock_deferred = 0;
+
+       /*
         * Count how many ticks have passed since the last clock interrupt...
         */
        clkdiff = cp0_get_count() - ci->ci_cpu_counter_last;
        while (clkdiff >= ci->ci_cpu_counter_interval) {
                ci->ci_cpu_counter_last += ci->ci_cpu_counter_interval;
                clkdiff = cp0_get_count() - ci->ci_cpu_counter_last;
-               ci->ci_pendingticks++;
+               pendingticks++;
        }
-       ci->ci_pendingticks++;
+       pendingticks++;
        ci->ci_cpu_counter_last += ci->ci_cpu_counter_interval;
 
        /*
@@ -132,32 +145,64 @@ cp0_int5(uint32_t mask, struct trapframe
        clkdiff = cp0_get_count() - ci->ci_cpu_counter_last;
        if ((int)clkdiff >= 0) {
                ci->ci_cpu_counter_last += ci->ci_cpu_counter_interval;
-               ci->ci_pendingticks++;
+               pendingticks++;
                cp0_set_compare(ci->ci_cpu_counter_last);
        }
 
        /*
-        * Process clock interrupt unless it is currently masked.
+        * Process clock interrupt.
         */
-       if (tf->ipl < IPL_CLOCK) {
 #ifdef MULTIPROCESSOR
-               register_t sr;
+       register_t sr;
 
-               sr = getsr();
-               ENABLEIPI();
+       sr = getsr();
+       ENABLEIPI();
 #endif
-               while (ci->ci_pendingticks) {
-                       atomic_inc_long(
-                           (unsigned long *)&cp0_clock_count.ec_count);
-                       hardclock(tf);
-                       ci->ci_pendingticks--;
-               }
+       while (pendingticks) {
+               atomic_inc_long((unsigned long *)&cp0_clock_count.ec_count);
+               hardclock(tf);
+               pendingticks--;
+       }
 #ifdef MULTIPROCESSOR
-               setsr(sr);
+       setsr(sr);
 #endif
-       }
 
        return CR_INT_5;        /* Clock is always on 5 */
+}
+
+unsigned long cp0_raise_calls, cp0_raise_miss;
+
+/*
+ * Trigger the clock interrupt.
+ * 
+ * We need to spin until either (a) INT5 is pending or (b) the compare
+ * register leads the count register, i.e. we know INT5 will be pending
+ * very soon.
+ *
+ * To ensure we don't spin forever, double the compensatory offset
+ * added to the compare value every time we miss the count register.
+ */
+void
+cp0_trigger_int5(void)
+{
+       uint32_t compare, offset = 16;
+       int leading = 0;
+       register_t sr;
+
+       sr = disableintr();
+       while (!leading && !ISSET(cp0_get_cause(), CR_INT_5)) {
+               compare = cp0_get_count() + offset;
+               cp0_set_compare(compare);
+               leading = (int32_t)(compare - cp0_get_count()) > 0;
+               offset *= 2;
+       }
+       setsr(sr);
+
+       unsigned long misses = 0;
+       for (; offset > 32; offset /= 2)
+               misses++;
+       atomic_add_long(&cp0_raise_miss, misses);
+       atomic_inc_long(&cp0_raise_calls);
 }
 
 /*
Index: mips64/mips64/cp0access.S
===================================================================
RCS file: /cvs/src/sys/arch/mips64/mips64/cp0access.S,v
retrieving revision 1.23
diff -u -p -r1.23 cp0access.S
--- mips64/mips64/cp0access.S   1 May 2021 16:11:11 -0000       1.23
+++ mips64/mips64/cp0access.S   9 Aug 2022 14:48:47 -0000
@@ -198,3 +198,10 @@ LEAF(cpu_rnd_messybits, 0)
        j       ra
         NOP
 END(cpu_rnd_messybits)
+
+LEAF(cp0_get_cause, 0)
+       MFC0    v0, COP_0_CAUSE_REG
+       MFC0_HAZARD
+       j       ra
+        NOP
+END(cp0_get_cause)
Index: mips64/mips64/mips64_machdep.c
===================================================================
RCS file: /cvs/src/sys/arch/mips64/mips64/mips64_machdep.c,v
retrieving revision 1.37
diff -u -p -r1.37 mips64_machdep.c
--- mips64/mips64/mips64_machdep.c      1 May 2021 16:11:11 -0000       1.37
+++ mips64/mips64/mips64_machdep.c      9 Aug 2022 14:48:48 -0000
@@ -219,6 +219,7 @@ tlb_asid_wrap(struct cpu_info *ci)
  */
 
 void (*md_startclock)(struct cpu_info *);
+void (*md_triggerclock)(void);
 
 extern todr_chip_handle_t todr_handle;
 
Index: mips64/include/cpu.h
===================================================================
RCS file: /cvs/src/sys/arch/mips64/include/cpu.h,v
retrieving revision 1.138
diff -u -p -r1.138 cpu.h
--- mips64/include/cpu.h        28 Jan 2022 16:20:09 -0000      1.138
+++ mips64/include/cpu.h        9 Aug 2022 14:48:48 -0000
@@ -178,11 +178,10 @@ struct cpu_info {
        volatile int    ci_ipl;                 /* software IPL */
        uint32_t        ci_softpending;         /* pending soft interrupts */
        int             ci_clock_started;
+       volatile int    ci_clock_deferred;      /* clock interrupt postponed */
        u_int32_t       ci_cpu_counter_last;    /* last compare value loaded */
        u_int32_t       ci_cpu_counter_interval; /* # of counter ticks/tick */
 
-       u_int32_t       ci_pendingticks;
-
        struct pmap     *ci_curpmap;
        uint            ci_intrdepth;           /* interrupt depth */
 #ifdef MULTIPROCESSOR
@@ -258,6 +257,7 @@ void        smp_rendezvous_cpus(unsigned long, 
 #define CPU_BUSY_CYCLE()       do {} while (0)
 
 extern void (*md_startclock)(struct cpu_info *);
+extern void (*md_triggerclock)(void);
 void   cp0_calibrate(struct cpu_info *);
 
 unsigned int cpu_rnd_messybits(void);
@@ -447,6 +447,7 @@ register_t disableintr(void);
 register_t getsr(void);
 register_t setsr(register_t);
 
+uint32_t cp0_get_cause(void);
 u_int  cp0_get_count(void);
 register_t cp0_get_config(void);
 uint32_t cp0_get_config_1(void);
Index: octeon/dev/octcit.c
===================================================================
RCS file: /cvs/src/sys/arch/octeon/dev/octcit.c,v
retrieving revision 1.12
diff -u -p -r1.12 octcit.c
--- octeon/dev/octcit.c 1 Sep 2019 12:16:01 -0000       1.12
+++ octeon/dev/octcit.c 9 Aug 2022 14:48:48 -0000
@@ -489,6 +489,10 @@ octcit_splx(int newipl)
                (void)CIU3_RD_8(sc, CIU3_IDT_PP(CIU3_IDT(core, 0)));
        }
 
+       /* Trigger deferred clock interrupt if it is now unmasked. */
+       if (ci->ci_clock_deferred && newipl < IPL_CLOCK)
+               md_triggerclock();
+
        /* If we still have softints pending trigger processing. */
        if (ci->ci_softpending != 0 && newipl < IPL_SOFTINT)
                setsoftintr0();
Index: octeon/dev/octciu.c
===================================================================
RCS file: /cvs/src/sys/arch/octeon/dev/octciu.c,v
retrieving revision 1.17
diff -u -p -r1.17 octciu.c
--- octeon/dev/octciu.c 1 Sep 2019 12:16:01 -0000       1.17
+++ octeon/dev/octciu.c 9 Aug 2022 14:48:48 -0000
@@ -588,6 +588,10 @@ octciu_splx(int newipl)
                    scpu->scpu_ibank[2].en,
                    scpu->scpu_intem[2] & ~scpu->scpu_imask[newipl][2]);
 
+       /* Trigger deferred clock interrupt if it is now unmasked. */
+       if (ci->ci_clock_deferred && newipl < IPL_CLOCK)
+               md_triggerclock();
+
        /* If we still have softints pending trigger processing. */
        if (ci->ci_softpending != 0 && newipl < IPL_SOFTINT)
                setsoftintr0();
Index: loongson/dev/bonito.c
===================================================================
RCS file: /cvs/src/sys/arch/loongson/dev/bonito.c,v
retrieving revision 1.35
diff -u -p -r1.35 bonito.c
--- loongson/dev/bonito.c       11 Mar 2021 11:16:57 -0000      1.35
+++ loongson/dev/bonito.c       9 Aug 2022 14:48:48 -0000
@@ -485,6 +485,11 @@ bonito_splx(int newipl)
        /* Update masks to new ipl. Order highly important! */
        ci->ci_ipl = newipl;
        bonito_setintrmask(newipl);
+
+       /* Trigger deferred clock interrupt if it is now unmasked. */
+       if (ci->ci_clock_deferred && newipl < IPL_CLOCK)
+               md_triggerclock();
+
        /* If we still have softints pending trigger processing. */
        if (ci->ci_softpending != 0 && newipl < IPL_SOFTINT)
                setsoftintr0();
Index: loongson/loongson/loongson3_intr.c
===================================================================
RCS file: /cvs/src/sys/arch/loongson/loongson/loongson3_intr.c,v
retrieving revision 1.7
diff -u -p -r1.7 loongson3_intr.c
--- loongson/loongson/loongson3_intr.c  24 Feb 2018 11:42:31 -0000      1.7
+++ loongson/loongson/loongson3_intr.c  9 Aug 2022 14:48:48 -0000
@@ -355,6 +355,10 @@ loongson3_splx(int newipl)
                REGVAL(LS3_IRT_INTENSET(0)) =
                    loongson3_intem & ~loongson3_imask[newipl];
 
+       /* Trigger deferred clock interrupt if it is now unmasked. */
+       if (ci->ci_clock_deferred && newipl < IPL_CLOCK)
+               md_triggerclock();
+
        if (ci->ci_softpending != 0 && newipl < IPL_SOFTINT)
                setsoftintr0();
 }

Reply via email to