acpi_timer.c (cace7a2a4d49e2588f5fb0b5ebd56b59c47e1b31) acpi_timer.c (be2b179704218e240b66f023545f8e97d4c29a08)
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:

--- 28 unchanged lines hidden (view full) ---

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"
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:

--- 28 unchanged lines hidden (view full) ---

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
46#include <dev/acpica/acpivar.h>
47#include <dev/pci/pcivar.h>
48
49/*
50 * A timecounter based on the free-running ACPI timer.
51 *
52 * Based on the i386-only mp_clock.c by <phk@FreeBSD.ORG>.
53 */
54
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
55/*
56 * Hooks for the ACPI CA debugging infrastructure
57 */
54/* Hooks for the ACPI CA debugging infrastructure */
58#define _COMPONENT ACPI_SYSTEM
59ACPI_MODULE_NAME("TIMER")
60
61static device_t acpi_timer_dev;
62struct resource *acpi_timer_reg;
63
55#define _COMPONENT ACPI_SYSTEM
56ACPI_MODULE_NAME("TIMER")
57
58static device_t acpi_timer_dev;
59struct resource *acpi_timer_reg;
60
64static u_int acpi_timer_frequency = 14318182/4;
61static u_int acpi_timer_frequency = 14318182 / 4;
65
66static void acpi_timer_identify(driver_t *driver, device_t parent);
67static int acpi_timer_probe(device_t dev);
68static int acpi_timer_attach(device_t dev);
69static unsigned acpi_timer_get_timecount(struct timecounter *tc);
70static unsigned acpi_timer_get_timecount_safe(struct timecounter *tc);
71static int acpi_timer_sysctl_freq(SYSCTL_HANDLER_ARGS);
72static void acpi_timer_test(void);
73
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
74static u_int32_t read_counter(void);
75static int test_counter(void);
71static uint32_t read_counter(void);
72static int test_counter(void);
76
73
77/*
78 * Driver hung off ACPI.
79 */
80static device_method_t acpi_timer_methods[] = {
81 DEVMETHOD(device_identify, acpi_timer_identify),
82 DEVMETHOD(device_probe, acpi_timer_probe),
83 DEVMETHOD(device_attach, acpi_timer_attach),
84
85 {0, 0}
86};
87
88static driver_t acpi_timer_driver = {
89 "acpi_timer",
90 acpi_timer_methods,
91 0,
92};
93
94static devclass_t acpi_timer_devclass;
95DRIVER_MODULE(acpi_timer, acpi, acpi_timer_driver, acpi_timer_devclass, 0, 0);
96
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
97/*
98 * Timecounter.
99 */
100static struct timecounter acpi_timer_timecounter = {
101 acpi_timer_get_timecount_safe,
102 0,
103 0xffffff,
104 0,
105 "ACPI",
106 1000
107};
108
91static struct timecounter acpi_timer_timecounter = {
92 acpi_timer_get_timecount_safe,
93 0,
94 0xffffff,
95 0,
96 "ACPI",
97 1000
98};
99
109
110static u_int32_t
100static uint32_t
111read_counter()
112{
101read_counter()
102{
113 bus_space_handle_t bsh;
114 bus_space_tag_t bst;
115 u_int32_t tv;
103 bus_space_handle_t bsh;
104 bus_space_tag_t bst;
105 u_int32_t tv;
116
106
117 bsh = rman_get_bushandle(acpi_timer_reg);
118 bst = rman_get_bustag(acpi_timer_reg);
119 tv = bus_space_read_4(bst, bsh, 0);
120 bus_space_barrier(bst, bsh, 0, 4, BUS_SPACE_BARRIER_READ);
121 return (tv);
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);
122}
123
124#define N 2000
125static int
126test_counter()
127{
113}
114
115#define N 2000
116static int
117test_counter()
118{
128 int min, max, n, delta;
129 unsigned last, this;
119 u_int last, this;
120 int min, max, n, delta;
130
121
131 min = 10000000;
132 max = 0;
133 last = read_counter();
134 for (n = 0; n < N; n++) {
135 this = read_counter();
136 delta = (this - last) & 0xffffff;
137 if (delta > max)
138 max = delta;
139 else if (delta < min)
140 min = delta;
141 last = this;
142 }
143 if (max - min > 2)
144 n = 0;
145 else if (min < 0 || max == 0)
146 n = 0;
147 else
148 n = 1;
149 if (bootverbose)
150 printf("ACPI timer looks %s min = %d, max = %d, width = %d\n",
151 n ? "GOOD" : "BAD ",
152 min, max, max - min);
153 return (n);
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);
154}
147}
148#undef N
155
156/*
157 * Locate the ACPI timer using the FADT, set up and allocate the I/O resources
158 * we will be using.
159 */
160static void
161acpi_timer_identify(driver_t *driver, device_t parent)
162{
163 device_t dev;
164 char desc[40];
165 u_long rlen, rstart;
166 int i, j, rid, rtype;
167
168 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
169
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
170 if (acpi_disabled("timer"))
164 if (acpi_disabled("timer") || AcpiGbl_FADT == NULL)
171 return_VOID;
165 return_VOID;
172
173 if (AcpiGbl_FADT == NULL)
174 return_VOID;
175
176 if ((dev = BUS_ADD_CHILD(parent, 0, "acpi_timer", 0)) == NULL) {
177 device_printf(parent, "could not add acpi_timer0\n");
178 return_VOID;
179 }
180 acpi_timer_dev = dev;
181
182 rid = 0;
183 rlen = AcpiGbl_FADT->PmTmLen;
184 rtype = (AcpiGbl_FADT->XPmTmrBlk.AddressSpaceId)
185 ? SYS_RES_IOPORT : SYS_RES_MEMORY;
186 rstart = AcpiGbl_FADT->XPmTmrBlk.Address;
187 bus_set_resource(dev, rtype, rid, rstart, rlen);
188 acpi_timer_reg = bus_alloc_resource(dev, rtype, &rid, 0, ~0, 1, RF_ACTIVE);
189 if (acpi_timer_reg == NULL) {
190 device_printf(dev, "couldn't allocate I/O resource (%s 0x%lx)\n",
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",
191 (rtype == SYS_RES_IOPORT) ? "port" : "mem", rstart);
182 rtype == SYS_RES_IOPORT ? "port" : "mem", rstart);
192 return_VOID;
193 }
194 if (testenv("debug.acpi.timer_test"))
195 acpi_timer_test();
196
197 acpi_timer_timecounter.tc_frequency = acpi_timer_frequency;
198 j = 0;
199 for(i = 0; i < 10; i++)
200 j += test_counter();
201 if (j == 10) {
202 acpi_timer_timecounter.tc_name = "ACPI-fast";
203 acpi_timer_timecounter.tc_get_timecount = acpi_timer_get_timecount;
204 } else {
205 acpi_timer_timecounter.tc_name = "ACPI-safe";
206 acpi_timer_timecounter.tc_get_timecount = acpi_timer_get_timecount_safe;
207 }
208 tc_init(&acpi_timer_timecounter);
209
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
210 sprintf(desc, "%d-bit timer at 3.579545MHz", (AcpiGbl_FADT->TmrValExt)
211 ? 32 : 24);
201 sprintf(desc, "%d-bit timer at 3.579545MHz",
202 AcpiGbl_FADT->TmrValExt ? 32 : 24);
212 device_set_desc_copy(dev, desc);
213
214 return_VOID;
215}
216
217static int
218acpi_timer_probe(device_t dev)
219{
220 if (dev == acpi_timer_dev)
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)
221 return(0);
222 return(ENXIO);
212 return (0);
213
214 return (ENXIO);
223}
224
225static int
226acpi_timer_attach(device_t dev)
227{
215}
216
217static int
218acpi_timer_attach(device_t dev)
219{
228 return(0);
220 return (0);
229}
230
231/*
232 * Fetch current time value from reliable hardware.
233 */
234static unsigned
235acpi_timer_get_timecount(struct timecounter *tc)
236{

--- 10 unchanged lines hidden (view full) ---

247 unsigned u1, u2, u3;
248
249 u2 = read_counter();
250 u3 = read_counter();
251 do {
252 u1 = u2;
253 u2 = u3;
254 u3 = read_counter();
221}
222
223/*
224 * Fetch current time value from reliable hardware.
225 */
226static unsigned
227acpi_timer_get_timecount(struct timecounter *tc)
228{

--- 10 unchanged lines hidden (view full) ---

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();
255 } while (u1 > u2 || u2 > u3 || (u3 - u1) > 15);
247 } while (u1 > u2 || u2 > u3 || u3 - u1 > 15);
248
256 return (u2);
257}
258
259/*
260 * Timecounter freqency adjustment interface.
261 */
262static int
263acpi_timer_sysctl_freq(SYSCTL_HANDLER_ARGS)

--- 4 unchanged lines hidden (view full) ---

268 if (acpi_timer_timecounter.tc_frequency == 0)
269 return (EOPNOTSUPP);
270 freq = acpi_timer_frequency;
271 error = sysctl_handle_int(oidp, &freq, sizeof(freq), req);
272 if (error == 0 && req->newptr != NULL) {
273 acpi_timer_frequency = freq;
274 acpi_timer_timecounter.tc_frequency = acpi_timer_frequency;
275 }
249 return (u2);
250}
251
252/*
253 * Timecounter freqency adjustment interface.
254 */
255static int
256acpi_timer_sysctl_freq(SYSCTL_HANDLER_ARGS)

--- 4 unchanged lines hidden (view full) ---

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
276 return (error);
277}
278
279SYSCTL_PROC(_machdep, OID_AUTO, acpi_timer_freq, CTLTYPE_INT | CTLFLAG_RW,
280 0, sizeof(u_int), acpi_timer_sysctl_freq, "I", "");
281
282/*
283 * Test harness for verifying ACPI timer behaviour.

--- 6 unchanged lines hidden (view full) ---

290
291 u1 = read_counter();
292 u2 = read_counter();
293 u3 = read_counter();
294
295 device_printf(acpi_timer_dev, "timer test in progress, reboot to quit.\n");
296 for (;;) {
297 /*
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.

--- 6 unchanged lines hidden (view full) ---

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 /*
298 * The failure case is where u3 > u1, but u2 does not fall between the two,
299 * ie. it contains garbage.
292 * The failure case is where u3 > u1, but u2 does not fall between
293 * the two, ie. it contains garbage.
300 */
301 if (u3 > u1) {
294 */
295 if (u3 > u1) {
302 if ((u2 < u1) || (u2 > u3))
303 device_printf(acpi_timer_dev, "timer is not monotonic: 0x%08x,0x%08x,0x%08x\n",
296 if (u2 < u1 || u2 > u3)
297 device_printf(acpi_timer_dev,
298 "timer is not monotonic: 0x%08x,0x%08x,0x%08x\n",
304 u1, u2, u3);
305 }
306 u1 = u2;
307 u2 = u3;
308 u3 = read_counter();
309 }
310}
311

--- 42 unchanged lines hidden (view full) ---

354
355static driver_t acpi_timer_pci_driver = {
356 "acpi_timer_pci",
357 acpi_timer_pci_methods,
358 0,
359};
360
361devclass_t acpi_timer_pci_devclass;
299 u1, u2, u3);
300 }
301 u1 = u2;
302 u2 = u3;
303 u3 = read_counter();
304 }
305}
306

--- 42 unchanged lines hidden (view full) ---

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;
362DRIVER_MODULE(acpi_timer_pci, pci, acpi_timer_pci_driver, acpi_timer_pci_devclass, 0, 0);
357DRIVER_MODULE(acpi_timer_pci, pci, acpi_timer_pci_driver,
358 acpi_timer_pci_devclass, 0, 0);
363
364/*
365 * Look at PCI devices going past; if we detect one we know contains
366 * a functional ACPI timer device, enable the faster timecounter read
367 * routine.
368 */
369static int
370acpi_timer_pci_probe(device_t dev)
371{
372 int vendor, device, revid;
373
374 vendor = pci_get_vendor(dev);
375 device = pci_get_device(dev);
376 revid = pci_get_revid(dev);
377
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
378 if (((vendor == 0x8086) && (device == 0x7113) && (revid >= 0x03)) || /* PIIX4M */
379 ((vendor == 0x8086) && (device == 0x719b)) || /* i440MX */
380 0) {
374 /* Detect the PIIX4M and i440MX, respectively */
375 if ((vendor == 0x8086 && device == 0x7113 && revid >= 0x03) ||
376 (vendor == 0x8086 && device == 0x719b)) {
381
382 acpi_timer_timecounter.tc_get_timecount = acpi_timer_get_timecount;
383 acpi_timer_timecounter.tc_name = "ACPI-fast";
377
378 acpi_timer_timecounter.tc_get_timecount = acpi_timer_get_timecount;
379 acpi_timer_timecounter.tc_name = "ACPI-fast";
384 if (bootverbose)
385 device_printf(acpi_timer_dev, "functional ACPI timer detected, enabling fast timecount interface\n");
380 if (bootverbose) {
381 device_printf(acpi_timer_dev,"functional ACPI timer detected, "
382 "enabling fast timecount interface\n");
383 }
386 }
387
384 }
385
388 return(ENXIO); /* we never match anything */
386 /* We never match anything */
387 return (ENXIO);
389}
390#endif
388}
389#endif