132580301SAttilio Rao /*-
251369649SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause
351369649SPedro F. Giffuni *
432580301SAttilio Rao * Copyright (c) 1990 The Regents of the University of California.
5875b8844SAlexander Motin * Copyright (c) 2010 Alexander Motin <mav@FreeBSD.org>
632580301SAttilio Rao * All rights reserved.
732580301SAttilio Rao *
832580301SAttilio Rao * This code is derived from software contributed to Berkeley by
932580301SAttilio Rao * William Jolitz and Don Ahn.
1032580301SAttilio Rao *
1132580301SAttilio Rao * Redistribution and use in source and binary forms, with or without
1232580301SAttilio Rao * modification, are permitted provided that the following conditions
1332580301SAttilio Rao * are met:
1432580301SAttilio Rao * 1. Redistributions of source code must retain the above copyright
1532580301SAttilio Rao * notice, this list of conditions and the following disclaimer.
1632580301SAttilio Rao * 2. Redistributions in binary form must reproduce the above copyright
1732580301SAttilio Rao * notice, this list of conditions and the following disclaimer in the
1832580301SAttilio Rao * documentation and/or other materials provided with the distribution.
19fbbd9655SWarner Losh * 3. Neither the name of the University nor the names of its contributors
2032580301SAttilio Rao * may be used to endorse or promote products derived from this software
2132580301SAttilio Rao * without specific prior written permission.
2232580301SAttilio Rao *
2332580301SAttilio Rao * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2432580301SAttilio Rao * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2532580301SAttilio Rao * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2632580301SAttilio Rao * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2732580301SAttilio Rao * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2832580301SAttilio Rao * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2932580301SAttilio Rao * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3032580301SAttilio Rao * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3132580301SAttilio Rao * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3232580301SAttilio Rao * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3332580301SAttilio Rao * SUCH DAMAGE.
3432580301SAttilio Rao */
3532580301SAttilio Rao
3632580301SAttilio Rao #include <sys/cdefs.h>
3732580301SAttilio Rao /*
3832580301SAttilio Rao * Routines to handle clock hardware.
3932580301SAttilio Rao */
4032580301SAttilio Rao
41aa597d40SMark Johnston #ifdef __amd64__
42aa597d40SMark Johnston #define DEV_APIC
43aa597d40SMark Johnston #else
44aa597d40SMark Johnston #include "opt_apic.h"
45aa597d40SMark Johnston #endif
4632580301SAttilio Rao #include "opt_clock.h"
4732580301SAttilio Rao #include "opt_isa.h"
4832580301SAttilio Rao
4932580301SAttilio Rao #include <sys/param.h>
5032580301SAttilio Rao #include <sys/systm.h>
5132580301SAttilio Rao #include <sys/bus.h>
5232580301SAttilio Rao #include <sys/lock.h>
5332580301SAttilio Rao #include <sys/kdb.h>
5432580301SAttilio Rao #include <sys/mutex.h>
5532580301SAttilio Rao #include <sys/proc.h>
5632580301SAttilio Rao #include <sys/kernel.h>
5732580301SAttilio Rao #include <sys/module.h>
58875b8844SAlexander Motin #include <sys/rman.h>
5932580301SAttilio Rao #include <sys/sched.h>
6032580301SAttilio Rao #include <sys/smp.h>
6132580301SAttilio Rao #include <sys/sysctl.h>
62875b8844SAlexander Motin #include <sys/timeet.h>
63875b8844SAlexander Motin #include <sys/timetc.h>
6432580301SAttilio Rao
6532580301SAttilio Rao #include <machine/clock.h>
6632580301SAttilio Rao #include <machine/cpu.h>
6732580301SAttilio Rao #include <machine/intr_machdep.h>
6862d09b46SMark Johnston #include <x86/apicvar.h>
695f05c794SRoger Pau Monné #include <x86/init.h>
70d1f4c44aSDmitry Chagin #include <x86/ppireg.h>
71*de4da6cdSDmitry Chagin #include <x86/timerreg.h>
7232580301SAttilio Rao
7332580301SAttilio Rao #include <isa/rtc.h>
7432580301SAttilio Rao #ifdef DEV_ISA
7532580301SAttilio Rao #include <isa/isareg.h>
7632580301SAttilio Rao #include <isa/isavar.h>
7732580301SAttilio Rao #endif
7832580301SAttilio Rao
7932580301SAttilio Rao int clkintr_pending;
8032580301SAttilio Rao #ifndef TIMER_FREQ
8132580301SAttilio Rao #define TIMER_FREQ 1193182
8232580301SAttilio Rao #endif
8332580301SAttilio Rao u_int i8254_freq = TIMER_FREQ;
8432580301SAttilio Rao TUNABLE_INT("hw.i8254.freq", &i8254_freq);
8532580301SAttilio Rao int i8254_max_count;
869500655eSAlexander Motin static int i8254_timecounter = 1;
8732580301SAttilio Rao
888355852fSIan Lepore static struct mtx clock_lock;
8932580301SAttilio Rao static struct intsrc *i8254_intsrc;
90875b8844SAlexander Motin static uint16_t i8254_lastcount;
91875b8844SAlexander Motin static uint16_t i8254_offset;
9232580301SAttilio Rao static int (*i8254_pending)(struct intsrc *);
9332580301SAttilio Rao static int i8254_ticked;
94875b8844SAlexander Motin
95875b8844SAlexander Motin struct attimer_softc {
96875b8844SAlexander Motin int intr_en;
9791751b1aSAlexander Motin int port_rid, intr_rid;
9891751b1aSAlexander Motin struct resource *port_res;
99875b8844SAlexander Motin struct resource *intr_res;
100875b8844SAlexander Motin void *intr_handler;
101875b8844SAlexander Motin struct timecounter tc;
102875b8844SAlexander Motin struct eventtimer et;
1039500655eSAlexander Motin int mode;
1049500655eSAlexander Motin #define MODE_STOP 0
1059500655eSAlexander Motin #define MODE_PERIODIC 1
1069500655eSAlexander Motin #define MODE_ONESHOT 2
1079500655eSAlexander Motin uint32_t period;
108875b8844SAlexander Motin };
109875b8844SAlexander Motin static struct attimer_softc *attimer_sc = NULL;
11032580301SAttilio Rao
111d3979248SAlexander Motin static int timer0_period = -2;
112a937c507SAlexander Motin static int timer0_mode = 0xffff;
113a937c507SAlexander Motin static int timer0_last = 0xffff;
114d3979248SAlexander Motin
11532580301SAttilio Rao /* Values for timerX_state: */
11632580301SAttilio Rao #define RELEASED 0
11732580301SAttilio Rao #define RELEASE_PENDING 1
11832580301SAttilio Rao #define ACQUIRED 2
11932580301SAttilio Rao #define ACQUIRE_PENDING 3
12032580301SAttilio Rao
12132580301SAttilio Rao static u_char timer2_state;
12232580301SAttilio Rao
12332580301SAttilio Rao static unsigned i8254_get_timecount(struct timecounter *tc);
1249500655eSAlexander Motin static void set_i8254_freq(int mode, uint32_t period);
12532580301SAttilio Rao
1265f05c794SRoger Pau Monné void
clock_init(void)1275f05c794SRoger Pau Monné clock_init(void)
1285f05c794SRoger Pau Monné {
1295f05c794SRoger Pau Monné /* Init the clock lock */
1305f05c794SRoger Pau Monné mtx_init(&clock_lock, "clk", NULL, MTX_SPIN | MTX_NOPROFILE);
1315f05c794SRoger Pau Monné /* Init the clock in order to use DELAY */
1325f05c794SRoger Pau Monné init_ops.early_clock_source_init();
1331ca34862SRoger Pau Monné tsc_init();
1345f05c794SRoger Pau Monné }
1355f05c794SRoger Pau Monné
13632580301SAttilio Rao static int
clkintr(void * arg)137875b8844SAlexander Motin clkintr(void *arg)
13832580301SAttilio Rao {
139875b8844SAlexander Motin struct attimer_softc *sc = (struct attimer_softc *)arg;
14032580301SAttilio Rao
1419500655eSAlexander Motin if (i8254_timecounter && sc->period != 0) {
14232580301SAttilio Rao mtx_lock_spin(&clock_lock);
14332580301SAttilio Rao if (i8254_ticked)
14432580301SAttilio Rao i8254_ticked = 0;
14532580301SAttilio Rao else {
14632580301SAttilio Rao i8254_offset += i8254_max_count;
14732580301SAttilio Rao i8254_lastcount = 0;
14832580301SAttilio Rao }
14932580301SAttilio Rao clkintr_pending = 0;
15032580301SAttilio Rao mtx_unlock_spin(&clock_lock);
15132580301SAttilio Rao }
15232580301SAttilio Rao
1530eda5b3fSJung-uk Kim if (sc->et.et_active && sc->mode != MODE_STOP)
1548a687080SAlexander Motin sc->et.et_event_cb(&sc->et, sc->et.et_arg);
15532580301SAttilio Rao
15632580301SAttilio Rao return (FILTER_HANDLED);
15732580301SAttilio Rao }
15832580301SAttilio Rao
15932580301SAttilio Rao int
timer_spkr_acquire(void)16032580301SAttilio Rao timer_spkr_acquire(void)
16132580301SAttilio Rao {
16232580301SAttilio Rao int mode;
16332580301SAttilio Rao
16432580301SAttilio Rao mode = TIMER_SEL2 | TIMER_SQWAVE | TIMER_16BIT;
16532580301SAttilio Rao
16632580301SAttilio Rao if (timer2_state != RELEASED)
16732580301SAttilio Rao return (-1);
16832580301SAttilio Rao timer2_state = ACQUIRED;
16932580301SAttilio Rao
17032580301SAttilio Rao /*
17132580301SAttilio Rao * This access to the timer registers is as atomic as possible
17232580301SAttilio Rao * because it is a single instruction. We could do better if we
17332580301SAttilio Rao * knew the rate. Use of splclock() limits glitches to 10-100us,
17432580301SAttilio Rao * and this is probably good enough for timer2, so we aren't as
17532580301SAttilio Rao * careful with it as with timer0.
17632580301SAttilio Rao */
17732580301SAttilio Rao outb(TIMER_MODE, TIMER_SEL2 | (mode & 0x3f));
1782b375b4eSYoshihiro Takahashi
17932580301SAttilio Rao ppi_spkr_on(); /* enable counter2 output to speaker */
18032580301SAttilio Rao return (0);
18132580301SAttilio Rao }
18232580301SAttilio Rao
18332580301SAttilio Rao int
timer_spkr_release(void)18432580301SAttilio Rao timer_spkr_release(void)
18532580301SAttilio Rao {
18632580301SAttilio Rao
18732580301SAttilio Rao if (timer2_state != ACQUIRED)
18832580301SAttilio Rao return (-1);
18932580301SAttilio Rao timer2_state = RELEASED;
19032580301SAttilio Rao outb(TIMER_MODE, TIMER_SEL2 | TIMER_SQWAVE | TIMER_16BIT);
1912b375b4eSYoshihiro Takahashi
19232580301SAttilio Rao ppi_spkr_off(); /* disable counter2 output to speaker */
19332580301SAttilio Rao return (0);
19432580301SAttilio Rao }
19532580301SAttilio Rao
19632580301SAttilio Rao void
timer_spkr_setfreq(int freq)19732580301SAttilio Rao timer_spkr_setfreq(int freq)
19832580301SAttilio Rao {
19932580301SAttilio Rao
20032580301SAttilio Rao freq = i8254_freq / freq;
20132580301SAttilio Rao mtx_lock_spin(&clock_lock);
20232580301SAttilio Rao outb(TIMER_CNTR2, freq & 0xff);
20332580301SAttilio Rao outb(TIMER_CNTR2, freq >> 8);
20432580301SAttilio Rao mtx_unlock_spin(&clock_lock);
20532580301SAttilio Rao }
20632580301SAttilio Rao
20732580301SAttilio Rao static int
getit(void)20832580301SAttilio Rao getit(void)
20932580301SAttilio Rao {
21032580301SAttilio Rao int high, low;
21132580301SAttilio Rao
21232580301SAttilio Rao mtx_lock_spin(&clock_lock);
21332580301SAttilio Rao
21432580301SAttilio Rao /* Select timer0 and latch counter value. */
21532580301SAttilio Rao outb(TIMER_MODE, TIMER_SEL0 | TIMER_LATCH);
21632580301SAttilio Rao
21732580301SAttilio Rao low = inb(TIMER_CNTR0);
21832580301SAttilio Rao high = inb(TIMER_CNTR0);
21932580301SAttilio Rao
22032580301SAttilio Rao mtx_unlock_spin(&clock_lock);
22132580301SAttilio Rao return ((high << 8) | low);
22232580301SAttilio Rao }
22332580301SAttilio Rao
224856e88c1SJung-uk Kim /*
225856e88c1SJung-uk Kim * Wait "n" microseconds.
226856e88c1SJung-uk Kim * Relies on timer 1 counting down from (i8254_freq / hz)
227856e88c1SJung-uk Kim * Note: timer had better have been programmed before this is first used!
228856e88c1SJung-uk Kim */
229856e88c1SJung-uk Kim void
i8254_delay(int n)2305f05c794SRoger Pau Monné i8254_delay(int n)
231856e88c1SJung-uk Kim {
232856e88c1SJung-uk Kim int delta, prev_tick, tick, ticks_left;
233856e88c1SJung-uk Kim #ifdef DELAYDEBUG
234856e88c1SJung-uk Kim int getit_calls = 1;
235856e88c1SJung-uk Kim int n1;
236856e88c1SJung-uk Kim static int state = 0;
23780c2cdcfSJung-uk Kim
23880c2cdcfSJung-uk Kim if (state == 0) {
23980c2cdcfSJung-uk Kim state = 1;
24080c2cdcfSJung-uk Kim for (n1 = 1; n1 <= 10000000; n1 *= 10)
24180c2cdcfSJung-uk Kim DELAY(n1);
24280c2cdcfSJung-uk Kim state = 2;
24380c2cdcfSJung-uk Kim }
24480c2cdcfSJung-uk Kim if (state == 1)
24580c2cdcfSJung-uk Kim printf("DELAY(%d)...", n);
24632580301SAttilio Rao #endif
24732580301SAttilio Rao /*
24832580301SAttilio Rao * Read the counter first, so that the rest of the setup overhead is
24932580301SAttilio Rao * counted. Guess the initial overhead is 20 usec (on most systems it
25032580301SAttilio Rao * takes about 1.5 usec for each of the i/o's in getit(). The loop
25132580301SAttilio Rao * takes about 6 usec on a 486/33 and 13 usec on a 386/20. The
25232580301SAttilio Rao * multiplications and divisions to scale the count take a while).
25332580301SAttilio Rao *
25432580301SAttilio Rao * However, if ddb is active then use a fake counter since reading
25532580301SAttilio Rao * the i8254 counter involves acquiring a lock. ddb must not do
25632580301SAttilio Rao * locking for many reasons, but it calls here for at least atkbd
25732580301SAttilio Rao * input.
25832580301SAttilio Rao */
25932580301SAttilio Rao #ifdef KDB
26032580301SAttilio Rao if (kdb_active)
26132580301SAttilio Rao prev_tick = 1;
26232580301SAttilio Rao else
26332580301SAttilio Rao #endif
26432580301SAttilio Rao prev_tick = getit();
26532580301SAttilio Rao n -= 0; /* XXX actually guess no initial overhead */
26632580301SAttilio Rao /*
26732580301SAttilio Rao * Calculate (n * (i8254_freq / 1e6)) without using floating point
26832580301SAttilio Rao * and without any avoidable overflows.
26932580301SAttilio Rao */
27032580301SAttilio Rao if (n <= 0)
27132580301SAttilio Rao ticks_left = 0;
27232580301SAttilio Rao else if (n < 256)
27332580301SAttilio Rao /*
27432580301SAttilio Rao * Use fixed point to avoid a slow division by 1000000.
27532580301SAttilio Rao * 39099 = 1193182 * 2^15 / 10^6 rounded to nearest.
27632580301SAttilio Rao * 2^15 is the first power of 2 that gives exact results
27732580301SAttilio Rao * for n between 0 and 256.
27832580301SAttilio Rao */
27932580301SAttilio Rao ticks_left = ((u_int)n * 39099 + (1 << 15) - 1) >> 15;
28032580301SAttilio Rao else
28132580301SAttilio Rao /*
28232580301SAttilio Rao * Don't bother using fixed point, although gcc-2.7.2
28332580301SAttilio Rao * generates particularly poor code for the long long
28432580301SAttilio Rao * division, since even the slow way will complete long
28532580301SAttilio Rao * before the delay is up (unless we're interrupted).
28632580301SAttilio Rao */
28732580301SAttilio Rao ticks_left = ((u_int)n * (long long)i8254_freq + 999999)
28832580301SAttilio Rao / 1000000;
28932580301SAttilio Rao
29032580301SAttilio Rao while (ticks_left > 0) {
29132580301SAttilio Rao #ifdef KDB
29232580301SAttilio Rao if (kdb_active) {
29332580301SAttilio Rao inb(0x84);
29432580301SAttilio Rao tick = prev_tick - 1;
29532580301SAttilio Rao if (tick <= 0)
29632580301SAttilio Rao tick = i8254_max_count;
29732580301SAttilio Rao } else
29832580301SAttilio Rao #endif
29932580301SAttilio Rao tick = getit();
30032580301SAttilio Rao #ifdef DELAYDEBUG
30132580301SAttilio Rao ++getit_calls;
30232580301SAttilio Rao #endif
30332580301SAttilio Rao delta = prev_tick - tick;
30432580301SAttilio Rao prev_tick = tick;
30532580301SAttilio Rao if (delta < 0) {
30632580301SAttilio Rao delta += i8254_max_count;
30732580301SAttilio Rao /*
30832580301SAttilio Rao * Guard against i8254_max_count being wrong.
30932580301SAttilio Rao * This shouldn't happen in normal operation,
31032580301SAttilio Rao * but it may happen if set_i8254_freq() is
31132580301SAttilio Rao * traced.
31232580301SAttilio Rao */
31332580301SAttilio Rao if (delta < 0)
31432580301SAttilio Rao delta = 0;
31532580301SAttilio Rao }
31632580301SAttilio Rao ticks_left -= delta;
31732580301SAttilio Rao }
31832580301SAttilio Rao #ifdef DELAYDEBUG
31932580301SAttilio Rao if (state == 1)
32032580301SAttilio Rao printf(" %d calls to getit() at %d usec each\n",
32132580301SAttilio Rao getit_calls, (n + 5) / getit_calls);
32232580301SAttilio Rao #endif
32332580301SAttilio Rao }
32432580301SAttilio Rao
32532580301SAttilio Rao static void
set_i8254_freq(int mode,uint32_t period)3269500655eSAlexander Motin set_i8254_freq(int mode, uint32_t period)
32732580301SAttilio Rao {
328a937c507SAlexander Motin int new_count, new_mode;
32932580301SAttilio Rao
33032580301SAttilio Rao mtx_lock_spin(&clock_lock);
331d3979248SAlexander Motin if (mode == MODE_STOP) {
332d3979248SAlexander Motin if (i8254_timecounter) {
3339500655eSAlexander Motin mode = MODE_PERIODIC;
334d3979248SAlexander Motin new_count = 0x10000;
335d3979248SAlexander Motin } else
336d3979248SAlexander Motin new_count = -1;
337d3979248SAlexander Motin } else {
338d3979248SAlexander Motin new_count = min(((uint64_t)i8254_freq * period +
339d3979248SAlexander Motin 0x80000000LLU) >> 32, 0x10000);
340d3979248SAlexander Motin }
341d3979248SAlexander Motin if (new_count == timer0_period)
342d3979248SAlexander Motin goto out;
343d3979248SAlexander Motin i8254_max_count = ((new_count & ~0xffff) != 0) ? 0xffff : new_count;
344d3979248SAlexander Motin timer0_period = (mode == MODE_PERIODIC) ? new_count : -1;
3459500655eSAlexander Motin switch (mode) {
3469500655eSAlexander Motin case MODE_STOP:
347a937c507SAlexander Motin new_mode = TIMER_SEL0 | TIMER_INTTC | TIMER_16BIT;
348a937c507SAlexander Motin outb(TIMER_MODE, new_mode);
349d3979248SAlexander Motin outb(TIMER_CNTR0, 0);
350d3979248SAlexander Motin outb(TIMER_CNTR0, 0);
3519500655eSAlexander Motin break;
3529500655eSAlexander Motin case MODE_PERIODIC:
353a937c507SAlexander Motin new_mode = TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT;
354a937c507SAlexander Motin outb(TIMER_MODE, new_mode);
355d3979248SAlexander Motin outb(TIMER_CNTR0, new_count & 0xff);
356d3979248SAlexander Motin outb(TIMER_CNTR0, new_count >> 8);
3579500655eSAlexander Motin break;
3589500655eSAlexander Motin case MODE_ONESHOT:
359a937c507SAlexander Motin if (new_count < 256 && timer0_last < 256) {
360a937c507SAlexander Motin new_mode = TIMER_SEL0 | TIMER_INTTC | TIMER_LSB;
361a937c507SAlexander Motin if (new_mode != timer0_mode)
362a937c507SAlexander Motin outb(TIMER_MODE, new_mode);
363a937c507SAlexander Motin outb(TIMER_CNTR0, new_count & 0xff);
364a937c507SAlexander Motin break;
365a937c507SAlexander Motin }
366a937c507SAlexander Motin new_mode = TIMER_SEL0 | TIMER_INTTC | TIMER_16BIT;
367a937c507SAlexander Motin if (new_mode != timer0_mode)
368a937c507SAlexander Motin outb(TIMER_MODE, new_mode);
369d3979248SAlexander Motin outb(TIMER_CNTR0, new_count & 0xff);
370d3979248SAlexander Motin outb(TIMER_CNTR0, new_count >> 8);
3719500655eSAlexander Motin break;
372ce4642ecSDavide Italiano default:
373ce4642ecSDavide Italiano panic("set_i8254_freq: unknown operational mode");
37432580301SAttilio Rao }
375a937c507SAlexander Motin timer0_mode = new_mode;
376a937c507SAlexander Motin timer0_last = new_count;
377d3979248SAlexander Motin out:
37832580301SAttilio Rao mtx_unlock_spin(&clock_lock);
37932580301SAttilio Rao }
38032580301SAttilio Rao
38132580301SAttilio Rao static void
i8254_restore(void)38232580301SAttilio Rao i8254_restore(void)
38332580301SAttilio Rao {
38432580301SAttilio Rao
385d3979248SAlexander Motin timer0_period = -2;
386a937c507SAlexander Motin timer0_mode = 0xffff;
387a937c507SAlexander Motin timer0_last = 0xffff;
388d3979248SAlexander Motin if (attimer_sc != NULL)
3899500655eSAlexander Motin set_i8254_freq(attimer_sc->mode, attimer_sc->period);
3909500655eSAlexander Motin else
391cb261f43SBrooks Davis set_i8254_freq(MODE_STOP, 0);
39232580301SAttilio Rao }
39332580301SAttilio Rao
39432580301SAttilio Rao /* This is separate from startrtclock() so that it can be called early. */
39532580301SAttilio Rao void
i8254_init(void)39632580301SAttilio Rao i8254_init(void)
39732580301SAttilio Rao {
39832580301SAttilio Rao
399cb261f43SBrooks Davis set_i8254_freq(MODE_STOP, 0);
40032580301SAttilio Rao }
40132580301SAttilio Rao
40232580301SAttilio Rao void
startrtclock(void)40384369dd5SMark Johnston startrtclock(void)
40432580301SAttilio Rao {
40532580301SAttilio Rao
40684369dd5SMark Johnston start_TSC();
40732580301SAttilio Rao }
40832580301SAttilio Rao
40932580301SAttilio Rao void
cpu_initclocks(void)410875b8844SAlexander Motin cpu_initclocks(void)
41132580301SAttilio Rao {
412fdce57a0SJohn Baldwin struct thread *td;
413fdce57a0SJohn Baldwin int i;
41432580301SAttilio Rao
415fdce57a0SJohn Baldwin td = curthread;
41662d09b46SMark Johnston
417553af8f1SMark Johnston tsc_calibrate();
418aa597d40SMark Johnston #ifdef DEV_APIC
41962d09b46SMark Johnston lapic_calibrate_timer();
420aa597d40SMark Johnston #endif
421875b8844SAlexander Motin cpu_initclocks_bsp();
422fdce57a0SJohn Baldwin CPU_FOREACH(i) {
423fdce57a0SJohn Baldwin if (i == 0)
424fdce57a0SJohn Baldwin continue;
425fdce57a0SJohn Baldwin thread_lock(td);
426fdce57a0SJohn Baldwin sched_bind(td, i);
427fdce57a0SJohn Baldwin thread_unlock(td);
428fdce57a0SJohn Baldwin cpu_initclocks_ap();
429fdce57a0SJohn Baldwin }
430fdce57a0SJohn Baldwin thread_lock(td);
431fdce57a0SJohn Baldwin if (sched_is_bound(td))
432fdce57a0SJohn Baldwin sched_unbind(td);
433fdce57a0SJohn Baldwin thread_unlock(td);
43432580301SAttilio Rao }
43532580301SAttilio Rao
43632580301SAttilio Rao static int
sysctl_machdep_i8254_freq(SYSCTL_HANDLER_ARGS)43732580301SAttilio Rao sysctl_machdep_i8254_freq(SYSCTL_HANDLER_ARGS)
43832580301SAttilio Rao {
43932580301SAttilio Rao int error;
44032580301SAttilio Rao u_int freq;
44132580301SAttilio Rao
44232580301SAttilio Rao /*
44332580301SAttilio Rao * Use `i8254' instead of `timer' in external names because `timer'
444974206cfSRebecca Cran * is too generic. Should use it everywhere.
44532580301SAttilio Rao */
44632580301SAttilio Rao freq = i8254_freq;
44732580301SAttilio Rao error = sysctl_handle_int(oidp, &freq, 0, req);
448875b8844SAlexander Motin if (error == 0 && req->newptr != NULL) {
4499500655eSAlexander Motin i8254_freq = freq;
450d3979248SAlexander Motin if (attimer_sc != NULL) {
4519500655eSAlexander Motin set_i8254_freq(attimer_sc->mode, attimer_sc->period);
452875b8844SAlexander Motin attimer_sc->tc.tc_frequency = freq;
453875b8844SAlexander Motin } else {
454cb261f43SBrooks Davis set_i8254_freq(MODE_STOP, 0);
455875b8844SAlexander Motin }
456875b8844SAlexander Motin }
45732580301SAttilio Rao return (error);
45832580301SAttilio Rao }
45932580301SAttilio Rao
4607029da5cSPawel Biernacki SYSCTL_PROC(_machdep, OID_AUTO, i8254_freq,
4611d6fb900SAlexander Motin CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE,
4625331d61dSJung-uk Kim 0, sizeof(u_int), sysctl_machdep_i8254_freq, "IU",
4635331d61dSJung-uk Kim "i8254 timer frequency");
46432580301SAttilio Rao
46532580301SAttilio Rao static unsigned
i8254_get_timecount(struct timecounter * tc)46632580301SAttilio Rao i8254_get_timecount(struct timecounter *tc)
46732580301SAttilio Rao {
468875b8844SAlexander Motin device_t dev = (device_t)tc->tc_priv;
469875b8844SAlexander Motin struct attimer_softc *sc = device_get_softc(dev);
47032580301SAttilio Rao register_t flags;
471875b8844SAlexander Motin uint16_t count;
47232580301SAttilio Rao u_int high, low;
47332580301SAttilio Rao
4749500655eSAlexander Motin if (sc->period == 0)
475875b8844SAlexander Motin return (i8254_max_count - getit());
476875b8844SAlexander Motin
47732580301SAttilio Rao #ifdef __amd64__
47832580301SAttilio Rao flags = read_rflags();
47932580301SAttilio Rao #else
48032580301SAttilio Rao flags = read_eflags();
48132580301SAttilio Rao #endif
48232580301SAttilio Rao mtx_lock_spin(&clock_lock);
48332580301SAttilio Rao
48432580301SAttilio Rao /* Select timer0 and latch counter value. */
48532580301SAttilio Rao outb(TIMER_MODE, TIMER_SEL0 | TIMER_LATCH);
48632580301SAttilio Rao
48732580301SAttilio Rao low = inb(TIMER_CNTR0);
48832580301SAttilio Rao high = inb(TIMER_CNTR0);
48932580301SAttilio Rao count = i8254_max_count - ((high << 8) | low);
49032580301SAttilio Rao if (count < i8254_lastcount ||
49132580301SAttilio Rao (!i8254_ticked && (clkintr_pending ||
49232580301SAttilio Rao ((count < 20 || (!(flags & PSL_I) &&
49332580301SAttilio Rao count < i8254_max_count / 2u)) &&
49432580301SAttilio Rao i8254_pending != NULL && i8254_pending(i8254_intsrc))))) {
49532580301SAttilio Rao i8254_ticked = 1;
49632580301SAttilio Rao i8254_offset += i8254_max_count;
49732580301SAttilio Rao }
49832580301SAttilio Rao i8254_lastcount = count;
49932580301SAttilio Rao count += i8254_offset;
50032580301SAttilio Rao mtx_unlock_spin(&clock_lock);
50132580301SAttilio Rao return (count);
50232580301SAttilio Rao }
50332580301SAttilio Rao
504875b8844SAlexander Motin static int
attimer_start(struct eventtimer * et,sbintime_t first,sbintime_t period)505fdc5dd2dSAlexander Motin attimer_start(struct eventtimer *et, sbintime_t first, sbintime_t period)
506875b8844SAlexander Motin {
507875b8844SAlexander Motin device_t dev = (device_t)et->et_priv;
508875b8844SAlexander Motin struct attimer_softc *sc = device_get_softc(dev);
509875b8844SAlexander Motin
510fdc5dd2dSAlexander Motin if (period != 0) {
5119500655eSAlexander Motin sc->mode = MODE_PERIODIC;
512fdc5dd2dSAlexander Motin sc->period = period;
5139500655eSAlexander Motin } else {
5149500655eSAlexander Motin sc->mode = MODE_ONESHOT;
515fdc5dd2dSAlexander Motin sc->period = first;
5169500655eSAlexander Motin }
517875b8844SAlexander Motin if (!sc->intr_en) {
518875b8844SAlexander Motin i8254_intsrc->is_pic->pic_enable_source(i8254_intsrc);
519875b8844SAlexander Motin sc->intr_en = 1;
520875b8844SAlexander Motin }
5219500655eSAlexander Motin set_i8254_freq(sc->mode, sc->period);
522875b8844SAlexander Motin return (0);
523875b8844SAlexander Motin }
524875b8844SAlexander Motin
525875b8844SAlexander Motin static int
attimer_stop(struct eventtimer * et)526875b8844SAlexander Motin attimer_stop(struct eventtimer *et)
527875b8844SAlexander Motin {
528875b8844SAlexander Motin device_t dev = (device_t)et->et_priv;
529875b8844SAlexander Motin struct attimer_softc *sc = device_get_softc(dev);
530875b8844SAlexander Motin
5319500655eSAlexander Motin sc->mode = MODE_STOP;
5329500655eSAlexander Motin sc->period = 0;
5339500655eSAlexander Motin set_i8254_freq(sc->mode, sc->period);
534875b8844SAlexander Motin return (0);
535875b8844SAlexander Motin }
536875b8844SAlexander Motin
53732580301SAttilio Rao #ifdef DEV_ISA
53832580301SAttilio Rao /*
53932580301SAttilio Rao * Attach to the ISA PnP descriptors for the timer
54032580301SAttilio Rao */
54132580301SAttilio Rao static struct isa_pnp_id attimer_ids[] = {
54232580301SAttilio Rao { 0x0001d041 /* PNP0100 */, "AT timer" },
54332580301SAttilio Rao { 0 }
54432580301SAttilio Rao };
54532580301SAttilio Rao
54632580301SAttilio Rao static int
attimer_probe(device_t dev)54732580301SAttilio Rao attimer_probe(device_t dev)
54832580301SAttilio Rao {
54932580301SAttilio Rao int result;
55032580301SAttilio Rao
55132580301SAttilio Rao result = ISA_PNP_PROBE(device_get_parent(dev), dev, attimer_ids);
552a7d6757cSAlexander Motin /* ENOENT means no PnP-ID, device is hinted. */
553a7d6757cSAlexander Motin if (result == ENOENT) {
554a7d6757cSAlexander Motin device_set_desc(dev, "AT timer");
555a7d6757cSAlexander Motin return (BUS_PROBE_LOW_PRIORITY);
556a7d6757cSAlexander Motin }
55732580301SAttilio Rao return (result);
55832580301SAttilio Rao }
55932580301SAttilio Rao
56032580301SAttilio Rao static int
attimer_attach(device_t dev)56132580301SAttilio Rao attimer_attach(device_t dev)
56232580301SAttilio Rao {
563875b8844SAlexander Motin struct attimer_softc *sc;
5642dd1bdf1SJustin Hibbits rman_res_t s;
565875b8844SAlexander Motin int i;
566875b8844SAlexander Motin
567875b8844SAlexander Motin attimer_sc = sc = device_get_softc(dev);
568875b8844SAlexander Motin bzero(sc, sizeof(struct attimer_softc));
56991751b1aSAlexander Motin if (!(sc->port_res = bus_alloc_resource(dev, SYS_RES_IOPORT,
57091751b1aSAlexander Motin &sc->port_rid, IO_TIMER1, IO_TIMER1 + 3, 4, RF_ACTIVE)))
57191751b1aSAlexander Motin device_printf(dev,"Warning: Couldn't map I/O.\n");
572875b8844SAlexander Motin i8254_intsrc = intr_lookup_source(0);
573875b8844SAlexander Motin if (i8254_intsrc != NULL)
574875b8844SAlexander Motin i8254_pending = i8254_intsrc->is_pic->pic_source_pending;
5759500655eSAlexander Motin resource_int_value(device_get_name(dev), device_get_unit(dev),
5769500655eSAlexander Motin "timecounter", &i8254_timecounter);
577cb261f43SBrooks Davis set_i8254_freq(MODE_STOP, 0);
5789500655eSAlexander Motin if (i8254_timecounter) {
579875b8844SAlexander Motin sc->tc.tc_get_timecount = i8254_get_timecount;
580875b8844SAlexander Motin sc->tc.tc_counter_mask = 0xffff;
581875b8844SAlexander Motin sc->tc.tc_frequency = i8254_freq;
582875b8844SAlexander Motin sc->tc.tc_name = "i8254";
583875b8844SAlexander Motin sc->tc.tc_quality = 0;
584875b8844SAlexander Motin sc->tc.tc_priv = dev;
585875b8844SAlexander Motin tc_init(&sc->tc);
5869500655eSAlexander Motin }
587875b8844SAlexander Motin if (resource_int_value(device_get_name(dev), device_get_unit(dev),
588875b8844SAlexander Motin "clock", &i) != 0 || i != 0) {
5896019ba4eSAlexander Motin sc->intr_rid = 0;
59091751b1aSAlexander Motin while (bus_get_resource(dev, SYS_RES_IRQ, sc->intr_rid,
59191751b1aSAlexander Motin &s, NULL) == 0 && s != 0)
59291751b1aSAlexander Motin sc->intr_rid++;
59349ed68bbSAlexander Motin if (!(sc->intr_res = bus_alloc_resource(dev, SYS_RES_IRQ,
59449ed68bbSAlexander Motin &sc->intr_rid, 0, 0, 1, RF_ACTIVE))) {
59549ed68bbSAlexander Motin device_printf(dev,"Can't map interrupt.\n");
59649ed68bbSAlexander Motin return (0);
59749ed68bbSAlexander Motin }
598875b8844SAlexander Motin /* Dirty hack, to make bus_setup_intr to not enable source. */
599875b8844SAlexander Motin i8254_intsrc->is_handlers++;
600875b8844SAlexander Motin if ((bus_setup_intr(dev, sc->intr_res,
601875b8844SAlexander Motin INTR_MPSAFE | INTR_TYPE_CLK,
602875b8844SAlexander Motin (driver_filter_t *)clkintr, NULL,
603875b8844SAlexander Motin sc, &sc->intr_handler))) {
604875b8844SAlexander Motin device_printf(dev, "Can't setup interrupt.\n");
60549ed68bbSAlexander Motin i8254_intsrc->is_handlers--;
60649ed68bbSAlexander Motin return (0);
60749ed68bbSAlexander Motin }
60849ed68bbSAlexander Motin i8254_intsrc->is_handlers--;
609875b8844SAlexander Motin i8254_intsrc->is_pic->pic_enable_intr(i8254_intsrc);
610875b8844SAlexander Motin sc->et.et_name = "i8254";
611875b8844SAlexander Motin sc->et.et_flags = ET_FLAGS_PERIODIC;
6129500655eSAlexander Motin if (!i8254_timecounter)
6139500655eSAlexander Motin sc->et.et_flags |= ET_FLAGS_ONESHOT;
614875b8844SAlexander Motin sc->et.et_quality = 100;
615875b8844SAlexander Motin sc->et.et_frequency = i8254_freq;
616fdc5dd2dSAlexander Motin sc->et.et_min_period = (0x0002LLU << 32) / i8254_freq;
617fdc5dd2dSAlexander Motin sc->et.et_max_period = (0xfffeLLU << 32) / i8254_freq;
618875b8844SAlexander Motin sc->et.et_start = attimer_start;
619875b8844SAlexander Motin sc->et.et_stop = attimer_stop;
620875b8844SAlexander Motin sc->et.et_priv = dev;
621875b8844SAlexander Motin et_register(&sc->et);
622875b8844SAlexander Motin }
62332580301SAttilio Rao return(0);
62432580301SAttilio Rao }
62532580301SAttilio Rao
62632580301SAttilio Rao static int
attimer_resume(device_t dev)62732580301SAttilio Rao attimer_resume(device_t dev)
62832580301SAttilio Rao {
62932580301SAttilio Rao
63032580301SAttilio Rao i8254_restore();
63132580301SAttilio Rao return (0);
63232580301SAttilio Rao }
63332580301SAttilio Rao
63432580301SAttilio Rao static device_method_t attimer_methods[] = {
63532580301SAttilio Rao /* Device interface */
63632580301SAttilio Rao DEVMETHOD(device_probe, attimer_probe),
63732580301SAttilio Rao DEVMETHOD(device_attach, attimer_attach),
63832580301SAttilio Rao DEVMETHOD(device_resume, attimer_resume),
63932580301SAttilio Rao { 0, 0 }
64032580301SAttilio Rao };
64132580301SAttilio Rao
64232580301SAttilio Rao static driver_t attimer_driver = {
64332580301SAttilio Rao "attimer",
64432580301SAttilio Rao attimer_methods,
645875b8844SAlexander Motin sizeof(struct attimer_softc),
64632580301SAttilio Rao };
64732580301SAttilio Rao
64880d2b3deSJohn Baldwin DRIVER_MODULE(attimer, isa, attimer_driver, 0, 0);
64980d2b3deSJohn Baldwin DRIVER_MODULE(attimer, acpi, attimer_driver, 0, 0);
650d6b66397SWarner Losh ISA_PNP_INFO(attimer_ids);
65132580301SAttilio Rao
65232580301SAttilio Rao #endif /* DEV_ISA */
653