diff options
author | phk <phk@FreeBSD.org> | 2002-02-25 09:51:17 +0000 |
---|---|---|
committer | phk <phk@FreeBSD.org> | 2002-02-25 09:51:17 +0000 |
commit | cc3e0b577549733067ade63ad57bf356e1fc5db1 (patch) | |
tree | aa5d0209a0cf7c74df530bf24ba45845e51a1286 /sys/dev | |
parent | 96af38570e5bb404afd2fddd82c10f429fe147b6 (diff) | |
download | FreeBSD-src-cc3e0b577549733067ade63ad57bf356e1fc5db1.zip FreeBSD-src-cc3e0b577549733067ade63ad57bf356e1fc5db1.tar.gz |
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
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/acpica/acpi_timer.c | 63 |
1 files changed, 46 insertions, 17 deletions
diff --git a/sys/dev/acpica/acpi_timer.c b/sys/dev/acpica/acpi_timer.c index 6de7641..6117a6f 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 |