acpi_timer.c revision 1.2 1 /* $NetBSD: acpi_timer.c,v 1.2 2006/06/26 12:29:36 drochner Exp $ */
2
3 #include <sys/types.h>
4
5 #ifdef __HAVE_TIMECOUNTER
6
7 #include <sys/systm.h>
8 #include <sys/time.h>
9 #include <sys/timetc.h>
10 #include <dev/acpi/acpica.h>
11 #include <dev/acpi/acpi_timer.h>
12
13 static int acpitimer_test(void);
14 static uint32_t acpitimer_delta(uint32_t, uint32_t);
15 static u_int acpitimer_read_safe(struct timecounter *);
16 static u_int acpitimer_read_fast(struct timecounter *);
17
18 static struct timecounter acpi_timecounter = {
19 acpitimer_read_safe,
20 0,
21 0x00ffffff,
22 PM_TIMER_FREQUENCY,
23 "ACPI-Safe",
24 900
25 };
26
27 int
28 acpitimer_init()
29 {
30 uint32_t bits;
31 int i, j;
32 ACPI_STATUS res;
33
34 res = AcpiGetTimerResolution(&bits);
35 if (res != AE_OK)
36 return (-1);
37
38 if (bits == 32)
39 acpi_timecounter.tc_counter_mask = 0xffffffff;
40
41 j = 0;
42 for (i = 0; i < 10; i++)
43 j += acpitimer_test();
44 aprint_verbose("acpitimer_test(): %d\n", j);
45 if (j >= 10) {
46 acpi_timecounter.tc_name = "ACPI-Fast";
47 acpi_timecounter.tc_get_timecount = acpitimer_read_fast;
48 acpi_timecounter.tc_quality = 1000;
49 }
50
51 tc_init(&acpi_timecounter);
52 aprint_normal("%s %d-bit timer\n", acpi_timecounter.tc_name, bits);
53
54 return (0);
55 }
56
57 static u_int
58 acpitimer_read_fast(struct timecounter *tc)
59 {
60 uint32_t t;
61
62 AcpiGetTimer(&t);
63 return (t);
64 }
65
66 /*
67 * Some chipsets (PIIX4 variants) do not latch correctly; there
68 * is a chance that a transition is hit.
69 */
70 static u_int
71 acpitimer_read_safe(struct timecounter *tc)
72 {
73 uint32_t t1, t2, t3;
74
75 AcpiGetTimer(&t2);
76 AcpiGetTimer(&t3);
77 do {
78 t1 = t2;
79 t2 = t3;
80 AcpiGetTimer(&t3);
81 } while ((t1 > t2) || (t2 > t3));
82 return (t2);
83 }
84
85 static uint32_t
86 acpitimer_delta(uint32_t end, uint32_t start)
87 {
88 uint32_t delta;
89 u_int mask = acpi_timecounter.tc_counter_mask;
90
91 if (end >= start)
92 delta = end - start;
93 else
94 delta = ((mask - start) + end + 1) & mask;
95
96 return (delta);
97 }
98
99 #define N 2000
100 static int
101 acpitimer_test()
102 {
103 uint32_t last, this, delta;
104 int minl, maxl, n;
105
106 minl = 10000000;
107 maxl = 0;
108
109 disable_intr();
110 AcpiGetTimer(&last);
111 for (n = 0; n < N; n++) {
112 AcpiGetTimer(&this);
113 delta = acpitimer_delta(this, last);
114 if (delta > maxl)
115 maxl = delta;
116 else if (delta < minl)
117 minl = delta;
118 last = this;
119 }
120 enable_intr();
121
122 if (maxl - minl > 2 )
123 n = 0;
124 else if (minl < 0 || maxl == 0)
125 n = 0;
126 else
127 n = 1;
128
129 return (n);
130 }
131
132 #else
133
134 int
135 acpitimer_init()
136 {
137
138 return (0);
139 }
140
141 #endif
142