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