From cc3e0b577549733067ade63ad57bf356e1fc5db1 Mon Sep 17 00:00:00 2001 From: phk Date: Mon, 25 Feb 2002 09:51:17 +0000 Subject: [PATCH] Add a new test_counter() function which tries to determine the width of the inter-value histogram for 2000 samples. If the width is 3 or less for 10 consequtive samples, we trust the counter to be good, otherwise we use the *_safe() method. This method may be too strict, but the worst which can happen is that we take the performance hit of the *_safe() method when we should not. Make the *_safe() method more discriminating by mandating that the three samples do not span more than 15 ticks on the counter. Disable the PCI-ident based probing as a means to recognize good counters. Inspiration from: dillon and msmith --- sys/dev/acpica/acpi_timer.c | 63 +++++++++++++++++++++++++++---------- 1 file changed, 46 insertions(+), 17 deletions(-) diff --git a/sys/dev/acpica/acpi_timer.c b/sys/dev/acpica/acpi_timer.c index 6de76416359c..6117a6f9d5e2 100644 --- a/sys/dev/acpica/acpi_timer.c +++ b/sys/dev/acpica/acpi_timer.c @@ -104,6 +104,38 @@ static struct timecounter acpi_timer_timecounter = { SYSCTL_OPAQUE(_debug, OID_AUTO, acpi_timecounter, CTLFLAG_RD, &acpi_timer_timecounter, sizeof(acpi_timer_timecounter), "S,timecounter", ""); +static int test_counter(void); + +#define N 2000 +static int +test_counter() +{ + int min, max, n, delta; + unsigned last, this; + + min = 10000000; + max = 0; + last = TIMER_READ; + for (n = 0; n < N; n++) { + this = TIMER_READ; + delta = (this - last) & 0xffffff; + if (delta > max) + max = delta; + else if (delta < min) + min = delta; + last = this; + } + if (max - min > 2) + n = 0; + else if (min < 0) + n = 0; + else + n = 1; + printf("ACPI timer looks %s min = %d, max = %d, width = %d\n", + n ? "GOOD" : "BAD ", + min, max, max - min + 1); + return (n); +} /* * Locate the ACPI timer using the FADT, set up and allocate the I/O resources @@ -114,7 +146,7 @@ acpi_timer_identify(driver_t *driver, device_t parent) { device_t dev; char desc[40]; - int rid; + int rid, i, j; ACPI_FUNCTION_TRACE(__func__); @@ -138,27 +170,22 @@ acpi_timer_identify(driver_t *driver, device_t parent) if (getenv("debug.acpi.timer_test") != NULL) acpi_timer_test(); - acpi_timer_timecounter.tc_get_timecount = acpi_timer_get_timecount_safe; acpi_timer_timecounter.tc_frequency = acpi_timer_frequency; + j = 0; + for(i = 0; i < 10; i++) + j += test_counter(); + if (j == 10) { + acpi_timer_timecounter.tc_name = "ACPI-fast"; + acpi_timer_timecounter.tc_get_timecount = acpi_timer_get_timecount; + } else { + acpi_timer_timecounter.tc_name = "ACPI-safe"; + acpi_timer_timecounter.tc_get_timecount = acpi_timer_get_timecount_safe; + } tc_init(&acpi_timer_timecounter); sprintf(desc, "%d-bit timer at 3.579545MHz", AcpiGbl_FADT->TmrValExt ? 32 : 24); device_set_desc_copy(dev, desc); -#if 0 - { - u_int64_t first; - - first = rdtsc(); - acpi_timer_get_timecount(NULL); - printf("acpi_timer_get_timecount %lld cycles\n", rdtsc() - first); - - first = rdtsc(); - acpi_timer_get_timecount_safe(NULL); - printf("acpi_timer_get_timecount_safe %lld cycles\n", rdtsc() - first); - } -#endif - return_VOID; } @@ -200,7 +227,7 @@ acpi_timer_get_timecount_safe(struct timecounter *tc) u1 = u2; u2 = u3; u3 = TIMER_READ; - } while (u1 > u2 || u2 > u3); + } while (u1 > u2 || u2 > u3 || (u3 - u1) > 15); return (u2); } @@ -293,6 +320,7 @@ acpi_timer_test(void) * directions. If we only cared about monosity two reads would be enough. */ +#if 0 static int acpi_timer_pci_probe(device_t dev); static device_method_t acpi_timer_pci_methods[] = { @@ -335,3 +363,4 @@ acpi_timer_pci_probe(device_t dev) return(ENXIO); /* we never match anything */ } +#endif