Deleted Added
full compact
acpi_hpet.c (212238) acpi_hpet.c (212323)
1/*-
2 * Copyright (c) 2005 Poul-Henning Kamp
3 * Copyright (c) 2010 Alexander Motin <mav@FreeBSD.org>
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
28#include <sys/cdefs.h>
1/*-
2 * Copyright (c) 2005 Poul-Henning Kamp
3 * Copyright (c) 2010 Alexander Motin <mav@FreeBSD.org>
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
28#include <sys/cdefs.h>
29__FBSDID("$FreeBSD: head/sys/dev/acpica/acpi_hpet.c 212238 2010-09-05 19:24:32Z mav $");
29__FBSDID("$FreeBSD: head/sys/dev/acpica/acpi_hpet.c 212323 2010-09-08 16:59:22Z mav $");
30
31#include "opt_acpi.h"
32#if defined(__amd64__) || defined(__ia64__)
33#define DEV_APIC
34#else
35#include "opt_apic.h"
36#endif
37#include <sys/param.h>
38#include <sys/bus.h>
39#include <sys/kernel.h>
40#include <sys/module.h>
41#include <sys/proc.h>
42#include <sys/rman.h>
43#include <sys/time.h>
44#include <sys/smp.h>
45#include <sys/sysctl.h>
46#include <sys/timeet.h>
47#include <sys/timetc.h>
48
49#include <contrib/dev/acpica/include/acpi.h>
50#include <contrib/dev/acpica/include/accommon.h>
51
52#include <dev/acpica/acpivar.h>
53#include <dev/acpica/acpi_hpet.h>
54
55#ifdef DEV_APIC
56#include "pcib_if.h"
57#endif
58
59#define HPET_VENDID_AMD 0x4353
60#define HPET_VENDID_INTEL 0x8086
61
62ACPI_SERIAL_DECL(hpet, "ACPI HPET support");
63
64static devclass_t hpet_devclass;
65
66/* ACPI CA debugging */
67#define _COMPONENT ACPI_TIMER
68ACPI_MODULE_NAME("HPET")
69
70struct hpet_softc {
71 device_t dev;
72 int mem_rid;
73 int intr_rid;
74 int irq;
75 int useirq;
76 int legacy_route;
77 uint32_t allowed_irqs;
78 struct resource *mem_res;
79 struct resource *intr_res;
80 void *intr_handle;
81 ACPI_HANDLE handle;
82 uint64_t freq;
83 uint32_t caps;
84 struct timecounter tc;
85 struct hpet_timer {
86 struct eventtimer et;
87 struct hpet_softc *sc;
88 int num;
89 int mode;
90 int intr_rid;
91 int irq;
30
31#include "opt_acpi.h"
32#if defined(__amd64__) || defined(__ia64__)
33#define DEV_APIC
34#else
35#include "opt_apic.h"
36#endif
37#include <sys/param.h>
38#include <sys/bus.h>
39#include <sys/kernel.h>
40#include <sys/module.h>
41#include <sys/proc.h>
42#include <sys/rman.h>
43#include <sys/time.h>
44#include <sys/smp.h>
45#include <sys/sysctl.h>
46#include <sys/timeet.h>
47#include <sys/timetc.h>
48
49#include <contrib/dev/acpica/include/acpi.h>
50#include <contrib/dev/acpica/include/accommon.h>
51
52#include <dev/acpica/acpivar.h>
53#include <dev/acpica/acpi_hpet.h>
54
55#ifdef DEV_APIC
56#include "pcib_if.h"
57#endif
58
59#define HPET_VENDID_AMD 0x4353
60#define HPET_VENDID_INTEL 0x8086
61
62ACPI_SERIAL_DECL(hpet, "ACPI HPET support");
63
64static devclass_t hpet_devclass;
65
66/* ACPI CA debugging */
67#define _COMPONENT ACPI_TIMER
68ACPI_MODULE_NAME("HPET")
69
70struct hpet_softc {
71 device_t dev;
72 int mem_rid;
73 int intr_rid;
74 int irq;
75 int useirq;
76 int legacy_route;
77 uint32_t allowed_irqs;
78 struct resource *mem_res;
79 struct resource *intr_res;
80 void *intr_handle;
81 ACPI_HANDLE handle;
82 uint64_t freq;
83 uint32_t caps;
84 struct timecounter tc;
85 struct hpet_timer {
86 struct eventtimer et;
87 struct hpet_softc *sc;
88 int num;
89 int mode;
90 int intr_rid;
91 int irq;
92 int pcpu_cpu;
93 int pcpu_misrouted;
92 int pcpu_master;
93 int pcpu_slaves[MAXCPU];
94 struct resource *intr_res;
95 void *intr_handle;
96 uint32_t caps;
97 uint32_t vectors;
98 uint32_t div;
99 uint32_t last;
100 char name[8];
101 } t[32];
102 int num_timers;
103};
104
105static u_int hpet_get_timecount(struct timecounter *tc);
106static void hpet_test(struct hpet_softc *sc);
107
108static char *hpet_ids[] = { "PNP0103", NULL };
109
110static u_int
111hpet_get_timecount(struct timecounter *tc)
112{
113 struct hpet_softc *sc;
114
115 sc = tc->tc_priv;
116 return (bus_read_4(sc->mem_res, HPET_MAIN_COUNTER));
117}
118
119static void
120hpet_enable(struct hpet_softc *sc)
121{
122 uint32_t val;
123
124 val = bus_read_4(sc->mem_res, HPET_CONFIG);
125 if (sc->legacy_route)
126 val |= HPET_CNF_LEG_RT;
127 else
128 val &= ~HPET_CNF_LEG_RT;
129 val |= HPET_CNF_ENABLE;
130 bus_write_4(sc->mem_res, HPET_CONFIG, val);
131}
132
133static void
134hpet_disable(struct hpet_softc *sc)
135{
136 uint32_t val;
137
138 val = bus_read_4(sc->mem_res, HPET_CONFIG);
139 val &= ~HPET_CNF_ENABLE;
140 bus_write_4(sc->mem_res, HPET_CONFIG, val);
141}
142
143static int
144hpet_start(struct eventtimer *et,
145 struct bintime *first, struct bintime *period)
146{
147 struct hpet_timer *mt = (struct hpet_timer *)et->et_priv;
148 struct hpet_timer *t;
149 struct hpet_softc *sc = mt->sc;
150 uint32_t fdiv, cmp;
151
152 t = (mt->pcpu_master < 0) ? mt : &sc->t[mt->pcpu_slaves[curcpu]];
153 if (period != NULL) {
154 t->mode = 1;
155 t->div = (sc->freq * (period->frac >> 32)) >> 32;
156 if (period->sec != 0)
157 t->div += sc->freq * period->sec;
158 } else {
159 t->mode = 2;
160 t->div = 0;
161 }
162 if (first != NULL) {
163 fdiv = (sc->freq * (first->frac >> 32)) >> 32;
164 if (first->sec != 0)
165 fdiv += sc->freq * first->sec;
166 } else
167 fdiv = t->div;
168 if (t->irq < 0)
169 bus_write_4(sc->mem_res, HPET_ISR, 1 << t->num);
170 t->caps |= HPET_TCNF_INT_ENB;
171 t->last = bus_read_4(sc->mem_res, HPET_MAIN_COUNTER);
172restart:
173 cmp = t->last + fdiv;
174 if (t->mode == 1 && (t->caps & HPET_TCAP_PER_INT)) {
175 t->caps |= HPET_TCNF_TYPE;
176 bus_write_4(sc->mem_res, HPET_TIMER_CAP_CNF(t->num),
177 t->caps | HPET_TCNF_VAL_SET);
178 bus_write_4(sc->mem_res, HPET_TIMER_COMPARATOR(t->num), cmp);
179 bus_write_4(sc->mem_res, HPET_TIMER_COMPARATOR(t->num), t->div);
180 } else {
181 t->caps &= ~HPET_TCNF_TYPE;
182 bus_write_4(sc->mem_res, HPET_TIMER_CAP_CNF(t->num), t->caps);
183 bus_write_4(sc->mem_res, HPET_TIMER_COMPARATOR(t->num), cmp);
184 }
185 if (fdiv < 5000) {
186 bus_read_4(sc->mem_res, HPET_TIMER_COMPARATOR(t->num));
187 t->last = bus_read_4(sc->mem_res, HPET_MAIN_COUNTER);
94 int pcpu_master;
95 int pcpu_slaves[MAXCPU];
96 struct resource *intr_res;
97 void *intr_handle;
98 uint32_t caps;
99 uint32_t vectors;
100 uint32_t div;
101 uint32_t last;
102 char name[8];
103 } t[32];
104 int num_timers;
105};
106
107static u_int hpet_get_timecount(struct timecounter *tc);
108static void hpet_test(struct hpet_softc *sc);
109
110static char *hpet_ids[] = { "PNP0103", NULL };
111
112static u_int
113hpet_get_timecount(struct timecounter *tc)
114{
115 struct hpet_softc *sc;
116
117 sc = tc->tc_priv;
118 return (bus_read_4(sc->mem_res, HPET_MAIN_COUNTER));
119}
120
121static void
122hpet_enable(struct hpet_softc *sc)
123{
124 uint32_t val;
125
126 val = bus_read_4(sc->mem_res, HPET_CONFIG);
127 if (sc->legacy_route)
128 val |= HPET_CNF_LEG_RT;
129 else
130 val &= ~HPET_CNF_LEG_RT;
131 val |= HPET_CNF_ENABLE;
132 bus_write_4(sc->mem_res, HPET_CONFIG, val);
133}
134
135static void
136hpet_disable(struct hpet_softc *sc)
137{
138 uint32_t val;
139
140 val = bus_read_4(sc->mem_res, HPET_CONFIG);
141 val &= ~HPET_CNF_ENABLE;
142 bus_write_4(sc->mem_res, HPET_CONFIG, val);
143}
144
145static int
146hpet_start(struct eventtimer *et,
147 struct bintime *first, struct bintime *period)
148{
149 struct hpet_timer *mt = (struct hpet_timer *)et->et_priv;
150 struct hpet_timer *t;
151 struct hpet_softc *sc = mt->sc;
152 uint32_t fdiv, cmp;
153
154 t = (mt->pcpu_master < 0) ? mt : &sc->t[mt->pcpu_slaves[curcpu]];
155 if (period != NULL) {
156 t->mode = 1;
157 t->div = (sc->freq * (period->frac >> 32)) >> 32;
158 if (period->sec != 0)
159 t->div += sc->freq * period->sec;
160 } else {
161 t->mode = 2;
162 t->div = 0;
163 }
164 if (first != NULL) {
165 fdiv = (sc->freq * (first->frac >> 32)) >> 32;
166 if (first->sec != 0)
167 fdiv += sc->freq * first->sec;
168 } else
169 fdiv = t->div;
170 if (t->irq < 0)
171 bus_write_4(sc->mem_res, HPET_ISR, 1 << t->num);
172 t->caps |= HPET_TCNF_INT_ENB;
173 t->last = bus_read_4(sc->mem_res, HPET_MAIN_COUNTER);
174restart:
175 cmp = t->last + fdiv;
176 if (t->mode == 1 && (t->caps & HPET_TCAP_PER_INT)) {
177 t->caps |= HPET_TCNF_TYPE;
178 bus_write_4(sc->mem_res, HPET_TIMER_CAP_CNF(t->num),
179 t->caps | HPET_TCNF_VAL_SET);
180 bus_write_4(sc->mem_res, HPET_TIMER_COMPARATOR(t->num), cmp);
181 bus_write_4(sc->mem_res, HPET_TIMER_COMPARATOR(t->num), t->div);
182 } else {
183 t->caps &= ~HPET_TCNF_TYPE;
184 bus_write_4(sc->mem_res, HPET_TIMER_CAP_CNF(t->num), t->caps);
185 bus_write_4(sc->mem_res, HPET_TIMER_COMPARATOR(t->num), cmp);
186 }
187 if (fdiv < 5000) {
188 bus_read_4(sc->mem_res, HPET_TIMER_COMPARATOR(t->num));
189 t->last = bus_read_4(sc->mem_res, HPET_MAIN_COUNTER);
188 if ((int32_t)(t->last - cmp) < 0) {
190 if ((int32_t)(t->last - cmp) >= 0) {
189 fdiv *= 2;
190 goto restart;
191 }
192 }
193 return (0);
194}
195
196static int
197hpet_stop(struct eventtimer *et)
198{
199 struct hpet_timer *mt = (struct hpet_timer *)et->et_priv;
200 struct hpet_timer *t;
201 struct hpet_softc *sc = mt->sc;
202
203 t = (mt->pcpu_master < 0) ? mt : &sc->t[mt->pcpu_slaves[curcpu]];
204 t->mode = 0;
205 t->caps &= ~(HPET_TCNF_INT_ENB | HPET_TCNF_TYPE);
206 bus_write_4(sc->mem_res, HPET_TIMER_CAP_CNF(t->num), t->caps);
207 return (0);
208}
209
210static int
211hpet_intr_single(void *arg)
212{
213 struct hpet_timer *t = (struct hpet_timer *)arg;
214 struct hpet_timer *mt;
215 struct hpet_softc *sc = t->sc;
216 uint32_t now;
217
191 fdiv *= 2;
192 goto restart;
193 }
194 }
195 return (0);
196}
197
198static int
199hpet_stop(struct eventtimer *et)
200{
201 struct hpet_timer *mt = (struct hpet_timer *)et->et_priv;
202 struct hpet_timer *t;
203 struct hpet_softc *sc = mt->sc;
204
205 t = (mt->pcpu_master < 0) ? mt : &sc->t[mt->pcpu_slaves[curcpu]];
206 t->mode = 0;
207 t->caps &= ~(HPET_TCNF_INT_ENB | HPET_TCNF_TYPE);
208 bus_write_4(sc->mem_res, HPET_TIMER_CAP_CNF(t->num), t->caps);
209 return (0);
210}
211
212static int
213hpet_intr_single(void *arg)
214{
215 struct hpet_timer *t = (struct hpet_timer *)arg;
216 struct hpet_timer *mt;
217 struct hpet_softc *sc = t->sc;
218 uint32_t now;
219
220 /* Check that per-CPU timer interrupt reached right CPU. */
221 if (t->pcpu_cpu >= 0 && t->pcpu_cpu != curcpu) {
222 if ((++t->pcpu_misrouted) % 32 == 0) {
223 printf("HPET interrupt routed to the wrong CPU"
224 " (timer %d CPU %d -> %d)!\n",
225 t->num, t->pcpu_cpu, curcpu);
226 }
227
228 /*
229 * Reload timer, hoping that next time may be more lucky
230 * (system will manage proper interrupt binding).
231 */
232 if ((t->mode == 1 && (t->caps & HPET_TCAP_PER_INT) == 0) ||
233 t->mode == 2) {
234 t->last = bus_read_4(sc->mem_res, HPET_MAIN_COUNTER);
235 bus_write_4(sc->mem_res, HPET_TIMER_COMPARATOR(t->num),
236 t->last + sc->freq / 8);
237 }
238 return (FILTER_HANDLED);
239 }
218 if (t->mode == 1 &&
219 (t->caps & HPET_TCAP_PER_INT) == 0) {
220 t->last += t->div;
221 now = bus_read_4(sc->mem_res, HPET_MAIN_COUNTER);
222 if ((int32_t)(now - (t->last + t->div / 2)) > 0)
223 t->last = now - t->div / 2;
224 bus_write_4(sc->mem_res,
225 HPET_TIMER_COMPARATOR(t->num), t->last + t->div);
226 } else if (t->mode == 2)
227 t->mode = 0;
228 mt = (t->pcpu_master < 0) ? t : &sc->t[t->pcpu_master];
229 if (mt->et.et_active)
230 mt->et.et_event_cb(&mt->et, mt->et.et_arg);
231 return (FILTER_HANDLED);
232}
233
234static int
235hpet_intr(void *arg)
236{
237 struct hpet_softc *sc = (struct hpet_softc *)arg;
238 int i;
239 uint32_t val;
240
241 val = bus_read_4(sc->mem_res, HPET_ISR);
242 if (val) {
243 bus_write_4(sc->mem_res, HPET_ISR, val);
244 val &= sc->useirq;
245 for (i = 0; i < sc->num_timers; i++) {
246 if ((val & (1 << i)) == 0)
247 continue;
248 hpet_intr_single(&sc->t[i]);
249 }
250 return (FILTER_HANDLED);
251 }
252 return (FILTER_STRAY);
253}
254
255static ACPI_STATUS
256hpet_find(ACPI_HANDLE handle, UINT32 level, void *context,
257 void **status)
258{
259 char **ids;
260 uint32_t id = (uint32_t)(uintptr_t)context;
261 uint32_t uid = 0;
262
263 for (ids = hpet_ids; *ids != NULL; ids++) {
264 if (acpi_MatchHid(handle, *ids))
265 break;
266 }
267 if (*ids == NULL)
268 return (AE_OK);
269 if (ACPI_FAILURE(acpi_GetInteger(handle, "_UID", &uid)) ||
270 id == uid)
271 *((int *)status) = 1;
272 return (AE_OK);
273}
274
275/* Discover the HPET via the ACPI table of the same name. */
276static void
277hpet_identify(driver_t *driver, device_t parent)
278{
279 ACPI_TABLE_HPET *hpet;
280 ACPI_STATUS status;
281 device_t child;
282 int i, found;
283
284 /* Only one HPET device can be added. */
285 if (devclass_get_device(hpet_devclass, 0))
286 return;
287 for (i = 1; ; i++) {
288 /* Search for HPET table. */
289 status = AcpiGetTable(ACPI_SIG_HPET, i, (ACPI_TABLE_HEADER **)&hpet);
290 if (ACPI_FAILURE(status))
291 return;
292 /* Search for HPET device with same ID. */
293 found = 0;
294 AcpiWalkNamespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
295 100, hpet_find, NULL, (void *)(uintptr_t)hpet->Sequence, (void *)&found);
296 /* If found - let it be probed in normal way. */
297 if (found)
298 continue;
299 /* If not - create it from table info. */
300 child = BUS_ADD_CHILD(parent, ACPI_DEV_BASE_ORDER, "hpet", 0);
301 if (child == NULL) {
302 printf("%s: can't add child\n", __func__);
303 continue;
304 }
305 bus_set_resource(child, SYS_RES_MEMORY, 0, hpet->Address.Address,
306 HPET_MEM_WIDTH);
307 }
308}
309
310static int
311hpet_probe(device_t dev)
312{
313 ACPI_FUNCTION_TRACE((char *)(uintptr_t) __func__);
314
315 if (acpi_disabled("hpet"))
316 return (ENXIO);
317 if (acpi_get_handle(dev) != NULL &&
318 ACPI_ID_PROBE(device_get_parent(dev), dev, hpet_ids) == NULL)
319 return (ENXIO);
320
321 device_set_desc(dev, "High Precision Event Timer");
322 return (0);
323}
324
325static int
326hpet_attach(device_t dev)
327{
328 struct hpet_softc *sc;
329 struct hpet_timer *t;
330 int i, j, num_msi, num_timers, num_percpu_et, num_percpu_t, cur_cpu;
331 int pcpu_master;
332 static int maxhpetet = 0;
333 uint32_t val, val2, cvectors, dvectors;
334 uint16_t vendor, rev;
335
336 ACPI_FUNCTION_TRACE((char *)(uintptr_t) __func__);
337
338 sc = device_get_softc(dev);
339 sc->dev = dev;
340 sc->handle = acpi_get_handle(dev);
341
342 sc->mem_rid = 0;
343 sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->mem_rid,
344 RF_ACTIVE);
345 if (sc->mem_res == NULL)
346 return (ENOMEM);
347
348 /* Validate that we can access the whole region. */
349 if (rman_get_size(sc->mem_res) < HPET_MEM_WIDTH) {
350 device_printf(dev, "memory region width %ld too small\n",
351 rman_get_size(sc->mem_res));
352 bus_free_resource(dev, SYS_RES_MEMORY, sc->mem_res);
353 return (ENXIO);
354 }
355
356 /* Be sure timer is enabled. */
357 hpet_enable(sc);
358
359 /* Read basic statistics about the timer. */
360 val = bus_read_4(sc->mem_res, HPET_PERIOD);
361 if (val == 0) {
362 device_printf(dev, "invalid period\n");
363 hpet_disable(sc);
364 bus_free_resource(dev, SYS_RES_MEMORY, sc->mem_res);
365 return (ENXIO);
366 }
367
368 sc->freq = (1000000000000000LL + val / 2) / val;
369 sc->caps = bus_read_4(sc->mem_res, HPET_CAPABILITIES);
370 vendor = (sc->caps & HPET_CAP_VENDOR_ID) >> 16;
371 rev = sc->caps & HPET_CAP_REV_ID;
372 num_timers = 1 + ((sc->caps & HPET_CAP_NUM_TIM) >> 8);
373 /*
374 * ATI/AMD violates IA-PC HPET (High Precision Event Timers)
375 * Specification and provides an off by one number
376 * of timers/comparators.
377 * Additionally, they use unregistered value in VENDOR_ID field.
378 */
379 if (vendor == HPET_VENDID_AMD && rev < 0x10 && num_timers > 0)
380 num_timers--;
381 sc->num_timers = num_timers;
382 if (bootverbose) {
383 device_printf(dev,
384 "vendor 0x%x, rev 0x%x, %jdHz%s, %d timers,%s\n",
385 vendor, rev, sc->freq,
386 (sc->caps & HPET_CAP_COUNT_SIZE) ? " 64bit" : "",
387 num_timers,
388 (sc->caps & HPET_CAP_LEG_RT) ? " legacy route" : "");
389 }
390 for (i = 0; i < num_timers; i++) {
391 t = &sc->t[i];
392 t->sc = sc;
393 t->num = i;
394 t->mode = 0;
395 t->intr_rid = -1;
396 t->irq = -1;
240 if (t->mode == 1 &&
241 (t->caps & HPET_TCAP_PER_INT) == 0) {
242 t->last += t->div;
243 now = bus_read_4(sc->mem_res, HPET_MAIN_COUNTER);
244 if ((int32_t)(now - (t->last + t->div / 2)) > 0)
245 t->last = now - t->div / 2;
246 bus_write_4(sc->mem_res,
247 HPET_TIMER_COMPARATOR(t->num), t->last + t->div);
248 } else if (t->mode == 2)
249 t->mode = 0;
250 mt = (t->pcpu_master < 0) ? t : &sc->t[t->pcpu_master];
251 if (mt->et.et_active)
252 mt->et.et_event_cb(&mt->et, mt->et.et_arg);
253 return (FILTER_HANDLED);
254}
255
256static int
257hpet_intr(void *arg)
258{
259 struct hpet_softc *sc = (struct hpet_softc *)arg;
260 int i;
261 uint32_t val;
262
263 val = bus_read_4(sc->mem_res, HPET_ISR);
264 if (val) {
265 bus_write_4(sc->mem_res, HPET_ISR, val);
266 val &= sc->useirq;
267 for (i = 0; i < sc->num_timers; i++) {
268 if ((val & (1 << i)) == 0)
269 continue;
270 hpet_intr_single(&sc->t[i]);
271 }
272 return (FILTER_HANDLED);
273 }
274 return (FILTER_STRAY);
275}
276
277static ACPI_STATUS
278hpet_find(ACPI_HANDLE handle, UINT32 level, void *context,
279 void **status)
280{
281 char **ids;
282 uint32_t id = (uint32_t)(uintptr_t)context;
283 uint32_t uid = 0;
284
285 for (ids = hpet_ids; *ids != NULL; ids++) {
286 if (acpi_MatchHid(handle, *ids))
287 break;
288 }
289 if (*ids == NULL)
290 return (AE_OK);
291 if (ACPI_FAILURE(acpi_GetInteger(handle, "_UID", &uid)) ||
292 id == uid)
293 *((int *)status) = 1;
294 return (AE_OK);
295}
296
297/* Discover the HPET via the ACPI table of the same name. */
298static void
299hpet_identify(driver_t *driver, device_t parent)
300{
301 ACPI_TABLE_HPET *hpet;
302 ACPI_STATUS status;
303 device_t child;
304 int i, found;
305
306 /* Only one HPET device can be added. */
307 if (devclass_get_device(hpet_devclass, 0))
308 return;
309 for (i = 1; ; i++) {
310 /* Search for HPET table. */
311 status = AcpiGetTable(ACPI_SIG_HPET, i, (ACPI_TABLE_HEADER **)&hpet);
312 if (ACPI_FAILURE(status))
313 return;
314 /* Search for HPET device with same ID. */
315 found = 0;
316 AcpiWalkNamespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
317 100, hpet_find, NULL, (void *)(uintptr_t)hpet->Sequence, (void *)&found);
318 /* If found - let it be probed in normal way. */
319 if (found)
320 continue;
321 /* If not - create it from table info. */
322 child = BUS_ADD_CHILD(parent, ACPI_DEV_BASE_ORDER, "hpet", 0);
323 if (child == NULL) {
324 printf("%s: can't add child\n", __func__);
325 continue;
326 }
327 bus_set_resource(child, SYS_RES_MEMORY, 0, hpet->Address.Address,
328 HPET_MEM_WIDTH);
329 }
330}
331
332static int
333hpet_probe(device_t dev)
334{
335 ACPI_FUNCTION_TRACE((char *)(uintptr_t) __func__);
336
337 if (acpi_disabled("hpet"))
338 return (ENXIO);
339 if (acpi_get_handle(dev) != NULL &&
340 ACPI_ID_PROBE(device_get_parent(dev), dev, hpet_ids) == NULL)
341 return (ENXIO);
342
343 device_set_desc(dev, "High Precision Event Timer");
344 return (0);
345}
346
347static int
348hpet_attach(device_t dev)
349{
350 struct hpet_softc *sc;
351 struct hpet_timer *t;
352 int i, j, num_msi, num_timers, num_percpu_et, num_percpu_t, cur_cpu;
353 int pcpu_master;
354 static int maxhpetet = 0;
355 uint32_t val, val2, cvectors, dvectors;
356 uint16_t vendor, rev;
357
358 ACPI_FUNCTION_TRACE((char *)(uintptr_t) __func__);
359
360 sc = device_get_softc(dev);
361 sc->dev = dev;
362 sc->handle = acpi_get_handle(dev);
363
364 sc->mem_rid = 0;
365 sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->mem_rid,
366 RF_ACTIVE);
367 if (sc->mem_res == NULL)
368 return (ENOMEM);
369
370 /* Validate that we can access the whole region. */
371 if (rman_get_size(sc->mem_res) < HPET_MEM_WIDTH) {
372 device_printf(dev, "memory region width %ld too small\n",
373 rman_get_size(sc->mem_res));
374 bus_free_resource(dev, SYS_RES_MEMORY, sc->mem_res);
375 return (ENXIO);
376 }
377
378 /* Be sure timer is enabled. */
379 hpet_enable(sc);
380
381 /* Read basic statistics about the timer. */
382 val = bus_read_4(sc->mem_res, HPET_PERIOD);
383 if (val == 0) {
384 device_printf(dev, "invalid period\n");
385 hpet_disable(sc);
386 bus_free_resource(dev, SYS_RES_MEMORY, sc->mem_res);
387 return (ENXIO);
388 }
389
390 sc->freq = (1000000000000000LL + val / 2) / val;
391 sc->caps = bus_read_4(sc->mem_res, HPET_CAPABILITIES);
392 vendor = (sc->caps & HPET_CAP_VENDOR_ID) >> 16;
393 rev = sc->caps & HPET_CAP_REV_ID;
394 num_timers = 1 + ((sc->caps & HPET_CAP_NUM_TIM) >> 8);
395 /*
396 * ATI/AMD violates IA-PC HPET (High Precision Event Timers)
397 * Specification and provides an off by one number
398 * of timers/comparators.
399 * Additionally, they use unregistered value in VENDOR_ID field.
400 */
401 if (vendor == HPET_VENDID_AMD && rev < 0x10 && num_timers > 0)
402 num_timers--;
403 sc->num_timers = num_timers;
404 if (bootverbose) {
405 device_printf(dev,
406 "vendor 0x%x, rev 0x%x, %jdHz%s, %d timers,%s\n",
407 vendor, rev, sc->freq,
408 (sc->caps & HPET_CAP_COUNT_SIZE) ? " 64bit" : "",
409 num_timers,
410 (sc->caps & HPET_CAP_LEG_RT) ? " legacy route" : "");
411 }
412 for (i = 0; i < num_timers; i++) {
413 t = &sc->t[i];
414 t->sc = sc;
415 t->num = i;
416 t->mode = 0;
417 t->intr_rid = -1;
418 t->irq = -1;
419 t->pcpu_cpu = -1;
420 t->pcpu_misrouted = 0;
397 t->pcpu_master = -1;
398 t->caps = bus_read_4(sc->mem_res, HPET_TIMER_CAP_CNF(i));
399 t->vectors = bus_read_4(sc->mem_res, HPET_TIMER_CAP_CNF(i) + 4);
400 if (bootverbose) {
401 device_printf(dev,
402 " t%d: irqs 0x%08x (%d)%s%s%s\n", i,
403 t->vectors, (t->caps & HPET_TCNF_INT_ROUTE) >> 9,
404 (t->caps & HPET_TCAP_FSB_INT_DEL) ? ", MSI" : "",
405 (t->caps & HPET_TCAP_SIZE) ? ", 64bit" : "",
406 (t->caps & HPET_TCAP_PER_INT) ? ", periodic" : "");
407 }
408 }
409 if (testenv("debug.acpi.hpet_test"))
410 hpet_test(sc);
411 /*
412 * Don't attach if the timer never increments. Since the spec
413 * requires it to be at least 10 MHz, it has to change in 1 us.
414 */
415 val = bus_read_4(sc->mem_res, HPET_MAIN_COUNTER);
416 DELAY(1);
417 val2 = bus_read_4(sc->mem_res, HPET_MAIN_COUNTER);
418 if (val == val2) {
419 device_printf(dev, "HPET never increments, disabling\n");
420 hpet_disable(sc);
421 bus_free_resource(dev, SYS_RES_MEMORY, sc->mem_res);
422 return (ENXIO);
423 }
424 /* Announce first HPET as timecounter. */
425 if (device_get_unit(dev) == 0) {
426 sc->tc.tc_get_timecount = hpet_get_timecount,
427 sc->tc.tc_counter_mask = ~0u,
428 sc->tc.tc_name = "HPET",
429 sc->tc.tc_quality = 900,
430 sc->tc.tc_frequency = sc->freq;
431 sc->tc.tc_priv = sc;
432 tc_init(&sc->tc);
433 }
434 /* If not disabled - setup and announce event timers. */
435 if (resource_int_value(device_get_name(dev), device_get_unit(dev),
436 "clock", &i) == 0 && i == 0)
437 return (0);
438
439 /* Check whether we can and want legacy routing. */
440 sc->legacy_route = 0;
441 resource_int_value(device_get_name(dev), device_get_unit(dev),
442 "legacy_route", &sc->legacy_route);
443 if ((sc->caps & HPET_CAP_LEG_RT) == 0)
444 sc->legacy_route = 0;
445 if (sc->legacy_route) {
446 sc->t[0].vectors = 0;
447 sc->t[1].vectors = 0;
448 }
449
450 /* Check what IRQs we want use. */
451 /* By default allow any PCI IRQs. */
452 sc->allowed_irqs = 0xffff0000;
453 /*
454 * HPETs in AMD chipsets before SB800 have problems with IRQs >= 16
455 * Lower are also not always working for different reasons.
456 * SB800 fixed it, but seems do not implements level triggering
457 * properly, that makes it very unreliable - it freezes after any
458 * interrupt loss. Avoid legacy IRQs for AMD.
459 */
460 if (vendor == HPET_VENDID_AMD)
461 sc->allowed_irqs = 0x00000000;
462 /*
463 * Neither QEMU nor VirtualBox report supported IRQs correctly.
464 * The only way to use HPET there is to specify IRQs manually
465 * and/or use legacy_route. Legacy_route mode work on both.
466 */
467 if (vm_guest)
468 sc->allowed_irqs = 0x00000000;
469 /* Let user override. */
470 resource_int_value(device_get_name(dev), device_get_unit(dev),
471 "allowed_irqs", &sc->allowed_irqs);
472
473 num_msi = 0;
474 sc->useirq = 0;
475 /* Find IRQ vectors for all timers. */
476 cvectors = sc->allowed_irqs & 0xffff0000;
477 dvectors = sc->allowed_irqs & 0x0000ffff;
478 if (sc->legacy_route)
479 dvectors &= 0x0000fefe;
480 for (i = 0; i < num_timers; i++) {
481 t = &sc->t[i];
482 if (sc->legacy_route && i < 2)
483 t->irq = (i == 0) ? 0 : 8;
484#ifdef DEV_APIC
485 else if (t->caps & HPET_TCAP_FSB_INT_DEL) {
486 if ((j = PCIB_ALLOC_MSIX(
487 device_get_parent(device_get_parent(dev)), dev,
488 &t->irq))) {
489 device_printf(dev,
490 "Can't allocate interrupt for t%d.\n", j);
491 }
492 }
493#endif
494 else if (dvectors & t->vectors) {
495 t->irq = ffs(dvectors & t->vectors) - 1;
496 dvectors &= ~(1 << t->irq);
497 }
498 if (t->irq >= 0) {
499 if (!(t->intr_res =
500 bus_alloc_resource(dev, SYS_RES_IRQ, &t->intr_rid,
501 t->irq, t->irq, 1, RF_ACTIVE))) {
502 t->irq = -1;
503 device_printf(dev,
504 "Can't map interrupt for t%d.\n", i);
505 } else if ((bus_setup_intr(dev, t->intr_res,
506 INTR_MPSAFE | INTR_TYPE_CLK,
507 (driver_filter_t *)hpet_intr_single, NULL,
508 t, &t->intr_handle))) {
509 t->irq = -1;
510 device_printf(dev,
511 "Can't setup interrupt for t%d.\n", i);
512 } else {
513 bus_describe_intr(dev, t->intr_res,
514 t->intr_handle, "t%d", i);
515 num_msi++;
516 }
517 }
518 if (t->irq < 0 && (cvectors & t->vectors) != 0) {
519 cvectors &= t->vectors;
520 sc->useirq |= (1 << i);
521 }
522 }
523 if (sc->legacy_route && sc->t[0].irq < 0 && sc->t[1].irq < 0)
524 sc->legacy_route = 0;
525 if (sc->legacy_route)
526 hpet_enable(sc);
527 /* Group timers for per-CPU operation. */
528 num_percpu_et = min(num_msi / mp_ncpus, 1);
529 num_percpu_t = num_percpu_et * mp_ncpus;
530 pcpu_master = 0;
531 cur_cpu = CPU_FIRST();
532 for (i = 0; i < num_timers; i++) {
533 t = &sc->t[i];
534 if (t->irq >= 0 && num_percpu_t > 0) {
535 if (cur_cpu == CPU_FIRST())
536 pcpu_master = i;
421 t->pcpu_master = -1;
422 t->caps = bus_read_4(sc->mem_res, HPET_TIMER_CAP_CNF(i));
423 t->vectors = bus_read_4(sc->mem_res, HPET_TIMER_CAP_CNF(i) + 4);
424 if (bootverbose) {
425 device_printf(dev,
426 " t%d: irqs 0x%08x (%d)%s%s%s\n", i,
427 t->vectors, (t->caps & HPET_TCNF_INT_ROUTE) >> 9,
428 (t->caps & HPET_TCAP_FSB_INT_DEL) ? ", MSI" : "",
429 (t->caps & HPET_TCAP_SIZE) ? ", 64bit" : "",
430 (t->caps & HPET_TCAP_PER_INT) ? ", periodic" : "");
431 }
432 }
433 if (testenv("debug.acpi.hpet_test"))
434 hpet_test(sc);
435 /*
436 * Don't attach if the timer never increments. Since the spec
437 * requires it to be at least 10 MHz, it has to change in 1 us.
438 */
439 val = bus_read_4(sc->mem_res, HPET_MAIN_COUNTER);
440 DELAY(1);
441 val2 = bus_read_4(sc->mem_res, HPET_MAIN_COUNTER);
442 if (val == val2) {
443 device_printf(dev, "HPET never increments, disabling\n");
444 hpet_disable(sc);
445 bus_free_resource(dev, SYS_RES_MEMORY, sc->mem_res);
446 return (ENXIO);
447 }
448 /* Announce first HPET as timecounter. */
449 if (device_get_unit(dev) == 0) {
450 sc->tc.tc_get_timecount = hpet_get_timecount,
451 sc->tc.tc_counter_mask = ~0u,
452 sc->tc.tc_name = "HPET",
453 sc->tc.tc_quality = 900,
454 sc->tc.tc_frequency = sc->freq;
455 sc->tc.tc_priv = sc;
456 tc_init(&sc->tc);
457 }
458 /* If not disabled - setup and announce event timers. */
459 if (resource_int_value(device_get_name(dev), device_get_unit(dev),
460 "clock", &i) == 0 && i == 0)
461 return (0);
462
463 /* Check whether we can and want legacy routing. */
464 sc->legacy_route = 0;
465 resource_int_value(device_get_name(dev), device_get_unit(dev),
466 "legacy_route", &sc->legacy_route);
467 if ((sc->caps & HPET_CAP_LEG_RT) == 0)
468 sc->legacy_route = 0;
469 if (sc->legacy_route) {
470 sc->t[0].vectors = 0;
471 sc->t[1].vectors = 0;
472 }
473
474 /* Check what IRQs we want use. */
475 /* By default allow any PCI IRQs. */
476 sc->allowed_irqs = 0xffff0000;
477 /*
478 * HPETs in AMD chipsets before SB800 have problems with IRQs >= 16
479 * Lower are also not always working for different reasons.
480 * SB800 fixed it, but seems do not implements level triggering
481 * properly, that makes it very unreliable - it freezes after any
482 * interrupt loss. Avoid legacy IRQs for AMD.
483 */
484 if (vendor == HPET_VENDID_AMD)
485 sc->allowed_irqs = 0x00000000;
486 /*
487 * Neither QEMU nor VirtualBox report supported IRQs correctly.
488 * The only way to use HPET there is to specify IRQs manually
489 * and/or use legacy_route. Legacy_route mode work on both.
490 */
491 if (vm_guest)
492 sc->allowed_irqs = 0x00000000;
493 /* Let user override. */
494 resource_int_value(device_get_name(dev), device_get_unit(dev),
495 "allowed_irqs", &sc->allowed_irqs);
496
497 num_msi = 0;
498 sc->useirq = 0;
499 /* Find IRQ vectors for all timers. */
500 cvectors = sc->allowed_irqs & 0xffff0000;
501 dvectors = sc->allowed_irqs & 0x0000ffff;
502 if (sc->legacy_route)
503 dvectors &= 0x0000fefe;
504 for (i = 0; i < num_timers; i++) {
505 t = &sc->t[i];
506 if (sc->legacy_route && i < 2)
507 t->irq = (i == 0) ? 0 : 8;
508#ifdef DEV_APIC
509 else if (t->caps & HPET_TCAP_FSB_INT_DEL) {
510 if ((j = PCIB_ALLOC_MSIX(
511 device_get_parent(device_get_parent(dev)), dev,
512 &t->irq))) {
513 device_printf(dev,
514 "Can't allocate interrupt for t%d.\n", j);
515 }
516 }
517#endif
518 else if (dvectors & t->vectors) {
519 t->irq = ffs(dvectors & t->vectors) - 1;
520 dvectors &= ~(1 << t->irq);
521 }
522 if (t->irq >= 0) {
523 if (!(t->intr_res =
524 bus_alloc_resource(dev, SYS_RES_IRQ, &t->intr_rid,
525 t->irq, t->irq, 1, RF_ACTIVE))) {
526 t->irq = -1;
527 device_printf(dev,
528 "Can't map interrupt for t%d.\n", i);
529 } else if ((bus_setup_intr(dev, t->intr_res,
530 INTR_MPSAFE | INTR_TYPE_CLK,
531 (driver_filter_t *)hpet_intr_single, NULL,
532 t, &t->intr_handle))) {
533 t->irq = -1;
534 device_printf(dev,
535 "Can't setup interrupt for t%d.\n", i);
536 } else {
537 bus_describe_intr(dev, t->intr_res,
538 t->intr_handle, "t%d", i);
539 num_msi++;
540 }
541 }
542 if (t->irq < 0 && (cvectors & t->vectors) != 0) {
543 cvectors &= t->vectors;
544 sc->useirq |= (1 << i);
545 }
546 }
547 if (sc->legacy_route && sc->t[0].irq < 0 && sc->t[1].irq < 0)
548 sc->legacy_route = 0;
549 if (sc->legacy_route)
550 hpet_enable(sc);
551 /* Group timers for per-CPU operation. */
552 num_percpu_et = min(num_msi / mp_ncpus, 1);
553 num_percpu_t = num_percpu_et * mp_ncpus;
554 pcpu_master = 0;
555 cur_cpu = CPU_FIRST();
556 for (i = 0; i < num_timers; i++) {
557 t = &sc->t[i];
558 if (t->irq >= 0 && num_percpu_t > 0) {
559 if (cur_cpu == CPU_FIRST())
560 pcpu_master = i;
561 t->pcpu_cpu = cur_cpu;
537 t->pcpu_master = pcpu_master;
538 sc->t[pcpu_master].
539 pcpu_slaves[cur_cpu] = i;
540 bus_bind_intr(dev, t->intr_res, cur_cpu);
541 cur_cpu = CPU_NEXT(cur_cpu);
542 num_percpu_t--;
543 } else if (t->irq >= 0)
544 bus_bind_intr(dev, t->intr_res, CPU_FIRST());
545 }
546 bus_write_4(sc->mem_res, HPET_ISR, 0xffffffff);
547 sc->irq = -1;
548 sc->intr_rid = -1;
549 /* If at least one timer needs legacy IRQ - setup it. */
550 if (sc->useirq) {
551 j = i = fls(cvectors) - 1;
552 while (j > 0 && (cvectors & (1 << (j - 1))) != 0)
553 j--;
554 if (!(sc->intr_res = bus_alloc_resource(dev, SYS_RES_IRQ,
555 &sc->intr_rid, j, i, 1, RF_SHAREABLE | RF_ACTIVE)))
556 device_printf(dev,"Can't map interrupt.\n");
557 else if ((bus_setup_intr(dev, sc->intr_res,
558 INTR_MPSAFE | INTR_TYPE_CLK,
559 (driver_filter_t *)hpet_intr, NULL,
560 sc, &sc->intr_handle))) {
561 device_printf(dev, "Can't setup interrupt.\n");
562 } else {
563 sc->irq = rman_get_start(sc->intr_res);
564 /* Bind IRQ to BSP to avoid live migration. */
565 bus_bind_intr(dev, sc->intr_res, CPU_FIRST());
566 }
567 }
568 /* Program and announce event timers. */
569 for (i = 0; i < num_timers; i++) {
570 t = &sc->t[i];
571 t->caps &= ~(HPET_TCNF_FSB_EN | HPET_TCNF_INT_ROUTE);
572 t->caps &= ~(HPET_TCNF_VAL_SET | HPET_TCNF_INT_ENB);
573 t->caps &= ~(HPET_TCNF_INT_TYPE);
574 t->caps |= HPET_TCNF_32MODE;
575 if (t->irq >= 0 && sc->legacy_route && i < 2) {
576 /* Legacy route doesn't need more configuration. */
577 } else
578#ifdef DEV_APIC
579 if ((t->caps & HPET_TCAP_FSB_INT_DEL) && t->irq >= 0) {
580 uint64_t addr;
581 uint32_t data;
582
583 if (PCIB_MAP_MSI(
584 device_get_parent(device_get_parent(dev)), dev,
585 t->irq, &addr, &data) == 0) {
586 bus_write_4(sc->mem_res,
587 HPET_TIMER_FSB_ADDR(i), addr);
588 bus_write_4(sc->mem_res,
589 HPET_TIMER_FSB_VAL(i), data);
590 t->caps |= HPET_TCNF_FSB_EN;
591 } else
592 t->irq = -2;
593 } else
594#endif
595 if (t->irq >= 0)
596 t->caps |= (t->irq << 9);
597 else if (sc->irq >= 0 && (t->vectors & (1 << sc->irq)))
598 t->caps |= (sc->irq << 9) | HPET_TCNF_INT_TYPE;
599 bus_write_4(sc->mem_res, HPET_TIMER_CAP_CNF(i), t->caps);
600 /* Skip event timers without set up IRQ. */
601 if (t->irq < 0 &&
602 (sc->irq < 0 || (t->vectors & (1 << sc->irq)) == 0))
603 continue;
604 /* Announce the reset. */
605 if (maxhpetet == 0)
606 t->et.et_name = "HPET";
607 else {
608 sprintf(t->name, "HPET%d", maxhpetet);
609 t->et.et_name = t->name;
610 }
611 t->et.et_flags = ET_FLAGS_PERIODIC | ET_FLAGS_ONESHOT;
612 t->et.et_quality = 450;
613 if (t->pcpu_master >= 0) {
614 t->et.et_flags |= ET_FLAGS_PERCPU;
615 t->et.et_quality += 100;
616 }
617 if ((t->caps & HPET_TCAP_PER_INT) == 0)
618 t->et.et_quality -= 10;
619 t->et.et_frequency = sc->freq;
620 t->et.et_min_period.sec = 0;
621 t->et.et_min_period.frac = 0x00008000LLU << 32;
622 t->et.et_max_period.sec = 0xfffffffeLLU / sc->freq;
623 t->et.et_max_period.frac =
624 ((0xfffffffeLLU << 32) / sc->freq) << 32;
625 t->et.et_start = hpet_start;
626 t->et.et_stop = hpet_stop;
627 t->et.et_priv = &sc->t[i];
628 if (t->pcpu_master < 0 || t->pcpu_master == i) {
629 et_register(&t->et);
630 maxhpetet++;
631 }
632 }
633 return (0);
634}
635
636static int
637hpet_detach(device_t dev)
638{
639 ACPI_FUNCTION_TRACE((char *)(uintptr_t) __func__);
640
641 /* XXX Without a tc_remove() function, we can't detach. */
642 return (EBUSY);
643}
644
645static int
646hpet_suspend(device_t dev)
647{
648 struct hpet_softc *sc;
649
650 /*
651 * Disable the timer during suspend. The timer will not lose
652 * its state in S1 or S2, but we are required to disable
653 * it.
654 */
655 sc = device_get_softc(dev);
656 hpet_disable(sc);
657
658 return (0);
659}
660
661static int
662hpet_resume(device_t dev)
663{
664 struct hpet_softc *sc;
665 struct hpet_timer *t;
666 int i;
667
668 /* Re-enable the timer after a resume to keep the clock advancing. */
669 sc = device_get_softc(dev);
670 hpet_enable(sc);
671 /* Restart event timers that were running on suspend. */
672 for (i = 0; i < sc->num_timers; i++) {
673 t = &sc->t[i];
674#ifdef DEV_APIC
675 if (t->irq >= 0 && (sc->legacy_route == 0 || i >= 2)) {
676 uint64_t addr;
677 uint32_t data;
678
679 if (PCIB_MAP_MSI(
680 device_get_parent(device_get_parent(dev)), dev,
681 t->irq, &addr, &data) == 0) {
682 bus_write_4(sc->mem_res,
683 HPET_TIMER_FSB_ADDR(i), addr);
684 bus_write_4(sc->mem_res,
685 HPET_TIMER_FSB_VAL(i), data);
686 }
687 }
688#endif
689 if (t->mode == 0)
690 continue;
691 t->last = bus_read_4(sc->mem_res, HPET_MAIN_COUNTER);
692 if (t->mode == 1 && (t->caps & HPET_TCAP_PER_INT)) {
693 t->caps |= HPET_TCNF_TYPE;
694 bus_write_4(sc->mem_res, HPET_TIMER_CAP_CNF(t->num),
695 t->caps | HPET_TCNF_VAL_SET);
696 bus_write_4(sc->mem_res, HPET_TIMER_COMPARATOR(t->num),
697 t->last + t->div);
698 bus_read_4(sc->mem_res, HPET_TIMER_COMPARATOR(t->num));
699 bus_write_4(sc->mem_res, HPET_TIMER_COMPARATOR(t->num),
700 t->div);
701 } else {
702 bus_write_4(sc->mem_res, HPET_TIMER_COMPARATOR(t->num),
703 t->last + sc->freq / 1024);
704 }
705 bus_write_4(sc->mem_res, HPET_ISR, 1 << t->num);
706 bus_write_4(sc->mem_res, HPET_TIMER_CAP_CNF(t->num), t->caps);
707 }
708 return (0);
709}
710
711/* Print some basic latency/rate information to assist in debugging. */
712static void
713hpet_test(struct hpet_softc *sc)
714{
715 int i;
716 uint32_t u1, u2;
717 struct bintime b0, b1, b2;
718 struct timespec ts;
719
720 binuptime(&b0);
721 binuptime(&b0);
722 binuptime(&b1);
723 u1 = bus_read_4(sc->mem_res, HPET_MAIN_COUNTER);
724 for (i = 1; i < 1000; i++)
725 u2 = bus_read_4(sc->mem_res, HPET_MAIN_COUNTER);
726 binuptime(&b2);
727 u2 = bus_read_4(sc->mem_res, HPET_MAIN_COUNTER);
728
729 bintime_sub(&b2, &b1);
730 bintime_sub(&b1, &b0);
731 bintime_sub(&b2, &b1);
732 bintime2timespec(&b2, &ts);
733
734 device_printf(sc->dev, "%ld.%09ld: %u ... %u = %u\n",
735 (long)ts.tv_sec, ts.tv_nsec, u1, u2, u2 - u1);
736
737 device_printf(sc->dev, "time per call: %ld ns\n", ts.tv_nsec / 1000);
738}
739
740#ifdef DEV_APIC
741static int
742hpet_remap_intr(device_t dev, device_t child, u_int irq)
743{
744 struct hpet_softc *sc = device_get_softc(dev);
745 struct hpet_timer *t;
746 uint64_t addr;
747 uint32_t data;
748 int error, i;
749
750 for (i = 0; i < sc->num_timers; i++) {
751 t = &sc->t[i];
752 if (t->irq != irq)
753 continue;
754 error = PCIB_MAP_MSI(
755 device_get_parent(device_get_parent(dev)), dev,
756 irq, &addr, &data);
757 if (error)
758 return (error);
759 hpet_disable(sc); /* Stop timer to avoid interrupt loss. */
760 bus_write_4(sc->mem_res, HPET_TIMER_FSB_ADDR(i), addr);
761 bus_write_4(sc->mem_res, HPET_TIMER_FSB_VAL(i), data);
762 hpet_enable(sc);
763 return (0);
764 }
765 return (ENOENT);
766}
767#endif
768
769static device_method_t hpet_methods[] = {
770 /* Device interface */
771 DEVMETHOD(device_identify, hpet_identify),
772 DEVMETHOD(device_probe, hpet_probe),
773 DEVMETHOD(device_attach, hpet_attach),
774 DEVMETHOD(device_detach, hpet_detach),
775 DEVMETHOD(device_suspend, hpet_suspend),
776 DEVMETHOD(device_resume, hpet_resume),
777
778#ifdef DEV_APIC
779 DEVMETHOD(bus_remap_intr, hpet_remap_intr),
780#endif
781
782 {0, 0}
783};
784
785static driver_t hpet_driver = {
786 "hpet",
787 hpet_methods,
788 sizeof(struct hpet_softc),
789};
790
791DRIVER_MODULE(hpet, acpi, hpet_driver, hpet_devclass, 0, 0);
792MODULE_DEPEND(hpet, acpi, 1, 1, 1);
562 t->pcpu_master = pcpu_master;
563 sc->t[pcpu_master].
564 pcpu_slaves[cur_cpu] = i;
565 bus_bind_intr(dev, t->intr_res, cur_cpu);
566 cur_cpu = CPU_NEXT(cur_cpu);
567 num_percpu_t--;
568 } else if (t->irq >= 0)
569 bus_bind_intr(dev, t->intr_res, CPU_FIRST());
570 }
571 bus_write_4(sc->mem_res, HPET_ISR, 0xffffffff);
572 sc->irq = -1;
573 sc->intr_rid = -1;
574 /* If at least one timer needs legacy IRQ - setup it. */
575 if (sc->useirq) {
576 j = i = fls(cvectors) - 1;
577 while (j > 0 && (cvectors & (1 << (j - 1))) != 0)
578 j--;
579 if (!(sc->intr_res = bus_alloc_resource(dev, SYS_RES_IRQ,
580 &sc->intr_rid, j, i, 1, RF_SHAREABLE | RF_ACTIVE)))
581 device_printf(dev,"Can't map interrupt.\n");
582 else if ((bus_setup_intr(dev, sc->intr_res,
583 INTR_MPSAFE | INTR_TYPE_CLK,
584 (driver_filter_t *)hpet_intr, NULL,
585 sc, &sc->intr_handle))) {
586 device_printf(dev, "Can't setup interrupt.\n");
587 } else {
588 sc->irq = rman_get_start(sc->intr_res);
589 /* Bind IRQ to BSP to avoid live migration. */
590 bus_bind_intr(dev, sc->intr_res, CPU_FIRST());
591 }
592 }
593 /* Program and announce event timers. */
594 for (i = 0; i < num_timers; i++) {
595 t = &sc->t[i];
596 t->caps &= ~(HPET_TCNF_FSB_EN | HPET_TCNF_INT_ROUTE);
597 t->caps &= ~(HPET_TCNF_VAL_SET | HPET_TCNF_INT_ENB);
598 t->caps &= ~(HPET_TCNF_INT_TYPE);
599 t->caps |= HPET_TCNF_32MODE;
600 if (t->irq >= 0 && sc->legacy_route && i < 2) {
601 /* Legacy route doesn't need more configuration. */
602 } else
603#ifdef DEV_APIC
604 if ((t->caps & HPET_TCAP_FSB_INT_DEL) && t->irq >= 0) {
605 uint64_t addr;
606 uint32_t data;
607
608 if (PCIB_MAP_MSI(
609 device_get_parent(device_get_parent(dev)), dev,
610 t->irq, &addr, &data) == 0) {
611 bus_write_4(sc->mem_res,
612 HPET_TIMER_FSB_ADDR(i), addr);
613 bus_write_4(sc->mem_res,
614 HPET_TIMER_FSB_VAL(i), data);
615 t->caps |= HPET_TCNF_FSB_EN;
616 } else
617 t->irq = -2;
618 } else
619#endif
620 if (t->irq >= 0)
621 t->caps |= (t->irq << 9);
622 else if (sc->irq >= 0 && (t->vectors & (1 << sc->irq)))
623 t->caps |= (sc->irq << 9) | HPET_TCNF_INT_TYPE;
624 bus_write_4(sc->mem_res, HPET_TIMER_CAP_CNF(i), t->caps);
625 /* Skip event timers without set up IRQ. */
626 if (t->irq < 0 &&
627 (sc->irq < 0 || (t->vectors & (1 << sc->irq)) == 0))
628 continue;
629 /* Announce the reset. */
630 if (maxhpetet == 0)
631 t->et.et_name = "HPET";
632 else {
633 sprintf(t->name, "HPET%d", maxhpetet);
634 t->et.et_name = t->name;
635 }
636 t->et.et_flags = ET_FLAGS_PERIODIC | ET_FLAGS_ONESHOT;
637 t->et.et_quality = 450;
638 if (t->pcpu_master >= 0) {
639 t->et.et_flags |= ET_FLAGS_PERCPU;
640 t->et.et_quality += 100;
641 }
642 if ((t->caps & HPET_TCAP_PER_INT) == 0)
643 t->et.et_quality -= 10;
644 t->et.et_frequency = sc->freq;
645 t->et.et_min_period.sec = 0;
646 t->et.et_min_period.frac = 0x00008000LLU << 32;
647 t->et.et_max_period.sec = 0xfffffffeLLU / sc->freq;
648 t->et.et_max_period.frac =
649 ((0xfffffffeLLU << 32) / sc->freq) << 32;
650 t->et.et_start = hpet_start;
651 t->et.et_stop = hpet_stop;
652 t->et.et_priv = &sc->t[i];
653 if (t->pcpu_master < 0 || t->pcpu_master == i) {
654 et_register(&t->et);
655 maxhpetet++;
656 }
657 }
658 return (0);
659}
660
661static int
662hpet_detach(device_t dev)
663{
664 ACPI_FUNCTION_TRACE((char *)(uintptr_t) __func__);
665
666 /* XXX Without a tc_remove() function, we can't detach. */
667 return (EBUSY);
668}
669
670static int
671hpet_suspend(device_t dev)
672{
673 struct hpet_softc *sc;
674
675 /*
676 * Disable the timer during suspend. The timer will not lose
677 * its state in S1 or S2, but we are required to disable
678 * it.
679 */
680 sc = device_get_softc(dev);
681 hpet_disable(sc);
682
683 return (0);
684}
685
686static int
687hpet_resume(device_t dev)
688{
689 struct hpet_softc *sc;
690 struct hpet_timer *t;
691 int i;
692
693 /* Re-enable the timer after a resume to keep the clock advancing. */
694 sc = device_get_softc(dev);
695 hpet_enable(sc);
696 /* Restart event timers that were running on suspend. */
697 for (i = 0; i < sc->num_timers; i++) {
698 t = &sc->t[i];
699#ifdef DEV_APIC
700 if (t->irq >= 0 && (sc->legacy_route == 0 || i >= 2)) {
701 uint64_t addr;
702 uint32_t data;
703
704 if (PCIB_MAP_MSI(
705 device_get_parent(device_get_parent(dev)), dev,
706 t->irq, &addr, &data) == 0) {
707 bus_write_4(sc->mem_res,
708 HPET_TIMER_FSB_ADDR(i), addr);
709 bus_write_4(sc->mem_res,
710 HPET_TIMER_FSB_VAL(i), data);
711 }
712 }
713#endif
714 if (t->mode == 0)
715 continue;
716 t->last = bus_read_4(sc->mem_res, HPET_MAIN_COUNTER);
717 if (t->mode == 1 && (t->caps & HPET_TCAP_PER_INT)) {
718 t->caps |= HPET_TCNF_TYPE;
719 bus_write_4(sc->mem_res, HPET_TIMER_CAP_CNF(t->num),
720 t->caps | HPET_TCNF_VAL_SET);
721 bus_write_4(sc->mem_res, HPET_TIMER_COMPARATOR(t->num),
722 t->last + t->div);
723 bus_read_4(sc->mem_res, HPET_TIMER_COMPARATOR(t->num));
724 bus_write_4(sc->mem_res, HPET_TIMER_COMPARATOR(t->num),
725 t->div);
726 } else {
727 bus_write_4(sc->mem_res, HPET_TIMER_COMPARATOR(t->num),
728 t->last + sc->freq / 1024);
729 }
730 bus_write_4(sc->mem_res, HPET_ISR, 1 << t->num);
731 bus_write_4(sc->mem_res, HPET_TIMER_CAP_CNF(t->num), t->caps);
732 }
733 return (0);
734}
735
736/* Print some basic latency/rate information to assist in debugging. */
737static void
738hpet_test(struct hpet_softc *sc)
739{
740 int i;
741 uint32_t u1, u2;
742 struct bintime b0, b1, b2;
743 struct timespec ts;
744
745 binuptime(&b0);
746 binuptime(&b0);
747 binuptime(&b1);
748 u1 = bus_read_4(sc->mem_res, HPET_MAIN_COUNTER);
749 for (i = 1; i < 1000; i++)
750 u2 = bus_read_4(sc->mem_res, HPET_MAIN_COUNTER);
751 binuptime(&b2);
752 u2 = bus_read_4(sc->mem_res, HPET_MAIN_COUNTER);
753
754 bintime_sub(&b2, &b1);
755 bintime_sub(&b1, &b0);
756 bintime_sub(&b2, &b1);
757 bintime2timespec(&b2, &ts);
758
759 device_printf(sc->dev, "%ld.%09ld: %u ... %u = %u\n",
760 (long)ts.tv_sec, ts.tv_nsec, u1, u2, u2 - u1);
761
762 device_printf(sc->dev, "time per call: %ld ns\n", ts.tv_nsec / 1000);
763}
764
765#ifdef DEV_APIC
766static int
767hpet_remap_intr(device_t dev, device_t child, u_int irq)
768{
769 struct hpet_softc *sc = device_get_softc(dev);
770 struct hpet_timer *t;
771 uint64_t addr;
772 uint32_t data;
773 int error, i;
774
775 for (i = 0; i < sc->num_timers; i++) {
776 t = &sc->t[i];
777 if (t->irq != irq)
778 continue;
779 error = PCIB_MAP_MSI(
780 device_get_parent(device_get_parent(dev)), dev,
781 irq, &addr, &data);
782 if (error)
783 return (error);
784 hpet_disable(sc); /* Stop timer to avoid interrupt loss. */
785 bus_write_4(sc->mem_res, HPET_TIMER_FSB_ADDR(i), addr);
786 bus_write_4(sc->mem_res, HPET_TIMER_FSB_VAL(i), data);
787 hpet_enable(sc);
788 return (0);
789 }
790 return (ENOENT);
791}
792#endif
793
794static device_method_t hpet_methods[] = {
795 /* Device interface */
796 DEVMETHOD(device_identify, hpet_identify),
797 DEVMETHOD(device_probe, hpet_probe),
798 DEVMETHOD(device_attach, hpet_attach),
799 DEVMETHOD(device_detach, hpet_detach),
800 DEVMETHOD(device_suspend, hpet_suspend),
801 DEVMETHOD(device_resume, hpet_resume),
802
803#ifdef DEV_APIC
804 DEVMETHOD(bus_remap_intr, hpet_remap_intr),
805#endif
806
807 {0, 0}
808};
809
810static driver_t hpet_driver = {
811 "hpet",
812 hpet_methods,
813 sizeof(struct hpet_softc),
814};
815
816DRIVER_MODULE(hpet, acpi, hpet_driver, hpet_devclass, 0, 0);
817MODULE_DEPEND(hpet, acpi, 1, 1, 1);