On Tue, Aug 09, 2022 at 09:54:02AM -0500, Scott Cheloha wrote:
> 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.

The machines completed a build with this patch without problems.
I tested with the debug counters removed from cp0_trigger_int5().

OK visa@

> 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