Instead of storing last event timestamp, store the next event timestamp.
It corrects handling of the first event offset in emulated periodic mode.
This commit is contained in:
parent
8b14990639
commit
8b0db56f3b
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user