As promised off-list: in anticipation of merging the clock interrupt code, let's sync up the lapic timer parts of i386/lapic.c with the corresponding parts in amd64/lapic.c. They will need identical changes to use the new code, so the more alike they are the better.
Notable differences remaining in the timer code: - We use i82489_readreg() and i82489_writereg() on i386 instead of lapic_readreg() and lapic_writereg(). - lapic_clockintr() is just plain different on i386, I'm not touching it yet. - No way to skip_calibration on i386. We can do synchronized cleanup in a later patch. Does this compile and boot on i386? If so, ok? Index: i386/i386/lapic.c =================================================================== RCS file: /cvs/src/sys/arch/i386/i386/lapic.c,v retrieving revision 1.50 diff -u -p -r1.50 lapic.c --- i386/i386/lapic.c 25 Aug 2022 17:38:16 -0000 1.50 +++ i386/i386/lapic.c 28 Aug 2022 20:24:55 -0000 @@ -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 *c * 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); + lapic_timer_oneshot(LAPIC_LVTT_M, 0x80000000); - s = intr_disable(); + if (delay_func == i8254_delay) { + s = intr_disable(); - /* wait for current cycle to finish */ - wait_next_cycle(); + /* wait for current cycle to finish */ + wait_next_cycle(); - startapic = lapic_gettick(); + startapic = lapic_gettick(); - /* wait the next hz cycles */ - for (i = 0; i < hz; i++) - wait_next_cycle(); + /* wait the next hz cycles */ + for (i = 0; i < hz; i++) + wait_next_cycle(); - endapic = lapic_gettick(); + endapic = lapic_gettick(); - intr_restore(s); + intr_restore(s); - dtick = hz * TIMER_DIV(hz); - dapic = startapic-endapic; + dtick = hz * rtclock_tval; + dapic = startapic-endapic; - /* - * there are TIMER_FREQ ticks per second. - * in dtick ticks, there are dapic bus clocks. - */ - tmp = (TIMER_FREQ * dapic) / dtick; + /* + * there are TIMER_FREQ ticks per second. + * in dtick ticks, there are dapic bus clocks. + */ + tmp = (TIMER_FREQ * dapic) / dtick; - lapic_per_second = tmp; + 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 *c 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(); } }