From owner-freebsd-current Sun Feb 17 15:34: 1 2002 Delivered-To: freebsd-current@freebsd.org Received: from apollo.backplane.com (apollo.backplane.com [216.240.41.2]) by hub.freebsd.org (Postfix) with ESMTP id E3B2337B400; Sun, 17 Feb 2002 15:33:56 -0800 (PST) Received: (from dillon@localhost) by apollo.backplane.com (8.11.6/8.9.1) id g1HNXuh07529; Sun, 17 Feb 2002 15:33:56 -0800 (PST) (envelope-from dillon) Date: Sun, 17 Feb 2002 15:33:56 -0800 (PST) From: Matthew Dillon Message-Id: <200202172333.g1HNXuh07529@apollo.backplane.com> To: Michael Smith Cc: Poul-Henning Kamp , Bruce Evans , freebsd-current@FreeBSD.ORG Subject: ACPI patch (was Re: 'microuptime() went backwards ...' using ACPI...) References: <200202172225.g1HMPKA01422@mass.dis.org> Sender: owner-freebsd-current@FreeBSD.ORG Precedence: bulk List-ID: List-Archive: (Web Archive) List-Help: (List Instructions) List-Subscribe: List-Unsubscribe: X-Loop: FreeBSD.ORG Ok, here is a patch that executes a brute-force solution to the asynchronous counter problem. Basically it figures out a mask and then the timer code loops until two masked reads yield the same value, guarenteeing that we haven't caught the timer during a carry. On my system, the mask I got was: 0xFFFFFFFC which means I lost only 2 bits of accuracy in order to be able to retrieve accurate counter values. This gives my particular box an approximately 1uS accuracy. I think this may be the only safe way to do it. It looks like it is possible to catch the ripple and/or fast-carry on *any* bit, with the statistical chance of it occuring on higher bits dropping by 2x per bit. My proposed (tested) patch is below. Mike? acpi_timer0: <32-bit timer at 3.579545MHz mask fffffffc> port 0x808-0x80b on acpi0 -Matt Index: acpi_timer.c =================================================================== RCS file: /home/ncvs/src/sys/dev/acpica/acpi_timer.c,v retrieving revision 1.11 diff -u -r1.11 acpi_timer.c --- acpi_timer.c 8 Jan 2002 06:45:56 -0000 1.11 +++ acpi_timer.c 17 Feb 2002 23:26:29 -0000 @@ -56,6 +56,7 @@ MODULE_NAME("TIMER") static device_t acpi_timer_dev; +static u_int32_t acpi_timer_mask; struct resource *acpi_timer_reg; #define TIMER_READ bus_space_read_4(rman_get_bustag(acpi_timer_reg), \ rman_get_bushandle(acpi_timer_reg), \ @@ -113,7 +114,7 @@ acpi_timer_identify(driver_t *driver, device_t parent) { device_t dev; - char desc[40]; + char desc[48]; int rid; FUNCTION_TRACE(__func__); @@ -138,14 +139,32 @@ if (getenv("debug.acpi.timer_test") != NULL) acpi_timer_test(); - acpi_timer_timecounter.tc_get_timecount = acpi_timer_get_timecount; + acpi_timer_timecounter.tc_get_timecount = acpi_timer_get_timecount_safe; acpi_timer_timecounter.tc_frequency = acpi_timer_frequency; tc_init(&acpi_timer_timecounter); - sprintf(desc, "%d-bit timer at 3.579545MHz", AcpiGbl_FADT->TmrValExt ? 32 : 24); + for (acpi_timer_mask = 0xFFFFFFFF; acpi_timer_mask; acpi_timer_mask <<= 1) { + u_int32_t u1; + u_int32_t u2; + int count = 10; + + u1 = TIMER_READ; + u2 = TIMER_READ; + while (count && ((u1 ^ u2) & acpi_timer_mask)) { + u1 = u2; + u2 = TIMER_READ; + --count; + } + if (count) + break; + } + acpi_timer_mask <<= 1; + + sprintf(desc, "%d-bit timer at 3.579545MHz mask %08x", + (AcpiGbl_FADT->TmrValExt ? 32 : 24), acpi_timer_mask); device_set_desc_copy(dev, desc); -#if 0 +#if 0 { u_int64_t first; @@ -192,16 +211,22 @@ static unsigned acpi_timer_get_timecount_safe(struct timecounter *tc) { - unsigned u1, u2, u3; + u_int32_t u1; + u_int32_t u2; + u1 = TIMER_READ; u2 = TIMER_READ; - u3 = TIMER_READ; - do { + while ((u1 ^ u2) & acpi_timer_mask) { u1 = u2; - u2 = u3; - u3 = TIMER_READ; - } while (u1 > u2 || u2 > u3); - return (u2); + u2 = TIMER_READ; + } +#if 0 /* DEBUGGING */ + if (u2 < u1) { + u_int32_t u3 = TIMER_READ; + printf("ACPI TIMER LSB MISREAD %08x %08x %08x\n", u1, u2, u3); + } +#endif + return(u2 & acpi_timer_mask); } /* To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-current" in the body of the message