acpi_timer.c revision 126517
1131962Smp/*-
259243Sobrien * Copyright (c) 2000, 2001 Michael Smith
359243Sobrien * Copyright (c) 2000 BSDi
459243Sobrien * All rights reserved.
559243Sobrien *
659243Sobrien * Redistribution and use in source and binary forms, with or without
759243Sobrien * modification, are permitted provided that the following conditions
859243Sobrien * are met:
959243Sobrien * 1. Redistributions of source code must retain the above copyright
1059243Sobrien *    notice, this list of conditions and the following disclaimer.
1159243Sobrien * 2. Redistributions in binary form must reproduce the above copyright
1259243Sobrien *    notice, this list of conditions and the following disclaimer in the
1359243Sobrien *    documentation and/or other materials provided with the distribution.
1459243Sobrien *
1559243Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1659243Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17131962Smp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 *	$FreeBSD: head/sys/dev/acpica/acpi_timer.c 126517 2004-03-03 03:02:17Z njl $
28 */
29#include "opt_acpi.h"
30#include <sys/param.h>
31#include <sys/bus.h>
32#include <sys/kernel.h>
33#include <sys/sysctl.h>
34#if __FreeBSD_version >= 500000
35#include <sys/timetc.h>
36#else
37#include <sys/time.h>
38#endif
39
40#include <machine/bus.h>
41#include <machine/resource.h>
42#include <sys/rman.h>
43
44#include "acpi.h"
45#include <dev/acpica/acpivar.h>
46#include <dev/pci/pcivar.h>
47
48/*
49 * A timecounter based on the free-running ACPI timer.
50 *
51 * Based on the i386-only mp_clock.c by <phk@FreeBSD.ORG>.
52 */
53
54/* Hooks for the ACPI CA debugging infrastructure */
55#define _COMPONENT	ACPI_TIMER
56ACPI_MODULE_NAME("TIMER")
57
58static device_t	acpi_timer_dev;
59struct resource	*acpi_timer_reg;
60
61static u_int	acpi_timer_frequency = 14318182 / 4;
62
63static void	acpi_timer_identify(driver_t *driver, device_t parent);
64static int	acpi_timer_probe(device_t dev);
65static int	acpi_timer_attach(device_t dev);
66static unsigned	acpi_timer_get_timecount(struct timecounter *tc);
67static unsigned	acpi_timer_get_timecount_safe(struct timecounter *tc);
68static int	acpi_timer_sysctl_freq(SYSCTL_HANDLER_ARGS);
69static void	acpi_timer_test(void);
70
71static uint32_t read_counter(void);
72static int	test_counter(void);
73
74static device_method_t acpi_timer_methods[] = {
75    DEVMETHOD(device_identify,	acpi_timer_identify),
76    DEVMETHOD(device_probe,	acpi_timer_probe),
77    DEVMETHOD(device_attach,	acpi_timer_attach),
78
79    {0, 0}
80};
81
82static driver_t acpi_timer_driver = {
83    "acpi_timer",
84    acpi_timer_methods,
85    0,
86};
87
88static devclass_t acpi_timer_devclass;
89DRIVER_MODULE(acpi_timer, acpi, acpi_timer_driver, acpi_timer_devclass, 0, 0);
90
91static struct timecounter acpi_timer_timecounter = {
92	acpi_timer_get_timecount_safe,
93	0,
94	0xffffff,
95	0,
96	"ACPI",
97	1000
98};
99
100static uint32_t
101read_counter()
102{
103    bus_space_handle_t bsh;
104    bus_space_tag_t bst;
105    u_int32_t tv;
106
107    bsh = rman_get_bushandle(acpi_timer_reg);
108    bst = rman_get_bustag(acpi_timer_reg);
109    tv = bus_space_read_4(bst, bsh, 0);
110    bus_space_barrier(bst, bsh, 0, 4, BUS_SPACE_BARRIER_READ);
111
112    return (tv);
113}
114
115#define N 2000
116static int
117test_counter()
118{
119    u_int	last, this;
120    int		min, max, n, delta;
121
122    min = 10000000;
123    max = 0;
124    last = read_counter();
125    for (n = 0; n < N; n++) {
126	this = read_counter();
127	delta = (this - last) & 0xffffff;
128	if (delta > max)
129	    max = delta;
130	else if (delta < min)
131	    min = delta;
132	last = this;
133    }
134    if (max - min > 2)
135	n = 0;
136    else if (min < 0 || max == 0)
137	n = 0;
138    else
139	n = 1;
140    if (bootverbose) {
141	printf("ACPI timer looks %s min = %d, max = %d, width = %d\n",
142		n ? "GOOD" : "BAD ",
143		min, max, max - min);
144    }
145
146    return (n);
147}
148#undef N
149
150/*
151 * Locate the ACPI timer using the FADT, set up and allocate the I/O resources
152 * we will be using.
153 */
154static void
155acpi_timer_identify(driver_t *driver, device_t parent)
156{
157    device_t	dev;
158    char	desc[40];
159    u_long	rlen, rstart;
160    int		i, j, rid, rtype;
161
162    ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
163
164    if (acpi_disabled("timer") || AcpiGbl_FADT == NULL)
165	return_VOID;
166
167    if ((dev = BUS_ADD_CHILD(parent, 0, "acpi_timer", 0)) == NULL) {
168	device_printf(parent, "could not add acpi_timer0\n");
169	return_VOID;
170    }
171    acpi_timer_dev = dev;
172
173    rid = 0;
174    rlen = AcpiGbl_FADT->PmTmLen;
175    rtype = (AcpiGbl_FADT->XPmTmrBlk.AddressSpaceId)
176      ? SYS_RES_IOPORT : SYS_RES_MEMORY;
177    rstart = AcpiGbl_FADT->XPmTmrBlk.Address;
178    bus_set_resource(dev, rtype, rid, rstart, rlen);
179    acpi_timer_reg = bus_alloc_resource(dev, rtype, &rid, 0, ~0, 1, RF_ACTIVE);
180    if (acpi_timer_reg == NULL) {
181	device_printf(dev, "couldn't allocate I/O resource (%s 0x%lx)\n",
182		      rtype == SYS_RES_IOPORT ? "port" : "mem", rstart);
183	return_VOID;
184    }
185    if (testenv("debug.acpi.timer_test"))
186	acpi_timer_test();
187
188    acpi_timer_timecounter.tc_frequency = acpi_timer_frequency;
189    j = 0;
190    for(i = 0; i < 10; i++)
191	j += test_counter();
192    if (j == 10) {
193	acpi_timer_timecounter.tc_name = "ACPI-fast";
194	acpi_timer_timecounter.tc_get_timecount = acpi_timer_get_timecount;
195    } else {
196	acpi_timer_timecounter.tc_name = "ACPI-safe";
197	acpi_timer_timecounter.tc_get_timecount = acpi_timer_get_timecount_safe;
198    }
199    tc_init(&acpi_timer_timecounter);
200
201    sprintf(desc, "%d-bit timer at 3.579545MHz",
202	    AcpiGbl_FADT->TmrValExt ? 32 : 24);
203    device_set_desc_copy(dev, desc);
204
205    return_VOID;
206}
207
208static int
209acpi_timer_probe(device_t dev)
210{
211    if (dev == acpi_timer_dev)
212	return (0);
213
214    return (ENXIO);
215}
216
217static int
218acpi_timer_attach(device_t dev)
219{
220    return (0);
221}
222
223/*
224 * Fetch current time value from reliable hardware.
225 */
226static unsigned
227acpi_timer_get_timecount(struct timecounter *tc)
228{
229    return (read_counter());
230}
231
232/*
233 * Fetch current time value from hardware that may not correctly
234 * latch the counter.
235 */
236static unsigned
237acpi_timer_get_timecount_safe(struct timecounter *tc)
238{
239    unsigned u1, u2, u3;
240
241    u2 = read_counter();
242    u3 = read_counter();
243    do {
244	u1 = u2;
245	u2 = u3;
246	u3 = read_counter();
247    } while (u1 > u2 || u2 > u3 || u3 - u1 > 15);
248
249    return (u2);
250}
251
252/*
253 * Timecounter freqency adjustment interface.
254 */
255static int
256acpi_timer_sysctl_freq(SYSCTL_HANDLER_ARGS)
257{
258    int error;
259    u_int freq;
260
261    if (acpi_timer_timecounter.tc_frequency == 0)
262	return (EOPNOTSUPP);
263    freq = acpi_timer_frequency;
264    error = sysctl_handle_int(oidp, &freq, sizeof(freq), req);
265    if (error == 0 && req->newptr != NULL) {
266	acpi_timer_frequency = freq;
267	acpi_timer_timecounter.tc_frequency = acpi_timer_frequency;
268    }
269
270    return (error);
271}
272
273SYSCTL_PROC(_machdep, OID_AUTO, acpi_timer_freq, CTLTYPE_INT | CTLFLAG_RW,
274	    0, sizeof(u_int), acpi_timer_sysctl_freq, "I", "");
275
276/*
277 * Test harness for verifying ACPI timer behaviour.
278 * Boot with debug.acpi.timer_test set to invoke this.
279 */
280static void
281acpi_timer_test(void)
282{
283    u_int32_t	u1, u2, u3;
284
285    u1 = read_counter();
286    u2 = read_counter();
287    u3 = read_counter();
288
289    device_printf(acpi_timer_dev, "timer test in progress, reboot to quit.\n");
290    for (;;) {
291	/*
292	 * The failure case is where u3 > u1, but u2 does not fall between
293	 * the two, ie. it contains garbage.
294	 */
295	if (u3 > u1) {
296	    if (u2 < u1 || u2 > u3)
297		device_printf(acpi_timer_dev,
298			      "timer is not monotonic: 0x%08x,0x%08x,0x%08x\n",
299			      u1, u2, u3);
300	}
301	u1 = u2;
302	u2 = u3;
303	u3 = read_counter();
304    }
305}
306
307/*
308 * Chipset workaround driver hung off PCI.
309 *
310 * Some ACPI timers are known or believed to suffer from implementation
311 * problems which can lead to erroneous values being read from the timer.
312 *
313 * Since we can't trust unknown chipsets, we default to a timer-read
314 * routine which compensates for the most common problem (as detailed
315 * in the excerpt from the Intel PIIX4 datasheet below).
316 *
317 * When we detect a known-functional chipset, we disable the workaround
318 * to improve speed.
319 *
320 * ] 20. ACPI Timer Errata
321 * ]
322 * ]   Problem: The power management timer may return improper result when
323 * ]   read. Although the timer value settles properly after incrementing,
324 * ]   while incrementing there is a 3nS window every 69.8nS where the
325 * ]   timer value is indeterminate (a 4.2% chance that the data will be
326 * ]   incorrect when read). As a result, the ACPI free running count up
327 * ]   timer specification is violated due to erroneous reads.  Implication:
328 * ]   System hangs due to the "inaccuracy" of the timer when used by
329 * ]   software for time critical events and delays.
330 * ]
331 * ] Workaround: Read the register twice and compare.
332 * ] Status: This will not be fixed in the PIIX4 or PIIX4E, it is fixed
333 * ] in the PIIX4M.
334 *
335 * The counter is in other words not latched to the PCI bus clock when
336 * read.  Notice the workaround isn't:  We need to read until we have
337 * three monotonic samples and then use the middle one, otherwise we are
338 * not protected against the fact that the bits can be wrong in two
339 * directions.  If we only cared about monosity two reads would be enough.
340 */
341
342#if 0
343static int	acpi_timer_pci_probe(device_t dev);
344
345static device_method_t acpi_timer_pci_methods[] = {
346    DEVMETHOD(device_probe,	acpi_timer_pci_probe),
347    {0, 0}
348};
349
350static driver_t acpi_timer_pci_driver = {
351    "acpi_timer_pci",
352    acpi_timer_pci_methods,
353    0,
354};
355
356devclass_t acpi_timer_pci_devclass;
357DRIVER_MODULE(acpi_timer_pci, pci, acpi_timer_pci_driver,
358	      acpi_timer_pci_devclass, 0, 0);
359
360/*
361 * Look at PCI devices going past; if we detect one we know contains
362 * a functional ACPI timer device, enable the faster timecounter read
363 * routine.
364 */
365static int
366acpi_timer_pci_probe(device_t dev)
367{
368    int vendor, device, revid;
369
370    vendor = pci_get_vendor(dev);
371    device = pci_get_device(dev);
372    revid  = pci_get_revid(dev);
373
374    /* Detect the PIIX4M and i440MX, respectively */
375    if ((vendor == 0x8086 && device == 0x7113 && revid >= 0x03)	||
376	(vendor == 0x8086 && device == 0x719b)) {
377
378	acpi_timer_timecounter.tc_get_timecount = acpi_timer_get_timecount;
379	acpi_timer_timecounter.tc_name = "ACPI-fast";
380	if (bootverbose) {
381	    device_printf(acpi_timer_dev,"functional ACPI timer detected, "
382			  "enabling fast timecount interface\n");
383	}
384    }
385
386    /* We never match anything */
387    return (ENXIO);
388}
389#endif
390