diff options
author | mav <mav@FreeBSD.org> | 2010-09-12 11:11:53 +0000 |
---|---|---|
committer | mav <mav@FreeBSD.org> | 2010-09-12 11:11:53 +0000 |
commit | 8b0db56f3b487a497fdeb31ed06ae3a6237ab78f (patch) | |
tree | 2c5f262ab40a4ffa56ce5a45e1d788cd77c5043a | |
parent | 8b14990639479c66cee0501932e741378332a085 (diff) | |
download | FreeBSD-src-8b0db56f3b487a497fdeb31ed06ae3a6237ab78f.zip FreeBSD-src-8b0db56f3b487a497fdeb31ed06ae3a6237ab78f.tar.gz |
Instead of storing last event timestamp, store the next event timestamp.
It corrects handling of the first event offset in emulated periodic mode.
-rw-r--r-- | sys/dev/acpica/acpi_hpet.c | 47 |
1 files changed, 28 insertions, 19 deletions
diff --git a/sys/dev/acpica/acpi_hpet.c b/sys/dev/acpica/acpi_hpet.c index 656a395..bc8cd85 100644 --- a/sys/dev/acpica/acpi_hpet.c +++ b/sys/dev/acpica/acpi_hpet.c @@ -98,7 +98,7 @@ struct hpet_softc { uint32_t caps; uint32_t vectors; uint32_t div; - uint32_t last; + uint32_t next; char name[8]; } t[32]; int num_timers; @@ -149,7 +149,7 @@ hpet_start(struct eventtimer *et, struct hpet_timer *mt = (struct hpet_timer *)et->et_priv; struct hpet_timer *t; struct hpet_softc *sc = mt->sc; - uint32_t fdiv, cmp; + uint32_t fdiv, now; t = (mt->pcpu_master < 0) ? mt : &sc->t[mt->pcpu_slaves[curcpu]]; if (period != NULL) { @@ -170,24 +170,28 @@ hpet_start(struct eventtimer *et, if (t->irq < 0) bus_write_4(sc->mem_res, HPET_ISR, 1 << t->num); t->caps |= HPET_TCNF_INT_ENB; - t->last = bus_read_4(sc->mem_res, HPET_MAIN_COUNTER); + now = bus_read_4(sc->mem_res, HPET_MAIN_COUNTER); restart: - cmp = t->last + fdiv; + t->next = now + fdiv; if (t->mode == 1 && (t->caps & HPET_TCAP_PER_INT)) { t->caps |= HPET_TCNF_TYPE; bus_write_4(sc->mem_res, HPET_TIMER_CAP_CNF(t->num), t->caps | HPET_TCNF_VAL_SET); - bus_write_4(sc->mem_res, HPET_TIMER_COMPARATOR(t->num), cmp); - bus_write_4(sc->mem_res, HPET_TIMER_COMPARATOR(t->num), t->div); + bus_write_4(sc->mem_res, HPET_TIMER_COMPARATOR(t->num), + t->next); + bus_write_4(sc->mem_res, HPET_TIMER_COMPARATOR(t->num), + t->div); } else { t->caps &= ~HPET_TCNF_TYPE; - bus_write_4(sc->mem_res, HPET_TIMER_CAP_CNF(t->num), t->caps); - bus_write_4(sc->mem_res, HPET_TIMER_COMPARATOR(t->num), cmp); + bus_write_4(sc->mem_res, HPET_TIMER_CAP_CNF(t->num), + t->caps); + bus_write_4(sc->mem_res, HPET_TIMER_COMPARATOR(t->num), + t->next); } if (fdiv < 5000) { bus_read_4(sc->mem_res, HPET_TIMER_COMPARATOR(t->num)); - t->last = bus_read_4(sc->mem_res, HPET_MAIN_COUNTER); - if ((int32_t)(t->last - cmp) >= 0) { + now = bus_read_4(sc->mem_res, HPET_MAIN_COUNTER); + if ((int32_t)(now - t->next) >= 0) { fdiv *= 2; goto restart; } @@ -217,6 +221,8 @@ hpet_intr_single(void *arg) struct hpet_softc *sc = t->sc; uint32_t now; + if (t->mode == 0) + return (FILTER_STRAY); /* Check that per-CPU timer interrupt reached right CPU. */ if (t->pcpu_cpu >= 0 && t->pcpu_cpu != curcpu) { if ((++t->pcpu_misrouted) % 32 == 0) { @@ -231,20 +237,21 @@ hpet_intr_single(void *arg) */ if ((t->mode == 1 && (t->caps & HPET_TCAP_PER_INT) == 0) || t->mode == 2) { - t->last = bus_read_4(sc->mem_res, HPET_MAIN_COUNTER); + t->next = bus_read_4(sc->mem_res, HPET_MAIN_COUNTER) + + sc->freq / 8; bus_write_4(sc->mem_res, HPET_TIMER_COMPARATOR(t->num), - t->last + sc->freq / 8); + t->next); } return (FILTER_HANDLED); } if (t->mode == 1 && (t->caps & HPET_TCAP_PER_INT) == 0) { - t->last += t->div; + t->next += t->div; now = bus_read_4(sc->mem_res, HPET_MAIN_COUNTER); - if ((int32_t)(now - (t->last + t->div / 2)) > 0) - t->last = now - t->div / 2; + if ((int32_t)((now + t->div / 2) - t->next) > 0) + t->next = now + t->div / 2; bus_write_4(sc->mem_res, - HPET_TIMER_COMPARATOR(t->num), t->last + t->div); + HPET_TIMER_COMPARATOR(t->num), t->next); } else if (t->mode == 2) t->mode = 0; mt = (t->pcpu_master < 0) ? t : &sc->t[t->pcpu_master]; @@ -713,19 +720,21 @@ hpet_resume(device_t dev) #endif if (t->mode == 0) continue; - t->last = bus_read_4(sc->mem_res, HPET_MAIN_COUNTER); + t->next = bus_read_4(sc->mem_res, HPET_MAIN_COUNTER); if (t->mode == 1 && (t->caps & HPET_TCAP_PER_INT)) { t->caps |= HPET_TCNF_TYPE; + t->next += t->div; bus_write_4(sc->mem_res, HPET_TIMER_CAP_CNF(t->num), t->caps | HPET_TCNF_VAL_SET); bus_write_4(sc->mem_res, HPET_TIMER_COMPARATOR(t->num), - t->last + t->div); + t->next); bus_read_4(sc->mem_res, HPET_TIMER_COMPARATOR(t->num)); bus_write_4(sc->mem_res, HPET_TIMER_COMPARATOR(t->num), t->div); } else { + t->next += sc->freq / 1024; bus_write_4(sc->mem_res, HPET_TIMER_COMPARATOR(t->num), - t->last + sc->freq / 1024); + t->next); } bus_write_4(sc->mem_res, HPET_ISR, 1 << t->num); bus_write_4(sc->mem_res, HPET_TIMER_CAP_CNF(t->num), t->caps); |