i386/lapic.c: sync with amd64/lapic.c
authorcheloha <cheloha@openbsd.org>
Tue, 6 Sep 2022 17:26:27 +0000 (17:26 +0000)
committercheloha <cheloha@openbsd.org>
Tue, 6 Sep 2022 17:26:27 +0000 (17:26 +0000)
In anticipation of merging the new clock interrupt code after release,
let's synchronize the lapic timer parts of i386's lapic.c with those
of amd64's lapic.c.  The two files will need similar changes to switch
to the new code, so the more alike they are the better.

Tested by mlarkin@ on an ESXi VM.  Tested by me on my amd64 laptop
running in x86 compatibility mode.

ok mlarkin@

sys/arch/i386/i386/lapic.c

index 86572f6..1f18d4c 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: lapic.c,v 1.50 2022/08/25 17:38:16 cheloha Exp $      */
+/*     $OpenBSD: lapic.c,v 1.51 2022/09/06 17:26:27 cheloha Exp $      */
 /* $NetBSD: lapic.c,v 1.1.2.8 2000/02/23 06:10:50 sommerfeld Exp $ */
 
 /*-
@@ -244,11 +244,41 @@ u_int32_t lapic_tval;
 /*
  * this gets us up to a 4GHz busclock....
  */
-u_int32_t lapic_per_second;
+u_int32_t lapic_per_second = 0;
 u_int32_t lapic_frac_usec_per_cycle;
 u_int64_t lapic_frac_cycle_per_usec;
 u_int32_t lapic_delaytab[26];
 
+void lapic_timer_oneshot(uint32_t, uint32_t);
+void lapic_timer_periodic(uint32_t, uint32_t);
+
+/*
+ * Start the local apic countdown timer.
+ *
+ * First set the mode, mask, and vector.  Then set the
+ * divisor.  Last, set the cycle count: this restarts
+ * the countdown.
+ */
+static inline void
+lapic_timer_start(uint32_t mode, uint32_t mask, uint32_t cycles)
+{
+       i82489_writereg(LAPIC_LVTT, mode | mask | LAPIC_TIMER_VECTOR);
+       i82489_writereg(LAPIC_DCR_TIMER, LAPIC_DCRT_DIV1);
+       i82489_writereg(LAPIC_ICR_TIMER, cycles);
+}
+
+void
+lapic_timer_oneshot(uint32_t mask, uint32_t cycles)
+{
+       lapic_timer_start(LAPIC_LVTT_TM_ONESHOT, mask, cycles);
+}
+
+void
+lapic_timer_periodic(uint32_t mask, uint32_t cycles)
+{
+       lapic_timer_start(LAPIC_LVTT_TM_PERIODIC, mask, cycles);
+}
+
 void
 lapic_clockintr(void *arg)
 {
@@ -262,17 +292,7 @@ lapic_clockintr(void *arg)
 void
 lapic_startclock(void)
 {
-       /*
-        * Start local apic countdown timer running, in repeated mode.
-        *
-        * Mask the clock interrupt and set mode,
-        * then set divisor,
-        * then unmask and set the vector.
-        */
-       i82489_writereg(LAPIC_LVTT, LAPIC_LVTT_TM|LAPIC_LVTT_M);
-       i82489_writereg(LAPIC_DCR_TIMER, LAPIC_DCRT_DIV1);
-       i82489_writereg(LAPIC_ICR_TIMER, lapic_tval);
-       i82489_writereg(LAPIC_LVTT, LAPIC_LVTT_TM|LAPIC_TIMER_VECTOR);
+       lapic_timer_periodic(0, lapic_tval);
 }
 
 void
@@ -284,6 +304,7 @@ lapic_initclocks(void)
 }
 
 extern int gettick(void);      /* XXX put in header file */
+extern u_long rtclock_tval; /* XXX put in header file */
 
 static __inline void
 wait_next_cycle(void)
@@ -325,38 +346,45 @@ lapic_calibrate_timer(struct cpu_info *ci)
         * Configure timer to one-shot, interrupt masked,
         * large positive number.
         */
-       i82489_writereg(LAPIC_LVTT, LAPIC_LVTT_M);
-       i82489_writereg(LAPIC_DCR_TIMER, LAPIC_DCRT_DIV1);
-       i82489_writereg(LAPIC_ICR_TIMER, 0x80000000);
-
-       s = intr_disable();
-
-       /* wait for current cycle to finish */
-       wait_next_cycle();
+       lapic_timer_oneshot(LAPIC_LVTT_M, 0x80000000);
 
-       startapic = lapic_gettick();
+       if (delay_func == i8254_delay) {
+               s = intr_disable();
 
-       /* wait the next hz cycles */
-       for (i = 0; i < hz; i++)
+               /* wait for current cycle to finish */
                wait_next_cycle();
 
-       endapic = lapic_gettick();
+               startapic = lapic_gettick();
 
-       intr_restore(s);
+               /* wait the next hz cycles */
+               for (i = 0; i < hz; i++)
+                       wait_next_cycle();
 
-       dtick = hz * TIMER_DIV(hz);
-       dapic = startapic-endapic;
+               endapic = lapic_gettick();
 
-       /*
-        * there are TIMER_FREQ ticks per second.
-        * in dtick ticks, there are dapic bus clocks.
-        */
-       tmp = (TIMER_FREQ * dapic) / dtick;
+               intr_restore(s);
+
+               dtick = hz * rtclock_tval;
+               dapic = startapic-endapic;
 
-       lapic_per_second = tmp;
+               /*
+                * there are TIMER_FREQ ticks per second.
+                * in dtick ticks, there are dapic bus clocks.
+                */
+               tmp = (TIMER_FREQ * dapic) / dtick;
+
+               lapic_per_second = tmp;
+       } else {
+               s = intr_disable();
+               startapic = lapic_gettick();
+               delay(1 * 1000 * 1000);
+               endapic = lapic_gettick();
+               intr_restore(s);
+               lapic_per_second = startapic - endapic;
+       }
 
-       printf("%s: apic clock running at %lldMHz\n",
-           ci->ci_dev->dv_xname, tmp / (1000 * 1000));
+       printf("%s: apic clock running at %dMHz\n",
+           ci->ci_dev->dv_xname, lapic_per_second / (1000 * 1000));
 
        if (lapic_per_second != 0) {
                /*
@@ -366,10 +394,7 @@ lapic_calibrate_timer(struct cpu_info *ci)
                lapic_tval = (lapic_per_second * 2) / hz;
                lapic_tval = (lapic_tval / 2) + (lapic_tval & 0x1);
 
-               i82489_writereg(LAPIC_LVTT, LAPIC_LVTT_TM | LAPIC_LVTT_M |
-                   LAPIC_TIMER_VECTOR);
-               i82489_writereg(LAPIC_DCR_TIMER, LAPIC_DCRT_DIV1);
-               i82489_writereg(LAPIC_ICR_TIMER, lapic_tval);
+               lapic_timer_periodic(LAPIC_LVTT_M, lapic_tval);
 
                /*
                 * Compute fixed-point ratios between cycles and
@@ -426,6 +451,8 @@ lapic_delay(int usec)
                else
                        deltat -= otick - tick;
                otick = tick;
+
+               CPU_BUSY_CYCLE();
        }
 }