Implement a HPET based DELAY().
This commit is contained in:
parent
d8fa6d0b7a
commit
e5210a69c7
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: hpet.c,v 1.13 2011/10/31 12:47:15 yamt Exp $ */
|
||||
/* $NetBSD: hpet.c,v 1.14 2020/04/23 20:33:57 ad Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2006 Nicolas Joly
|
||||
@ -33,7 +33,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: hpet.c,v 1.13 2011/10/31 12:47:15 yamt Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: hpet.c,v 1.14 2020/04/23 20:33:57 ad Exp $");
|
||||
|
||||
#include <sys/systm.h>
|
||||
#include <sys/device.h>
|
||||
@ -43,6 +43,7 @@ __KERNEL_RCSID(0, "$NetBSD: hpet.c,v 1.13 2011/10/31 12:47:15 yamt Exp $");
|
||||
#include <sys/timetc.h>
|
||||
|
||||
#include <sys/bus.h>
|
||||
#include <sys/lock.h>
|
||||
|
||||
#include <dev/ic/hpetreg.h>
|
||||
#include <dev/ic/hpetvar.h>
|
||||
@ -50,9 +51,12 @@ __KERNEL_RCSID(0, "$NetBSD: hpet.c,v 1.13 2011/10/31 12:47:15 yamt Exp $");
|
||||
static u_int hpet_get_timecount(struct timecounter *);
|
||||
static bool hpet_resume(device_t, const pmf_qual_t *);
|
||||
|
||||
static struct hpet_softc *hpet0 __read_mostly;
|
||||
|
||||
int
|
||||
hpet_detach(device_t dv, int flags)
|
||||
{
|
||||
#if 0 /* XXX DELAY() is based off this, detaching is not a good idea. */
|
||||
struct hpet_softc *sc = device_private(dv);
|
||||
int rc;
|
||||
|
||||
@ -64,6 +68,9 @@ hpet_detach(device_t dv, int flags)
|
||||
bus_space_write_4(sc->sc_memt, sc->sc_memh, HPET_CONFIG, sc->sc_config);
|
||||
|
||||
return 0;
|
||||
#else
|
||||
return EBUSY;
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
@ -84,8 +91,8 @@ hpet_attach_subr(device_t dv)
|
||||
tc->tc_counter_mask = 0xffffffff;
|
||||
|
||||
/* Get frequency */
|
||||
val = bus_space_read_4(sc->sc_memt, sc->sc_memh, HPET_PERIOD);
|
||||
if (val == 0 || val > HPET_PERIOD_MAX) {
|
||||
sc->sc_period = bus_space_read_4(sc->sc_memt, sc->sc_memh, HPET_PERIOD);
|
||||
if (sc->sc_period == 0 || sc->sc_period > HPET_PERIOD_MAX) {
|
||||
aprint_error_dev(dv, "invalid timer period\n");
|
||||
return;
|
||||
}
|
||||
@ -104,7 +111,7 @@ hpet_attach_subr(device_t dv)
|
||||
}
|
||||
}
|
||||
|
||||
tmp = (1000000000000000ULL * 2) / val;
|
||||
tmp = (1000000000000000ULL * 2) / sc->sc_period;
|
||||
tc->tc_frequency = (tmp / 2) + (tmp & 1);
|
||||
|
||||
/* Enable timer */
|
||||
@ -120,6 +127,9 @@ hpet_attach_subr(device_t dv)
|
||||
|
||||
if (!pmf_device_register(dv, NULL, hpet_resume))
|
||||
aprint_error_dev(dv, "couldn't establish power handler\n");
|
||||
|
||||
if (device_unit(dv) == 0)
|
||||
hpet0 = sc;
|
||||
}
|
||||
|
||||
static u_int
|
||||
@ -143,6 +153,38 @@ hpet_resume(device_t dv, const pmf_qual_t *qual)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
hpet_delay_p(void)
|
||||
{
|
||||
|
||||
return hpet0 != NULL;
|
||||
}
|
||||
|
||||
void
|
||||
hpet_delay(unsigned int us)
|
||||
{
|
||||
struct hpet_softc *sc;
|
||||
uint32_t ntick, otick;
|
||||
int64_t delta;
|
||||
|
||||
/*
|
||||
* Read timer before slow division. Assume that each read of the
|
||||
* HPET costs ~500ns. Aim for the middle and subtract 750ns for
|
||||
* overhead.
|
||||
*/
|
||||
sc = hpet0;
|
||||
otick = bus_space_read_4(sc->sc_memt, sc->sc_memh, HPET_MCOUNT_LO);
|
||||
delta = (((int64_t)us * 1000000000) - 750000000) / sc->sc_period;
|
||||
|
||||
while (delta > 0) {
|
||||
SPINLOCK_BACKOFF_HOOK;
|
||||
ntick = bus_space_read_4(sc->sc_memt, sc->sc_memh,
|
||||
HPET_MCOUNT_LO);
|
||||
delta -= (uint32_t)(ntick - otick);
|
||||
otick = ntick;
|
||||
}
|
||||
}
|
||||
|
||||
MODULE(MODULE_CLASS_DRIVER, hpet, NULL);
|
||||
|
||||
#ifdef _MODULE
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: hpetvar.h,v 1.4 2011/06/14 16:33:51 jruoho Exp $ */
|
||||
/* $NetBSD: hpetvar.h,v 1.5 2020/04/23 20:33:57 ad Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2006 Nicolas Joly
|
||||
@ -31,6 +31,8 @@
|
||||
#ifndef _DEV_IC_HPETVAR_H_
|
||||
#define _DEV_IC_HPETVAR_H_
|
||||
|
||||
#include <sys/timetc.h>
|
||||
|
||||
struct hpet_softc {
|
||||
bus_size_t sc_mems;
|
||||
bus_space_tag_t sc_memt;
|
||||
@ -38,10 +40,13 @@ struct hpet_softc {
|
||||
|
||||
bool sc_mapped;
|
||||
uint32_t sc_config;
|
||||
int32_t sc_period;
|
||||
struct timecounter sc_tc;
|
||||
};
|
||||
|
||||
void hpet_attach_subr(device_t);
|
||||
int hpet_detach(device_t, int flags);
|
||||
void hpet_delay(unsigned int);
|
||||
bool hpet_delay_p(void);
|
||||
|
||||
#endif /* _DEV_IC_HPETVAR_H_ */
|
||||
|
Loading…
Reference in New Issue
Block a user