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