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