diff options
-rw-r--r-- | sys/dev/acpica/acpi_hpet.c | 16 | ||||
-rw-r--r-- | sys/kern/kern_clocksource.c | 46 | ||||
-rw-r--r-- | sys/kern/kern_et.c | 20 | ||||
-rw-r--r-- | sys/sys/timeet.h | 3 | ||||
-rw-r--r-- | sys/x86/isa/atrtc.c | 6 | ||||
-rw-r--r-- | sys/x86/isa/clock.c | 5 | ||||
-rw-r--r-- | sys/x86/x86/local_apic.c | 11 |
7 files changed, 90 insertions, 17 deletions
diff --git a/sys/dev/acpica/acpi_hpet.c b/sys/dev/acpica/acpi_hpet.c index 95f2b32..a789418 100644 --- a/sys/dev/acpica/acpi_hpet.c +++ b/sys/dev/acpica/acpi_hpet.c @@ -154,15 +154,16 @@ hpet_start(struct eventtimer *et, t->div = (sc->freq * (period->frac >> 32)) >> 32; if (period->sec != 0) t->div += sc->freq * period->sec; - if (first == NULL) - first = period; } else { t->mode = 2; t->div = 0; } - fdiv = (sc->freq * (first->frac >> 32)) >> 32; - if (first->sec != 0) - fdiv += sc->freq * first->sec; + if (first != NULL) { + fdiv = (sc->freq * (first->frac >> 32)) >> 32; + if (first->sec != 0) + fdiv += sc->freq * first->sec; + } else + fdiv = t->div; t->last = bus_read_4(sc->mem_res, HPET_MAIN_COUNTER); if (t->mode == 1 && (t->caps & HPET_TCAP_PER_INT)) { t->caps |= HPET_TCNF_TYPE; @@ -583,6 +584,11 @@ hpet_attach(device_t dev) if ((t->caps & HPET_TCAP_PER_INT) == 0) t->et.et_quality -= 10; t->et.et_frequency = sc->freq; + t->et.et_min_period.sec = 0; + t->et.et_min_period.frac = 0x00004000LL << 32; + t->et.et_max_period.sec = 0xffffffff / sc->freq; + t->et.et_max_period.frac = + ((0xffffffffLL << 32) / sc->freq) << 32; t->et.et_start = hpet_start; t->et.et_stop = hpet_stop; t->et.et_priv = &sc->t[i]; diff --git a/sys/kern/kern_clocksource.c b/sys/kern/kern_clocksource.c index 697275a..9656db6 100644 --- a/sys/kern/kern_clocksource.c +++ b/sys/kern/kern_clocksource.c @@ -87,11 +87,9 @@ static DPCPU_DEFINE(tc, configtimer); (bt)->sec = 0; \ (bt)->frac = ((uint64_t)0x8000000000000000 / (freq)) << 1; \ } -#define BT2FREQ(bt, freq) \ -{ \ - *(freq) = ((uint64_t)0x8000000000000000 + ((bt)->frac >> 2)) / \ - ((bt)->frac >> 1); \ -} +#define BT2FREQ(bt) \ + (((uint64_t)0x8000000000000000 + ((bt)->frac >> 2)) / \ + ((bt)->frac >> 1)) /* Per-CPU timer1 handler. */ static int @@ -295,6 +293,26 @@ restart: #endif } +static int +round_freq(struct eventtimer *et, int freq) +{ + uint64_t div; + + if (et->et_frequency != 0) { + div = (et->et_frequency + freq / 2) / freq; + if (et->et_flags & ET_FLAGS_POW2DIV) + div = 1 << (flsl(div + div / 2) - 1); + freq = (et->et_frequency + div / 2) / div; + } + if (et->et_min_period.sec > 0) + freq = 0; + else if (et->et_max_period.frac != 0) + freq = min(freq, BT2FREQ(&et->et_min_period)); + if (et->et_max_period.sec == 0 && et->et_max_period.frac != 0) + freq = max(freq, BT2FREQ(&et->et_max_period)); + return (freq); +} + /* * Configure and start event timers. */ @@ -327,21 +345,25 @@ cpu_initclocks_bsp(void) singlemul = 4; } if (timer[1] == NULL) { - base = hz * singlemul; - if (base < 128) + base = round_freq(timer[0], hz * singlemul); + singlemul = max((base + hz / 2) / hz, 1); + hz = (base + singlemul / 2) / singlemul; + if (base <= 128) stathz = base; else { div = base / 128; - if (div % 2 == 0) + if (div >= singlemul && (div % singlemul) == 0) div++; stathz = base / div; } profhz = stathz; - while ((profhz + stathz) <= 8192) + while ((profhz + stathz) <= 128 * 64) profhz += stathz; + profhz = round_freq(timer[0], profhz); } else { - stathz = 128; - profhz = stathz * 64; + hz = round_freq(timer[0], hz); + stathz = round_freq(timer[1], 127); + profhz = round_freq(timer[1], stathz * 64); } ET_LOCK(); cpu_restartclocks(); @@ -385,7 +407,9 @@ cpu_restartclocks(void) } else { timer1hz = hz; timer2hz = profiling_on ? profhz : stathz; + timer2hz = round_freq(timer[1], timer2hz); } + timer1hz = round_freq(timer[0], timer1hz); printf("Starting kernel event timers: %s @ %dHz, %s @ %dHz\n", timer[0]->et_name, timer1hz, timer[1] ? timer[1]->et_name : "NONE", timer2hz); diff --git a/sys/kern/kern_et.c b/sys/kern/kern_et.c index 52fb705..61a2500 100644 --- a/sys/kern/kern_et.c +++ b/sys/kern/kern_et.c @@ -167,6 +167,26 @@ et_start(struct eventtimer *et, if ((et->et_flags & ET_FLAGS_ONESHOT) == 0 && period == NULL) return (ENODEV); + if (first != NULL) { + if (first->sec < et->et_min_period.sec || + (first->sec == et->et_min_period.sec && + first->frac < et->et_min_period.frac)) + first = &et->et_min_period; + if (first->sec > et->et_max_period.sec || + (first->sec == et->et_max_period.sec && + first->frac > et->et_max_period.frac)) + first = &et->et_max_period; + } + if (period != NULL) { + if (period->sec < et->et_min_period.sec || + (period->sec == et->et_min_period.sec && + period->frac < et->et_min_period.frac)) + period = &et->et_min_period; + if (period->sec > et->et_max_period.sec || + (period->sec == et->et_max_period.sec && + period->frac > et->et_max_period.frac)) + period = &et->et_max_period; + } if (et->et_start) return (et->et_start(et, first, period)); return (0); diff --git a/sys/sys/timeet.h b/sys/sys/timeet.h index bafa55a..bc713d6 100644 --- a/sys/sys/timeet.h +++ b/sys/sys/timeet.h @@ -61,6 +61,7 @@ struct eventtimer { #define ET_FLAGS_ONESHOT 2 #define ET_FLAGS_PERCPU 4 #define ET_FLAGS_C3STOP 8 +#define ET_FLAGS_POW2DIV 16 int et_quality; /* * Used to determine if this timecounter is better than @@ -69,6 +70,8 @@ struct eventtimer { int et_active; u_int64_t et_frequency; /* Base frequency in Hz. */ + struct bintime et_min_period; + struct bintime et_max_period; et_start_t *et_start; et_stop_t *et_stop; et_event_cb_t *et_event_cb; diff --git a/sys/x86/isa/atrtc.c b/sys/x86/isa/atrtc.c index 5a5ba63..b01e933 100644 --- a/sys/x86/isa/atrtc.c +++ b/sys/x86/isa/atrtc.c @@ -276,9 +276,13 @@ atrtc_attach(device_t dev) bus_bind_intr(dev, sc->intr_res, 0); } sc->et.et_name = "RTC"; - sc->et.et_flags = ET_FLAGS_PERIODIC; + sc->et.et_flags = ET_FLAGS_PERIODIC | ET_FLAGS_POW2DIV; sc->et.et_quality = 0; sc->et.et_frequency = 32768; + sc->et.et_min_period.sec = 0; + sc->et.et_min_period.frac = 0x0008LL << 48; + sc->et.et_max_period.sec = 0; + sc->et.et_max_period.frac = 0x8000LL << 48; sc->et.et_start = rtc_start; sc->et.et_stop = rtc_stop; sc->et.et_priv = dev; diff --git a/sys/x86/isa/clock.c b/sys/x86/isa/clock.c index 6b5fede..62869a6 100644 --- a/sys/x86/isa/clock.c +++ b/sys/x86/isa/clock.c @@ -665,6 +665,11 @@ attimer_attach(device_t dev) sc->et.et_flags = ET_FLAGS_PERIODIC; sc->et.et_quality = 100; sc->et.et_frequency = i8254_freq; + sc->et.et_min_period.sec = 0; + sc->et.et_min_period.frac = ((1LL << 62) / i8254_freq) << 2; + sc->et.et_max_period.sec = 0xffff / i8254_freq; + sc->et.et_max_period.frac = + ((0xffffLL << 48) / i8254_freq) << 16; sc->et.et_start = attimer_start; sc->et.et_stop = attimer_stop; sc->et.et_priv = dev; diff --git a/sys/x86/x86/local_apic.c b/sys/x86/x86/local_apic.c index 4364fb1..ffa34a5 100644 --- a/sys/x86/x86/local_apic.c +++ b/sys/x86/x86/local_apic.c @@ -263,6 +263,11 @@ lapic_init(vm_paddr_t addr) lapic_et.et_quality -= 100; } lapic_et.et_frequency = 0; + /* We don't know frequency yet, so trying to guess. */ + lapic_et.et_min_period.sec = 0; + lapic_et.et_min_period.frac = 0x00001000LL << 32; + lapic_et.et_max_period.sec = 1; + lapic_et.et_max_period.frac = 0; lapic_et.et_start = lapic_et_start; lapic_et.et_stop = lapic_et_stop; lapic_et.et_priv = NULL; @@ -493,6 +498,12 @@ lapic_et_start(struct eventtimer *et, printf("lapic: Divisor %lu, Frequency %lu Hz\n", lapic_timer_divisor, value); et->et_frequency = value; + et->et_min_period.sec = 0; + et->et_min_period.frac = + ((1LL << 63) / et->et_frequency) << 1; + et->et_max_period.sec = 0xffffffff / et->et_frequency; + et->et_max_period.frac = + ((0xffffffffLL << 32) / et->et_frequency) << 32; } la = &lapics[lapic_id()]; /* |