Module Name: src Committed By: ad Date: Thu Apr 23 20:33:57 UTC 2020
Modified Files: src/sys/dev/ic: hpet.c hpetvar.h Log Message: Implement a HPET based DELAY(). To generate a diff of this commit: cvs rdiff -u -r1.13 -r1.14 src/sys/dev/ic/hpet.c cvs rdiff -u -r1.4 -r1.5 src/sys/dev/ic/hpetvar.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/dev/ic/hpet.c diff -u src/sys/dev/ic/hpet.c:1.13 src/sys/dev/ic/hpet.c:1.14 --- src/sys/dev/ic/hpet.c:1.13 Mon Oct 31 12:47:15 2011 +++ src/sys/dev/ic/hpet.c Thu Apr 23 20:33:57 2020 @@ -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.1 #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.1 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_ 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 Index: src/sys/dev/ic/hpetvar.h diff -u src/sys/dev/ic/hpetvar.h:1.4 src/sys/dev/ic/hpetvar.h:1.5 --- src/sys/dev/ic/hpetvar.h:1.4 Tue Jun 14 16:33:51 2011 +++ src/sys/dev/ic/hpetvar.h Thu Apr 23 20:33:57 2020 @@ -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_ */