On Tue, Aug 09, 2022 at 02:03:31PM +0000, Visa Hankala wrote:
> On Mon, Aug 08, 2022 at 02:52:37AM -0500, Scott Cheloha wrote:
> > One thing I'm still uncertain about is how glxclk fits into the
> > loongson picture.  It's an interrupt clock that runs hardclock() and
> > statclock(), but the code doesn't do any logical masking, so I don't
> > know whether or not I need to adjust anything in that code or account
> > for it at all.  If there's no logical masking there's no deferral, so
> > it would never call need to call md_triggerclock() from splx(9).
> 
> I think the masking of glxclk interrupts are handled by the ISA
> interrupt code.

Do those machines not have Coprocessor 0?  If they do, why would you
prefer glxclk over CP0?

> The patch misses md_triggerclock definition in mips64_machdep.c.

Whoops, forgot that file.  Fuller patch below.

> I have put this to the test on the mips64 ports builder machines.

Cool, thank you for testing.

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