Port-sparc64 archive

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

Re: Using %stick where available



>>> Michael <macallan%netbsd.org@localhost> wrote

> Hello,
> 
> the attached patch adds support for the system timer interrupt present  
> in UltraSPARC-III and some later II ( like IIe and IIi with on chip  
> ecache ). It hasn't seen much testing beyond 'works on my Blade 2500'.  
> The purpose is to have a timer interrupt / time counter that's  
> independent of the CPU's clock rate, so we can change it without  
> worrying about time keeping.

It looks ok to me, but as Eric reported it needs some fix.


(snip)
> Index: sparc64/clock.c
> ===================================================================
> RCS file: /cvsroot/src/sys/arch/sparc64/sparc64/clock.c,v
> retrieving revision 1.106
> diff -u -w -r1.106 clock.c
> --- sparc64/clock.c   4 Sep 2011 12:17:46 -0000       1.106
> +++ sparc64/clock.c   6 Nov 2012 19:20:24 -0000
> @@ -99,6 +99,7 @@
>   *  counter-timer     timer#0         timer#1         %tick
>   *  counter-timer + SMP       timer#0/%tick   -               timer#1 or 
> %tick
>   *  no counter-timer  %tick           -               %tick
> + *  US-IIIi           %stick          -               %stick
>   */
>  
>  /*
> @@ -137,6 +138,7 @@
>  int timerblurb = 10; /* Guess a value; used before clock is attached */
>  
>  static u_int tick_get_timecount(struct timecounter *);
> +static u_int stick_get_timecount(struct timecounter *);
>  
>  /*
>   * define timecounter "tick-counter"
> @@ -153,6 +155,17 @@
>       NULL                    /* next timecounter */
>  };
>  
> +static struct timecounter stick_timecounter = {
> +     stick_get_timecount,    /* get_timecount */
> +     0,                      /* no poll_pps */
> +     ~0u,                    /* counter_mask */
> +     0,                      /* frequency - set at initialisation */
> +     "stick-counter",        /* name */
> +     100,                    /* quality */
> +     0,                      /* private reference - UNUSED */
> +     NULL                    /* next timecounter */
> +};
> +
>  /*
>   * tick_get_timecount provide current tick counter value
>   */
> @@ -162,6 +175,12 @@
>       return cpu_counter();
>  }
>  
> +static u_int
> +stick_get_timecount(struct timecounter *tc)
> +{
> +     return getstick();
> +}
> +
>  #ifdef MULTIPROCESSOR
>  static u_int counter_get_timecount(struct timecounter *);
>  
> @@ -329,6 +348,27 @@
>       intr_restore(s);
>  }
>  
> +void
> +stickintr_establish(int pil, int (*fun)(void *))
> +{
> +     int s;
> +     struct intrhand *ih;
> +     struct cpu_info *ci = curcpu();
> +
> +     ih = sparc_softintr_establish(pil, fun, NULL);
> +     ih->ih_number = 1;
> +     if (CPU_IS_PRIMARY(ci))
> +             intr_establish(pil, true, ih);
> +     ci->ci_tick_ih = ih;
> +
> +     /* set the next interrupt time */
> +     ci->ci_tick_increment = ci->ci_system_clockrate[0] / hz;
> +
> +     s = intr_disable();
> +     next_stick(ci->ci_tick_increment);
> +     intr_restore(s);
> +}
> +
>  /*
>   * Set up the real-time and statistics clocks.  Leave stathz 0 only if
>   * no alternative timer is available.
> @@ -338,6 +378,7 @@
>  void
>  cpu_initclocks(void)
>  {
> +     struct cpu_info *ci = curcpu();

Replace the following curcpu()s with ci.

>  #ifndef MULTIPROCESSOR
>       int statint, minint;
>  #endif
> @@ -370,8 +411,15 @@
>       /* Initialize the %tick register */
>       settick(0);
>  
> +     if (ci->ci_system_clockrate[0] == 0) {
>       tick_timecounter.tc_frequency = curcpu()->ci_cpu_clockrate[0];
                                        ~~~~~~~~
>       tc_init(&tick_timecounter);
> +     } else {
> +             setstick(0);
> +             stick_timecounter.tc_frequency = 
> +                 curcpu()->ci_system_clockrate[0];
                    ~~~~~~~~
> +             tc_init(&stick_timecounter);
> +     }
>  
>       /*
>        * Now handle machines w/o counter-timers.
> @@ -379,13 +427,21 @@
>  
>       if (!timerreg_4u.t_timer || !timerreg_4u.t_clrintr) {
>  
> -             aprint_normal("No counter-timer -- using %%tick at %luMHz as "
> -                     "system clock.\n",
> +             if (ci->ci_system_clockrate[0] == 0) {
> +                     aprint_normal("No counter-timer -- using %%tick "
> +                         "at %luMHz as system clock.\n",
>                       (unsigned long)curcpu()->ci_cpu_clockrate[1]);
                                       ~~~~~~~~
>  
>               /* We don't have a counter-timer -- use %tick */
>               tickintr_establish(PIL_CLOCK, tickintr);
> +             } else {
> +                     aprint_normal("No counter-timer -- using %%stick "
> +                         "at %luMHz as system clock.\n",
> +                         (unsigned long)curcpu()->ci_system_clockrate[1]);
                                           ~~~~~~~~
>  
> +                     /* We don't have a counter-timer -- use %tick */
> +                     stickintr_establish(PIL_CLOCK, stickintr);
> +             }
>               /* We only have one timer so we have no statclock */
>               stathz = 0;
>  
> @@ -525,6 +581,22 @@
>       return (1);
>  }
>  
> +int
> +stickintr(void *cap)
> +{
> +     int s;
> +
> +     hardclock((struct clockframe *)cap);
> +
> +     s = intr_disable();
> +     /* Reset the interrupt */
> +     next_stick(curcpu()->ci_tick_increment);
> +     intr_restore(s);
> +     curcpu()->ci_tick_evcnt.ev_count++;
> +
> +     return (1);
> +}
> +
>  #ifndef MULTIPROCESSOR
>  /*
>   * Level 14 (stat clock) interrupt handler.
> Index: sparc64/cpu.c
> ===================================================================
> RCS file: /cvsroot/src/sys/arch/sparc64/sparc64/cpu.c,v
> retrieving revision 1.102
> diff -u -w -r1.102 cpu.c
> --- sparc64/cpu.c     27 Oct 2012 17:18:12 -0000      1.102
> +++ sparc64/cpu.c     6 Nov 2012 19:20:24 -0000
> @@ -250,7 +250,7 @@
>       int bigcache, cachesize;
>       char buf[100];
>       int     totalsize = 0;
> -     int     linesize, dcachesize, icachesize;
> +     int     linesize, dcachesize, icachesize, sclk;

I think the following is better for consistency.

-       long clk;
+       long clk, sclk;

>  
>       /* tell them what we have */
>       node = ma->ma_node;
> @@ -299,12 +299,21 @@
>               ci->ci_cpu_clockrate[1] = clk / 1000000;
>       }
>  
> +     sclk = prom_getpropint(findroot(), "stick-frequency", 0);
> +     ci->ci_system_clockrate[0] = sclk;
> +     ci->ci_system_clockrate[1] = sclk / 1000000;

US-IIe has system tick register, but its implementation is
different to US-III one.  It can be used via memory mapped system
registers, not via ancillary state register (%asr24).

So, I suggest not to use it on US-IIe as below.

        if (!CPU_IS_HUMMINGBIRD()) {
                sclk = prom_getpropint(findroot(), "stick-frequency", 0);
                ci->ci_system_clockrate[0] = sclk;
                ci->ci_system_clockrate[1] = sclk / 1000000;
        }

And, put the following into include/psl.h.

#define CPU_IS_HUMMINGBIRD()    (GETVER_CPU_IMPL() == IMPL_HUMMINGBIRD)


> +
>       snprintf(buf, sizeof buf, "%s @ %s MHz",
>               prom_getpropstring(node, "name"), clockfreq(clk));
>       snprintf(cpu_model, sizeof cpu_model, "%s (%s)", machine_model, buf);
>  
>       aprint_normal(": %s, UPA id %d\n", buf, ci->ci_cpuid);
>       aprint_naive("\n");
> +
> +     if (ci->ci_system_clockrate[0] != 0) {
> +             aprint_normal_dev(dev, "system tick frequency %d MHz\n", 
> +                 (int)ci->ci_system_clockrate[1]);
> +     }
>       aprint_normal_dev(dev, "");
>  
>       bigcache = 0;
> @@ -452,6 +461,8 @@
>               sync_tick = 1;
>               membar_Sync();
>               settick(0);
> +             if (ci->ci_system_clockrate[0] != 0)
> +                     setstick(0);
>  
>               setpstate(pstate);
>  
> @@ -480,8 +491,12 @@
>               /* we do nothing here */
>       }
>       settick(0);
> -
> +     if (curcpu()->ci_system_clockrate[0] != 0) {
> +             setstick(0);
> +             stickintr_establish(PIL_CLOCK, stickintr);
> +     } else {
>       tickintr_establish(PIL_CLOCK, tickintr);
> +     }
>       spl0();
>  }
>  #endif /* MULTIPROCESSOR */
> Index: sparc64/genassym.cf
> ===================================================================
> RCS file: /cvsroot/src/sys/arch/sparc64/sparc64/genassym.cf,v
> retrieving revision 1.66
> diff -u -w -r1.66 genassym.cf
> --- sparc64/genassym.cf       20 Jul 2011 12:06:00 -0000      1.66
> +++ sparc64/genassym.cf       6 Nov 2012 19:20:24 -0000
> @@ -157,6 +157,7 @@
>  define       CI_NFAULT       offsetof(struct cpu_info, ci_data.cpu_nfault)
>  define       CI_NINTR        offsetof(struct cpu_info, ci_data.cpu_nintr)
>  define       CI_CLOCKRATE    offsetof(struct cpu_info, ci_cpu_clockrate)
> +define       CI_SYSCLOCKRATE offsetof(struct cpu_info, ci_system_clockrate)
>  define       CI_IDEPTH       offsetof(struct cpu_info, ci_idepth)
>  define       CI_INTRPENDING  offsetof(struct cpu_info, ci_intrpending)
>  define       CI_TICK_IH      offsetof(struct cpu_info, ci_tick_ih)

CI_SYSCLOCKRATE is unused.


> Index: sparc64/locore.s
> ===================================================================
> RCS file: /cvsroot/src/sys/arch/sparc64/sparc64/locore.s,v
> retrieving revision 1.341
> diff -u -w -r1.341 locore.s
> --- sparc64/locore.s  17 Mar 2012 22:19:53 -0000      1.341
> +++ sparc64/locore.s  6 Nov 2012 19:20:25 -0000
> @@ -3270,13 +3270,18 @@
>       wrpr    %g0, PSTATE_KERN|PSTATE_IG, %pstate     ! DEBUG
>  #endif
>       /*
> -      * If this is a %tick softint, clear it then call interrupt_vector.
> +      * If this is a %tick or %stick softint, clear it then call
> +      * interrupt_vector. Only one of them should be enabled at any given
> +      * time.
>        */
>       rd      SOFTINT, %g1
> -     btst    1, %g1
> +     mov     1, %g5
> +     sllx    %g5, 16, %g3
> +     or      %g5, %g3, %g5
> +     andcc   %g5, %g1, %g5
>       bz,pt   %icc, 0f
>        sethi  %hi(CPUINFO_VA+CI_TICK_IH), %g3
> -     wr      %g0, 1, CLEAR_SOFTINT
> +     wr      %g0, %g5, CLEAR_SOFTINT
>       ba,pt   %icc, setup_sparcintr
>        LDPTR  [%g3 + %lo(CPUINFO_VA+CI_TICK_IH)], %g5
>  0:
> @@ -6058,6 +6063,93 @@
>        wr     %o2, TICK_CMPR
>  #endif
>  
> +/*
> + * setstick(long)
> + */
> +ENTRY(setstick)
> +     retl
> +      wr %o0, STICK
> +
> +/*
> + * long getstick(void)
> + */
> +ENTRY(getstick)
> +     retl
> +      rd STICK, %o0

I'll replace them with inline functions like settick/gettick after
you commited.


> +
> +/*
> + * next_stick(long increment)
> + *
> + * Sets the %stick_cmpr register to fire off in `increment' machine
> + * cycles in the future.  Also handles %stick wraparound.  In 32-bit
> + * mode we're limited to a 32-bit increment.
> + */
> +ENTRY(next_stick)
> +     rd      STICK_CMPR, %o2
> +     rd      STICK, %o1
> +
> +     mov     1, %o3          ! Mask off high bits of these registers
> +     sllx    %o3, 63, %o3
> +     andn    %o1, %o3, %o1
> +     andn    %o2, %o3, %o2
> +     cmp     %o1, %o2        ! Did we wrap?  (tick < tick_cmpr)
> +     bgt,pt  %icc, 1f
> +      add    %o1, 1000, %o1  ! Need some slack so we don't lose intrs.
> +
> +     /*
> +      * Handle the unlikely case of %stick wrapping.
> +      *
> +      * This should only happen every 10 years or more.
> +      *
> +      * We need to increment the time base by the size of %stick in
> +      * microseconds.  This will require some divides and multiplies
> +      * which can take time.  So we re-read %stick.
> +      *
> +      */
> +
> +     /* XXXXX NOT IMPLEMENTED */
> +
> +
> +
> +1:
> +     add     %o2, %o0, %o2
> +     andn    %o2, %o3, %o4
> +     brlz,pn %o4, Lstick_ovflw
> +      cmp    %o2, %o1        ! Has this stick passed?
> +     blt,pn  %xcc, 1b        ! Yes
> +      nop
> +
> +#ifdef BB_ERRATA_1
> +     ba,a    2f
> +      nop
> +#else
> +     retl
> +      wr     %o2, STICK_CMPR
> +#endif
> +
> +Lstick_ovflw:
> +/*
> + * When we get here tick_cmpr has wrapped, but we don't know if %stick
> + * has wrapped.  If bit 62 is set then we have not wrapped and we can
> + * use the current value of %o4 as %stick.  Otherwise we need to return
> + * to our loop with %o4 as %stick_cmpr (%o2).
> + */
> +     srlx    %o3, 1, %o5
> +     btst    %o5, %o1
> +     bz,pn   %xcc, 1b
> +      mov    %o4, %o2
> +#ifdef BB_ERRATA_1
> +     ba,a    2f
> +      nop
> +     .align  64
> +2:   wr      %o2, STICK_CMPR
> +     rd      STICK_CMPR, %g0
> +     retl
> +      nop
> +#else
> +     retl
> +      wr     %o2, STICK_CMPR
> +#endif
>  
>  ENTRY(setjmp)
>       save    %sp, -CC64FSZ, %sp      ! Need a frame to return to.

BB_ERRATA_1 is an errata of US-II, so #ifdef BB_ERRATA_1 cases are
unnecessary.


-- Takeshi Nakayama


Home | Main Index | Thread Index | Old Index