On Wed, Jul 05, 2023 at 09:39:00PM -0500, Scott Cheloha wrote:
> glxclk(4) has been compiled-but-disabled for over six months.  It was
> disabled when loongson made the clockintr switch.  Nobody has asked me
> to make it an intrclock option for loongson so I assume the mips64 CP0
> interrupt clock is sufficient.
> 
> This patch deletes the driver, driver config glue, manpage, and
> manpage cross-references.  Not sure if I got it all.  I have no
> system to test this with.
> 
> One thing I noticed: glxclk(4) is compiled into loongson GENERIC but
> not loongson RAMDISK.  A bit odd for a clock interrupt driver, no?  I
> figure you would want to be sure certain such a basic component was
> working during installation, but maybe I'm missing something.
> 
> Anyway, did I get everything?  If so, ok?

I would like to keep the driver and make it functional again. glxclk(4)
provides an external interrupt to the CPU core. With it, it is possible
to stop the core clock when the system is idle and save a little power.
Sadly, the saving is not enough to quieten the fan noise on a Yeeloong.

Below is the glxclk(4) patch that I was tinkering with a while ago.

Index: arch/loongson/dev/glxclk.c
===================================================================
RCS file: src/sys/arch/loongson/dev/glxclk.c,v
retrieving revision 1.8
diff -u -p -r1.8 glxclk.c
--- arch/loongson/dev/glxclk.c  19 Nov 2022 16:23:48 -0000      1.8
+++ arch/loongson/dev/glxclk.c  1 May 2023 14:54:26 -0000
@@ -18,8 +18,10 @@
 
 #include <sys/param.h>
 #include <sys/systm.h>
+#include <sys/clockintr.h>
 #include <sys/device.h>
 #include <sys/kernel.h>
+#include <sys/stdint.h>
 
 #include <machine/bus.h>
 #include <machine/autoconf.h>
@@ -47,30 +49,36 @@ struct cfdriver glxclk_cd = {
 int    glxclk_match(struct device *, void *, void *);
 void   glxclk_attach(struct device *, struct device *, void *);
 int    glxclk_intr(void *);
-int    glxclk_stat_intr(void *arg);
 void   glxclk_startclock(struct cpu_info *);
+void   glxclk_rearm(void *, uint64_t);
+void   glxclk_trigger(void *);
 
 const struct cfattach glxclk_ca = {
        sizeof(struct glxclk_softc), glxclk_match, glxclk_attach,
 };
 
+const struct intrclock glxclk_intrclock = {
+       .ic_rearm       = glxclk_rearm,
+       .ic_trigger     = glxclk_trigger,
+};
+
 #define        MSR_LBAR_ENABLE         0x100000000ULL
 #define        MSR_LBAR_MFGPT          DIVIL_LBAR_MFGPT
 #define        MSR_MFGPT_SIZE          0x40
 #define        MSR_MFGPT_ADDR_MASK     0xffc0
 
+/*
+ * Experience shows that the clock source goes crazy on scale factors
+ * lower than 8, so keep it at 8.
+ */
+
 #define        AMD5536_MFGPT1_CMP2     0x0000000a      /* Compare value for 
CMP2 */
 #define        AMD5536_MFGPT1_CNT      0x0000000c      /* Up counter */
 #define        AMD5536_MFGPT1_SETUP    0x0000000e      /* Setup register */
-#define        AMD5536_MFGPT1_SCALE    0x7             /* Set to 128 */
+#define        AMD5536_MFGPT1_SCALE    0x3             /* Set divider to 8 */
+#define        AMD5536_MFGPT1_CLOCK    (1 << 15)       /* Clock frequency */
 #define        AMD5536_MFGPT1_C2_IRQM  0x00000200
 
-#define        AMD5536_MFGPT2_CMP2     0x00000012      /* Compare value for 
CMP2 */
-#define        AMD5536_MFGPT2_CNT      0x00000014      /* Up counter */
-#define        AMD5536_MFGPT2_SETUP    0x00000016      /* Setup register */
-#define        AMD5536_MFGPT2_SCALE    0x3             /* Divide by 8 */
-#define        AMD5536_MFGPT2_C2_IRQM  0x00000400
-
 #define        AMD5536_MFGPT_CNT_EN    (1 << 15)       /* Enable counting */
 #define        AMD5536_MFGPT_CMP2      (1 << 14)       /* Compare 2 output */
 #define        AMD5536_MFGPT_CMP1      (1 << 13)       /* Compare 1 output */
@@ -82,18 +90,6 @@ const struct cfattach glxclk_ca = {
 
 struct glxclk_softc *glxclk_sc;
 
-/*
- * Statistics clock interval and variance, in usec.  Variance must be a
- * power of two.  Since this gives us an even number, not an odd number,
- * we discard one case and compensate.  That is, a variance of 1024 would
- * give us offsets in [0..1023].  Instead, we take offsets in [1..1023].
- * This is symmetric about the point 512, or statvar/2, and thus averages
- * to that value (assuming uniform random numbers).
- */
-/* XXX fix comment to match value */
-int statvar = 8192;
-int statmin;                   /* statclock interval - 1/2*variance */
-
 int
 glxclk_match(struct device *parent, void *match, void *aux)
 {
@@ -112,10 +108,6 @@ glxclk_attach(struct device *parent, str
        glxclk_sc = (struct glxclk_softc *)self;
        struct glxpcib_attach_args *gaa = aux;
        u_int64_t wa;
-       int statint, minint;
-
-       printf(" not configured\n");
-       return;
 
        glxclk_sc->sc_iot = gaa->gaa_iot;
        glxclk_sc->sc_ioh = gaa->gaa_ioh;
@@ -137,11 +129,10 @@ glxclk_attach(struct device *parent, str
         * MFGPT runs on powers of two, adjust the hz value accordingly.
         */
        stathz = hz = 128;
+       profhz = hz * 10;
        tick = 1000000 / hz;
        tick_nsec = 1000000000 / hz;
 
-       printf(": clock");
-
        /* Set comparator 2 */
        bus_space_write_2(glxclk_sc->sc_iot, glxclk_sc->sc_ioh,
            AMD5536_MFGPT1_CMP2, 1);
@@ -155,8 +146,7 @@ glxclk_attach(struct device *parent, str
         * After they're set the first time all further writes are
         * ignored.
         */
-       uint16_t setup = (AMD5536_MFGPT1_SCALE | AMD5536_MFGPT_CMP2MODE |
-           AMD5536_MFGPT_CMP1 | AMD5536_MFGPT_CMP2 | AMD5536_MFGPT_CNT_EN);
+       uint16_t setup = (AMD5536_MFGPT1_SCALE | AMD5536_MFGPT_CMP2MODE);
 
        bus_space_write_2(glxclk_sc->sc_iot, glxclk_sc->sc_ioh,
            AMD5536_MFGPT1_SETUP, setup);
@@ -182,99 +172,31 @@ glxclk_attach(struct device *parent, str
        wa |= 7 << 20;
        wrmsr(PIC_ZSEL_LOW, wa);
 
-       /* Start the counter */
-       setup = (AMD5536_MFGPT_CNT_EN | AMD5536_MFGPT_CMP2);
-       bus_space_write_2(glxclk_sc->sc_iot, glxclk_sc->sc_ioh,
-           AMD5536_MFGPT1_SETUP, setup);
-
        /*
         * The interrupt argument is NULL in order to notify the dispatcher
         * to pass the clock frame as argument. This trick also forces keeping
-        * the soft state global because during the interrupt we need to clear
-        * the comp2 event in the MFGPT setup register.
+        * the soft state global because during the interrupt we need to
+        * disable the counter in the MFGPT setup register.
         */
-       isa_intr_establish(sys_platform->isa_chipset, 7, IST_PULSE, IPL_CLOCK,
+       isa_intr_establish(sys_platform->isa_chipset, 7, IST_LEVEL, IPL_CLOCK,
            glxclk_intr, NULL, "clock");
 
        md_startclock = glxclk_startclock;
 
-       printf(", prof");
-
-
-       /*
-        * Try to be as close as possible, w/o the variance, to the hardclock.
-        * The stat clock has its source set to the 14MHz clock so that the
-        * variance interval can be more generous. 
-        *
-        * Experience shows that the clock source goes crazy on scale factors
-        * lower than 8, so keep it at 8 and adjust the counter (statint) so
-        * that it results a 128Hz statclock, just like the hardclock.
-        */
-       statint = 16000;
-       minint = statint / 2 + 100;
-       while (statvar > minint)
-               statvar >>= 1;
-
-       /* Set comparator 2 */
-       bus_space_write_2(glxclk_sc->sc_iot, glxclk_sc->sc_ioh,
-           AMD5536_MFGPT2_CMP2, statint);
-       statmin = statint - (statvar >> 1);
-
-       /* Reset counter to 0 */
-       bus_space_write_2(glxclk_sc->sc_iot, glxclk_sc->sc_ioh,
-           AMD5536_MFGPT2_CNT, 0);
-
-       /*
-        * All the bits in the range 11:0 have to be written at once.
-        * After they're set the first time all further writes are
-        * ignored.
-        */
-       setup = (AMD5536_MFGPT2_SCALE | AMD5536_MFGPT_CMP2MODE |
-           AMD5536_MFGPT_CLKSEL | AMD5536_MFGPT_CMP1 | AMD5536_MFGPT_CMP2 |
-           AMD5536_MFGPT_CNT_EN);
-
-       bus_space_write_2(glxclk_sc->sc_iot, glxclk_sc->sc_ioh,
-           AMD5536_MFGPT2_SETUP, setup);
-
-       /* Check to see if the MFGPT_SETUP bit was set */
-       setup = bus_space_read_2(glxclk_sc->sc_iot, glxclk_sc->sc_ioh,
-           AMD5536_MFGPT2_SETUP);
-       if ((setup & AMD5536_MFGPT_SETUP) == 0) {
-               printf(" not configured\n");
-               return;
-       }
-
-       /* Enable MFGPT2 Comparator 2 Output to the Interrupt Mapper */
-       wa = rdmsr(MFGPT_IRQ);
-       wa |= AMD5536_MFGPT2_C2_IRQM;
-       wrmsr(MFGPT_IRQ, wa);
-
-       /*
-        * Tie PIC input 6 to IG8 for glxstat(4).
-        */
-       wa = rdmsr(PIC_ZSEL_LOW);
-       wa &= ~(0xfUL << 24);
-       wa |= 8 << 24;
-       wrmsr(PIC_ZSEL_LOW, wa);
-
-       /*
-        * The interrupt argument is NULL in order to notify the dispatcher
-        * to pass the clock frame as argument. This trick also forces keeping
-        * the soft state global because during the interrupt we need to clear
-        * the comp2 event in the MFGPT setup register.
-        */
-       isa_intr_establish(sys_platform->isa_chipset, 8, IST_PULSE,
-           IPL_STATCLOCK, glxclk_stat_intr, NULL, "prof");
-
        printf("\n");
 }
 
 void
 glxclk_startclock(struct cpu_info *ci)
 {
+       if (CPU_IS_PRIMARY(ci))
+               clockintr_init(CL_RNDSTAT);
+       clockintr_cpu_init(&glxclk_intrclock);
+
        /* Start the clock. */
        int s = splclock();
        ci->ci_clock_started++;
+       clockintr_trigger();
        splx(s);
 }
 
@@ -282,57 +204,44 @@ int
 glxclk_intr(void *arg)
 {
        struct clockframe *frame = arg;
-       uint16_t setup = 0;
        struct cpu_info *ci = curcpu();
+       struct glxclk_softc *sc = glxclk_sc;
 
-       /* Clear the current event */
-       setup = bus_space_read_2(glxclk_sc->sc_iot, glxclk_sc->sc_ioh,
-           AMD5536_MFGPT1_SETUP);
-       setup |= AMD5536_MFGPT_CMP2;
-       bus_space_write_2(glxclk_sc->sc_iot, glxclk_sc->sc_ioh,
-           AMD5536_MFGPT1_SETUP, setup);
+       /* Clear the current event and disable the counter. */
+       bus_space_write_2(sc->sc_iot, sc->sc_ioh, AMD5536_MFGPT1_SETUP,
+           AMD5536_MFGPT_CMP1 | AMD5536_MFGPT_CMP2);
 
        if (ci->ci_clock_started == 0)
                return 1;
 
-       hardclock(frame);
+       clockintr_dispatch(frame);
 
        return 1;
 }
 
-int
-glxclk_stat_intr(void *arg)
+void
+glxclk_rearm(void *cookie, uint64_t nsecs)
 {
-       struct clockframe *frame = arg;
-       uint16_t setup = 0;
-       struct cpu_info *ci = curcpu();
-       u_long newint, r, var;
-
-       /* Clear the current event */
-       setup = bus_space_read_2(glxclk_sc->sc_iot, glxclk_sc->sc_ioh,
-           AMD5536_MFGPT2_SETUP);
-       setup |= AMD5536_MFGPT_CMP2;
-       bus_space_write_2(glxclk_sc->sc_iot, glxclk_sc->sc_ioh,
-           AMD5536_MFGPT2_SETUP, setup);
-
-       if (ci->ci_clock_started == 0)
-               return 1;
-
-       statclock(frame);
-
-       /*
-        * Compute new randomized interval.  The intervals are uniformly
-        * distributed on [statint - statvar / 2, statint + statvar / 2],
-        * and therefore have mean statint, giving a stathz frequency clock.
-        */
-       var = statvar;
-       do {
-               r = random() & (var - 1);
-       } while (r == 0);
-       newint = statmin + r;
-
-       bus_space_write_2(glxclk_sc->sc_iot, glxclk_sc->sc_ioh,
-           AMD5536_MFGPT2_CMP2, newint);
+       const uint64_t freq = AMD5536_MFGPT1_CLOCK >> AMD5536_MFGPT1_SCALE;
+       const uint64_t nsec_ratio = (freq << 32) / 1000000000;
+       const uint64_t nsec_max = UINT64_MAX / nsec_ratio;
+       struct glxclk_softc *sc = glxclk_sc;
+       uint64_t count;
+       register_t sr;
+
+       nsecs = min(nsecs, nsec_max);
+       count = max((nsecs * nsec_ratio) >> 32, 1);
+
+       sr = disableintr();
+       bus_space_write_2(sc->sc_iot, sc->sc_ioh, AMD5536_MFGPT1_CMP2, count);
+       bus_space_write_2(sc->sc_iot, sc->sc_ioh, AMD5536_MFGPT1_CNT, 0);
+       bus_space_write_2(sc->sc_iot, sc->sc_ioh, AMD5536_MFGPT1_SETUP,
+           AMD5536_MFGPT_CNT_EN | AMD5536_MFGPT_CMP2);
+       setsr(sr);
+}
 
-       return 1;
+void
+glxclk_trigger(void *cookie)
+{
+       glxclk_rearm(cookie, 0);
 }

Reply via email to