Module Name: src Committed By: yamt Date: Mon Oct 31 12:47:15 UTC 2011
Modified Files: src/sys/dev/ic: hpet.c hpetreg.h Log Message: hpet: - fix an integer overflow bug introduced by hpet.c rev.1.11. - a workaround for AMD SB700 based systems, inspired from linux. To generate a diff of this commit: cvs rdiff -u -r1.12 -r1.13 src/sys/dev/ic/hpet.c cvs rdiff -u -r1.3 -r1.4 src/sys/dev/ic/hpetreg.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.12 src/sys/dev/ic/hpet.c:1.13 --- src/sys/dev/ic/hpet.c:1.12 Fri Jul 29 19:19:14 2011 +++ src/sys/dev/ic/hpet.c Mon Oct 31 12:47:15 2011 @@ -1,4 +1,4 @@ -/* $NetBSD: hpet.c,v 1.12 2011/07/29 19:19:14 jakllsch Exp $ */ +/* $NetBSD: hpet.c,v 1.13 2011/10/31 12:47:15 yamt Exp $ */ /* * Copyright (c) 2006 Nicolas Joly @@ -33,7 +33,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: hpet.c,v 1.12 2011/07/29 19:19:14 jakllsch Exp $"); +__KERNEL_RCSID(0, "$NetBSD: hpet.c,v 1.13 2011/10/31 12:47:15 yamt Exp $"); #include <sys/systm.h> #include <sys/device.h> @@ -71,7 +71,9 @@ hpet_attach_subr(device_t dv) { struct hpet_softc *sc = device_private(dv); struct timecounter *tc; + uint64_t tmp; uint32_t val; + int i; tc = &sc->sc_tc; @@ -83,12 +85,27 @@ hpet_attach_subr(device_t dv) /* Get frequency */ val = bus_space_read_4(sc->sc_memt, sc->sc_memh, HPET_PERIOD); - if (val == 0) { + if (val == 0 || val > HPET_PERIOD_MAX) { aprint_error_dev(dv, "invalid timer period\n"); return; } - val = (1000000000000000ULL * 2) / val; - tc->tc_frequency = (val / 2) + (val & 1); + + /* + * The following loop is a workaround for AMD SB700 based systems. + * http://kerneltrap.org/mailarchive/git-commits-head/2008/8/17/2964724 + * http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=a6825f1c1fa83b1e92b6715ee5771a4d6524d3b9 + */ + for (i = 0; bus_space_read_4(sc->sc_memt, sc->sc_memh, HPET_CONFIG) + == 0xffffffff; i++) { + if (i >= 1000) { + aprint_error_dev(dv, + "HPET_CONFIG value = 0xffffffff\n"); + return; + } + } + + tmp = (1000000000000000ULL * 2) / val; + tc->tc_frequency = (tmp / 2) + (tmp & 1); /* Enable timer */ val = bus_space_read_4(sc->sc_memt, sc->sc_memh, HPET_CONFIG); Index: src/sys/dev/ic/hpetreg.h diff -u src/sys/dev/ic/hpetreg.h:1.3 src/sys/dev/ic/hpetreg.h:1.4 --- src/sys/dev/ic/hpetreg.h:1.3 Fri Feb 15 22:14:10 2008 +++ src/sys/dev/ic/hpetreg.h Mon Oct 31 12:47:15 2011 @@ -1,4 +1,4 @@ -/* $NetBSD: hpetreg.h,v 1.3 2008/02/15 22:14:10 jmcneill Exp $ */ +/* $NetBSD: hpetreg.h,v 1.4 2011/10/31 12:47:15 yamt Exp $ */ /* * Copyright (c) 2006 Nicolas Joly @@ -36,6 +36,7 @@ #define HPET_INFO 0x00 #define HPET_INFO_64BITS 0x2000 #define HPET_PERIOD 0x04 +#define HPET_PERIOD_MAX 100000000 #define HPET_CONFIG 0x10 #define HPET_CONFIG_ENABLE 0x0001 #define HPET_CONFIG_LEGRTCNF 0x0002