intel_drv.c revision 306770
1/*-
2 * Copyright (c) 2013-2015 The FreeBSD Foundation
3 * All rights reserved.
4 *
5 * This software was developed by Konstantin Belousov <kib@FreeBSD.org>
6 * under sponsorship from the FreeBSD Foundation.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30#include <sys/cdefs.h>
31__FBSDID("$FreeBSD: stable/11/sys/x86/iommu/intel_drv.c 306770 2016-10-06 17:21:19Z jhb $");
32
33#include "opt_acpi.h"
34#if defined(__amd64__)
35#define	DEV_APIC
36#else
37#include "opt_apic.h"
38#endif
39#include "opt_ddb.h"
40
41#include <sys/param.h>
42#include <sys/bus.h>
43#include <sys/kernel.h>
44#include <sys/lock.h>
45#include <sys/malloc.h>
46#include <sys/memdesc.h>
47#include <sys/module.h>
48#include <sys/rman.h>
49#include <sys/rwlock.h>
50#include <sys/smp.h>
51#include <sys/taskqueue.h>
52#include <sys/tree.h>
53#include <sys/vmem.h>
54#include <machine/bus.h>
55#include <contrib/dev/acpica/include/acpi.h>
56#include <contrib/dev/acpica/include/accommon.h>
57#include <dev/acpica/acpivar.h>
58#include <vm/vm.h>
59#include <vm/vm_extern.h>
60#include <vm/vm_kern.h>
61#include <vm/vm_object.h>
62#include <vm/vm_page.h>
63#include <vm/vm_pager.h>
64#include <vm/vm_map.h>
65#include <x86/include/busdma_impl.h>
66#include <x86/iommu/intel_reg.h>
67#include <x86/iommu/busdma_dmar.h>
68#include <x86/iommu/intel_dmar.h>
69#include <dev/pci/pcireg.h>
70#include <dev/pci/pcivar.h>
71
72#ifdef DEV_APIC
73#include "pcib_if.h"
74#endif
75
76#define	DMAR_FAULT_IRQ_RID	0
77#define	DMAR_QI_IRQ_RID		1
78#define	DMAR_REG_RID		2
79
80static devclass_t dmar_devclass;
81static device_t *dmar_devs;
82static int dmar_devcnt;
83
84typedef int (*dmar_iter_t)(ACPI_DMAR_HEADER *, void *);
85
86static void
87dmar_iterate_tbl(dmar_iter_t iter, void *arg)
88{
89	ACPI_TABLE_DMAR *dmartbl;
90	ACPI_DMAR_HEADER *dmarh;
91	char *ptr, *ptrend;
92	ACPI_STATUS status;
93
94	status = AcpiGetTable(ACPI_SIG_DMAR, 1, (ACPI_TABLE_HEADER **)&dmartbl);
95	if (ACPI_FAILURE(status))
96		return;
97	ptr = (char *)dmartbl + sizeof(*dmartbl);
98	ptrend = (char *)dmartbl + dmartbl->Header.Length;
99	for (;;) {
100		if (ptr >= ptrend)
101			break;
102		dmarh = (ACPI_DMAR_HEADER *)ptr;
103		if (dmarh->Length <= 0) {
104			printf("dmar_identify: corrupted DMAR table, l %d\n",
105			    dmarh->Length);
106			break;
107		}
108		ptr += dmarh->Length;
109		if (!iter(dmarh, arg))
110			break;
111	}
112}
113
114struct find_iter_args {
115	int i;
116	ACPI_DMAR_HARDWARE_UNIT *res;
117};
118
119static int
120dmar_find_iter(ACPI_DMAR_HEADER *dmarh, void *arg)
121{
122	struct find_iter_args *fia;
123
124	if (dmarh->Type != ACPI_DMAR_TYPE_HARDWARE_UNIT)
125		return (1);
126
127	fia = arg;
128	if (fia->i == 0) {
129		fia->res = (ACPI_DMAR_HARDWARE_UNIT *)dmarh;
130		return (0);
131	}
132	fia->i--;
133	return (1);
134}
135
136static ACPI_DMAR_HARDWARE_UNIT *
137dmar_find_by_index(int idx)
138{
139	struct find_iter_args fia;
140
141	fia.i = idx;
142	fia.res = NULL;
143	dmar_iterate_tbl(dmar_find_iter, &fia);
144	return (fia.res);
145}
146
147static int
148dmar_count_iter(ACPI_DMAR_HEADER *dmarh, void *arg)
149{
150
151	if (dmarh->Type == ACPI_DMAR_TYPE_HARDWARE_UNIT)
152		dmar_devcnt++;
153	return (1);
154}
155
156static int dmar_enable = 0;
157static void
158dmar_identify(driver_t *driver, device_t parent)
159{
160	ACPI_TABLE_DMAR *dmartbl;
161	ACPI_DMAR_HARDWARE_UNIT *dmarh;
162	ACPI_STATUS status;
163	int i, error;
164
165	if (acpi_disabled("dmar"))
166		return;
167	TUNABLE_INT_FETCH("hw.dmar.enable", &dmar_enable);
168	if (!dmar_enable)
169		return;
170#ifdef INVARIANTS
171	TUNABLE_INT_FETCH("hw.dmar.check_free", &dmar_check_free);
172#endif
173	TUNABLE_INT_FETCH("hw.dmar.match_verbose", &dmar_match_verbose);
174	status = AcpiGetTable(ACPI_SIG_DMAR, 1, (ACPI_TABLE_HEADER **)&dmartbl);
175	if (ACPI_FAILURE(status))
176		return;
177	haw = dmartbl->Width + 1;
178	if ((1ULL << (haw + 1)) > BUS_SPACE_MAXADDR)
179		dmar_high = BUS_SPACE_MAXADDR;
180	else
181		dmar_high = 1ULL << (haw + 1);
182	if (bootverbose) {
183		printf("DMAR HAW=%d flags=<%b>\n", dmartbl->Width,
184		    (unsigned)dmartbl->Flags,
185		    "\020\001INTR_REMAP\002X2APIC_OPT_OUT");
186	}
187
188	dmar_iterate_tbl(dmar_count_iter, NULL);
189	if (dmar_devcnt == 0)
190		return;
191	dmar_devs = malloc(sizeof(device_t) * dmar_devcnt, M_DEVBUF,
192	    M_WAITOK | M_ZERO);
193	for (i = 0; i < dmar_devcnt; i++) {
194		dmarh = dmar_find_by_index(i);
195		if (dmarh == NULL) {
196			printf("dmar_identify: cannot find HWUNIT %d\n", i);
197			continue;
198		}
199		dmar_devs[i] = BUS_ADD_CHILD(parent, 1, "dmar", i);
200		if (dmar_devs[i] == NULL) {
201			printf("dmar_identify: cannot create instance %d\n", i);
202			continue;
203		}
204		error = bus_set_resource(dmar_devs[i], SYS_RES_MEMORY,
205		    DMAR_REG_RID, dmarh->Address, PAGE_SIZE);
206		if (error != 0) {
207			printf(
208	"dmar%d: unable to alloc register window at 0x%08jx: error %d\n",
209			    i, (uintmax_t)dmarh->Address, error);
210			device_delete_child(parent, dmar_devs[i]);
211			dmar_devs[i] = NULL;
212		}
213	}
214}
215
216static int
217dmar_probe(device_t dev)
218{
219
220	if (acpi_get_handle(dev) != NULL)
221		return (ENXIO);
222	device_set_desc(dev, "DMA remap");
223	return (BUS_PROBE_NOWILDCARD);
224}
225
226static void
227dmar_release_intr(device_t dev, struct dmar_unit *unit, int idx)
228{
229	struct dmar_msi_data *dmd;
230
231	dmd = &unit->intrs[idx];
232	if (dmd->irq == -1)
233		return;
234	bus_teardown_intr(dev, dmd->irq_res, dmd->intr_handle);
235	bus_release_resource(dev, SYS_RES_IRQ, dmd->irq_rid, dmd->irq_res);
236	bus_delete_resource(dev, SYS_RES_IRQ, dmd->irq_rid);
237	PCIB_RELEASE_MSIX(device_get_parent(device_get_parent(dev)),
238	    dev, dmd->irq);
239	dmd->irq = -1;
240}
241
242static void
243dmar_release_resources(device_t dev, struct dmar_unit *unit)
244{
245	int i;
246
247	dmar_fini_busdma(unit);
248	dmar_fini_irt(unit);
249	dmar_fini_qi(unit);
250	dmar_fini_fault_log(unit);
251	for (i = 0; i < DMAR_INTR_TOTAL; i++)
252		dmar_release_intr(dev, unit, i);
253	if (unit->regs != NULL) {
254		bus_deactivate_resource(dev, SYS_RES_MEMORY, unit->reg_rid,
255		    unit->regs);
256		bus_release_resource(dev, SYS_RES_MEMORY, unit->reg_rid,
257		    unit->regs);
258		unit->regs = NULL;
259	}
260	if (unit->domids != NULL) {
261		delete_unrhdr(unit->domids);
262		unit->domids = NULL;
263	}
264	if (unit->ctx_obj != NULL) {
265		vm_object_deallocate(unit->ctx_obj);
266		unit->ctx_obj = NULL;
267	}
268}
269
270static int
271dmar_alloc_irq(device_t dev, struct dmar_unit *unit, int idx)
272{
273	device_t pcib;
274	struct dmar_msi_data *dmd;
275	uint64_t msi_addr;
276	uint32_t msi_data;
277	int error;
278
279	dmd = &unit->intrs[idx];
280	pcib = device_get_parent(device_get_parent(dev)); /* Really not pcib */
281	error = PCIB_ALLOC_MSIX(pcib, dev, &dmd->irq);
282	if (error != 0) {
283		device_printf(dev, "cannot allocate %s interrupt, %d\n",
284		    dmd->name, error);
285		goto err1;
286	}
287	error = bus_set_resource(dev, SYS_RES_IRQ, dmd->irq_rid,
288	    dmd->irq, 1);
289	if (error != 0) {
290		device_printf(dev, "cannot set %s interrupt resource, %d\n",
291		    dmd->name, error);
292		goto err2;
293	}
294	dmd->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ,
295	    &dmd->irq_rid, RF_ACTIVE);
296	if (dmd->irq_res == NULL) {
297		device_printf(dev,
298		    "cannot allocate resource for %s interrupt\n", dmd->name);
299		error = ENXIO;
300		goto err3;
301	}
302	error = bus_setup_intr(dev, dmd->irq_res, INTR_TYPE_MISC,
303	    dmd->handler, NULL, unit, &dmd->intr_handle);
304	if (error != 0) {
305		device_printf(dev, "cannot setup %s interrupt, %d\n",
306		    dmd->name, error);
307		goto err4;
308	}
309	bus_describe_intr(dev, dmd->irq_res, dmd->intr_handle, "%s", dmd->name);
310	error = PCIB_MAP_MSI(pcib, dev, dmd->irq, &msi_addr, &msi_data);
311	if (error != 0) {
312		device_printf(dev, "cannot map %s interrupt, %d\n",
313		    dmd->name, error);
314		goto err5;
315	}
316	dmar_write4(unit, dmd->msi_data_reg, msi_data);
317	dmar_write4(unit, dmd->msi_addr_reg, msi_addr);
318	/* Only for xAPIC mode */
319	dmar_write4(unit, dmd->msi_uaddr_reg, msi_addr >> 32);
320	return (0);
321
322err5:
323	bus_teardown_intr(dev, dmd->irq_res, dmd->intr_handle);
324err4:
325	bus_release_resource(dev, SYS_RES_IRQ, dmd->irq_rid, dmd->irq_res);
326err3:
327	bus_delete_resource(dev, SYS_RES_IRQ, dmd->irq_rid);
328err2:
329	PCIB_RELEASE_MSIX(pcib, dev, dmd->irq);
330	dmd->irq = -1;
331err1:
332	return (error);
333}
334
335#ifdef DEV_APIC
336static int
337dmar_remap_intr(device_t dev, device_t child, u_int irq)
338{
339	struct dmar_unit *unit;
340	struct dmar_msi_data *dmd;
341	uint64_t msi_addr;
342	uint32_t msi_data;
343	int i, error;
344
345	unit = device_get_softc(dev);
346	for (i = 0; i < DMAR_INTR_TOTAL; i++) {
347		dmd = &unit->intrs[i];
348		if (irq == dmd->irq) {
349			error = PCIB_MAP_MSI(device_get_parent(
350			    device_get_parent(dev)),
351			    dev, irq, &msi_addr, &msi_data);
352			if (error != 0)
353				return (error);
354			DMAR_LOCK(unit);
355			(dmd->disable_intr)(unit);
356			dmar_write4(unit, dmd->msi_data_reg, msi_data);
357			dmar_write4(unit, dmd->msi_addr_reg, msi_addr);
358			dmar_write4(unit, dmd->msi_uaddr_reg, msi_addr >> 32);
359			(dmd->enable_intr)(unit);
360			DMAR_UNLOCK(unit);
361			return (0);
362		}
363	}
364	return (ENOENT);
365}
366#endif
367
368static void
369dmar_print_caps(device_t dev, struct dmar_unit *unit,
370    ACPI_DMAR_HARDWARE_UNIT *dmaru)
371{
372	uint32_t caphi, ecaphi;
373
374	device_printf(dev, "regs@0x%08jx, ver=%d.%d, seg=%d, flags=<%b>\n",
375	    (uintmax_t)dmaru->Address, DMAR_MAJOR_VER(unit->hw_ver),
376	    DMAR_MINOR_VER(unit->hw_ver), dmaru->Segment,
377	    dmaru->Flags, "\020\001INCLUDE_ALL_PCI");
378	caphi = unit->hw_cap >> 32;
379	device_printf(dev, "cap=%b,", (u_int)unit->hw_cap,
380	    "\020\004AFL\005WBF\006PLMR\007PHMR\010CM\027ZLR\030ISOCH");
381	printf("%b, ", caphi, "\020\010PSI\027DWD\030DRD\031FL1GP\034PSI");
382	printf("ndoms=%d, sagaw=%d, mgaw=%d, fro=%d, nfr=%d, superp=%d",
383	    DMAR_CAP_ND(unit->hw_cap), DMAR_CAP_SAGAW(unit->hw_cap),
384	    DMAR_CAP_MGAW(unit->hw_cap), DMAR_CAP_FRO(unit->hw_cap),
385	    DMAR_CAP_NFR(unit->hw_cap), DMAR_CAP_SPS(unit->hw_cap));
386	if ((unit->hw_cap & DMAR_CAP_PSI) != 0)
387		printf(", mamv=%d", DMAR_CAP_MAMV(unit->hw_cap));
388	printf("\n");
389	ecaphi = unit->hw_ecap >> 32;
390	device_printf(dev, "ecap=%b,", (u_int)unit->hw_ecap,
391	    "\020\001C\002QI\003DI\004IR\005EIM\007PT\010SC\031ECS\032MTS"
392	    "\033NEST\034DIS\035PASID\036PRS\037ERS\040SRS");
393	printf("%b, ", ecaphi, "\020\002NWFS\003EAFS");
394	printf("mhmw=%d, iro=%d\n", DMAR_ECAP_MHMV(unit->hw_ecap),
395	    DMAR_ECAP_IRO(unit->hw_ecap));
396}
397
398static int
399dmar_attach(device_t dev)
400{
401	struct dmar_unit *unit;
402	ACPI_DMAR_HARDWARE_UNIT *dmaru;
403	int i, error;
404
405	unit = device_get_softc(dev);
406	unit->dev = dev;
407	unit->unit = device_get_unit(dev);
408	dmaru = dmar_find_by_index(unit->unit);
409	if (dmaru == NULL)
410		return (EINVAL);
411	unit->segment = dmaru->Segment;
412	unit->base = dmaru->Address;
413	unit->reg_rid = DMAR_REG_RID;
414	unit->regs = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
415	    &unit->reg_rid, RF_ACTIVE);
416	if (unit->regs == NULL) {
417		device_printf(dev, "cannot allocate register window\n");
418		return (ENOMEM);
419	}
420	unit->hw_ver = dmar_read4(unit, DMAR_VER_REG);
421	unit->hw_cap = dmar_read8(unit, DMAR_CAP_REG);
422	unit->hw_ecap = dmar_read8(unit, DMAR_ECAP_REG);
423	if (bootverbose)
424		dmar_print_caps(dev, unit, dmaru);
425	dmar_quirks_post_ident(unit);
426
427	for (i = 0; i < DMAR_INTR_TOTAL; i++)
428		unit->intrs[i].irq = -1;
429
430	unit->intrs[DMAR_INTR_FAULT].name = "fault";
431	unit->intrs[DMAR_INTR_FAULT].irq_rid = DMAR_FAULT_IRQ_RID;
432	unit->intrs[DMAR_INTR_FAULT].handler = dmar_fault_intr;
433	unit->intrs[DMAR_INTR_FAULT].msi_data_reg = DMAR_FEDATA_REG;
434	unit->intrs[DMAR_INTR_FAULT].msi_addr_reg = DMAR_FEADDR_REG;
435	unit->intrs[DMAR_INTR_FAULT].msi_uaddr_reg = DMAR_FEUADDR_REG;
436	unit->intrs[DMAR_INTR_FAULT].enable_intr = dmar_enable_fault_intr;
437	unit->intrs[DMAR_INTR_FAULT].disable_intr = dmar_disable_fault_intr;
438	error = dmar_alloc_irq(dev, unit, DMAR_INTR_FAULT);
439	if (error != 0) {
440		dmar_release_resources(dev, unit);
441		return (error);
442	}
443	if (DMAR_HAS_QI(unit)) {
444		unit->intrs[DMAR_INTR_QI].name = "qi";
445		unit->intrs[DMAR_INTR_QI].irq_rid = DMAR_QI_IRQ_RID;
446		unit->intrs[DMAR_INTR_QI].handler = dmar_qi_intr;
447		unit->intrs[DMAR_INTR_QI].msi_data_reg = DMAR_IEDATA_REG;
448		unit->intrs[DMAR_INTR_QI].msi_addr_reg = DMAR_IEADDR_REG;
449		unit->intrs[DMAR_INTR_QI].msi_uaddr_reg = DMAR_IEUADDR_REG;
450		unit->intrs[DMAR_INTR_QI].enable_intr = dmar_enable_qi_intr;
451		unit->intrs[DMAR_INTR_QI].disable_intr = dmar_disable_qi_intr;
452		error = dmar_alloc_irq(dev, unit, DMAR_INTR_QI);
453		if (error != 0) {
454			dmar_release_resources(dev, unit);
455			return (error);
456		}
457	}
458
459	mtx_init(&unit->lock, "dmarhw", NULL, MTX_DEF);
460	unit->domids = new_unrhdr(0, dmar_nd2mask(DMAR_CAP_ND(unit->hw_cap)),
461	    &unit->lock);
462	LIST_INIT(&unit->domains);
463
464	/*
465	 * 9.2 "Context Entry":
466	 * When Caching Mode (CM) field is reported as Set, the
467	 * domain-id value of zero is architecturally reserved.
468	 * Software must not use domain-id value of zero
469	 * when CM is Set.
470	 */
471	if ((unit->hw_cap & DMAR_CAP_CM) != 0)
472		alloc_unr_specific(unit->domids, 0);
473
474	unit->ctx_obj = vm_pager_allocate(OBJT_PHYS, NULL, IDX_TO_OFF(1 +
475	    DMAR_CTX_CNT), 0, 0, NULL);
476
477	/*
478	 * Allocate and load the root entry table pointer.  Enable the
479	 * address translation after the required invalidations are
480	 * done.
481	 */
482	dmar_pgalloc(unit->ctx_obj, 0, DMAR_PGF_WAITOK | DMAR_PGF_ZERO);
483	DMAR_LOCK(unit);
484	error = dmar_load_root_entry_ptr(unit);
485	if (error != 0) {
486		DMAR_UNLOCK(unit);
487		dmar_release_resources(dev, unit);
488		return (error);
489	}
490	error = dmar_inv_ctx_glob(unit);
491	if (error != 0) {
492		DMAR_UNLOCK(unit);
493		dmar_release_resources(dev, unit);
494		return (error);
495	}
496	if ((unit->hw_ecap & DMAR_ECAP_DI) != 0) {
497		error = dmar_inv_iotlb_glob(unit);
498		if (error != 0) {
499			DMAR_UNLOCK(unit);
500			dmar_release_resources(dev, unit);
501			return (error);
502		}
503	}
504
505	DMAR_UNLOCK(unit);
506	error = dmar_init_fault_log(unit);
507	if (error != 0) {
508		dmar_release_resources(dev, unit);
509		return (error);
510	}
511	error = dmar_init_qi(unit);
512	if (error != 0) {
513		dmar_release_resources(dev, unit);
514		return (error);
515	}
516	error = dmar_init_irt(unit);
517	if (error != 0) {
518		dmar_release_resources(dev, unit);
519		return (error);
520	}
521	error = dmar_init_busdma(unit);
522	if (error != 0) {
523		dmar_release_resources(dev, unit);
524		return (error);
525	}
526
527#ifdef NOTYET
528	DMAR_LOCK(unit);
529	error = dmar_enable_translation(unit);
530	if (error != 0) {
531		DMAR_UNLOCK(unit);
532		dmar_release_resources(dev, unit);
533		return (error);
534	}
535	DMAR_UNLOCK(unit);
536#endif
537
538	return (0);
539}
540
541static int
542dmar_detach(device_t dev)
543{
544
545	return (EBUSY);
546}
547
548static int
549dmar_suspend(device_t dev)
550{
551
552	return (0);
553}
554
555static int
556dmar_resume(device_t dev)
557{
558
559	/* XXXKIB */
560	return (0);
561}
562
563static device_method_t dmar_methods[] = {
564	DEVMETHOD(device_identify, dmar_identify),
565	DEVMETHOD(device_probe, dmar_probe),
566	DEVMETHOD(device_attach, dmar_attach),
567	DEVMETHOD(device_detach, dmar_detach),
568	DEVMETHOD(device_suspend, dmar_suspend),
569	DEVMETHOD(device_resume, dmar_resume),
570#ifdef DEV_APIC
571	DEVMETHOD(bus_remap_intr, dmar_remap_intr),
572#endif
573	DEVMETHOD_END
574};
575
576static driver_t	dmar_driver = {
577	"dmar",
578	dmar_methods,
579	sizeof(struct dmar_unit),
580};
581
582DRIVER_MODULE(dmar, acpi, dmar_driver, dmar_devclass, 0, 0);
583MODULE_DEPEND(dmar, acpi, 1, 1, 1);
584
585static void
586dmar_print_path(device_t dev, const char *banner, int busno, int depth,
587    const ACPI_DMAR_PCI_PATH *path)
588{
589	int i;
590
591	device_printf(dev, "%s [%d, ", banner, busno);
592	for (i = 0; i < depth; i++) {
593		if (i != 0)
594			printf(", ");
595		printf("(%d, %d)", path[i].Device, path[i].Function);
596	}
597	printf("]\n");
598}
599
600static int
601dmar_dev_depth(device_t child)
602{
603	devclass_t pci_class;
604	device_t bus, pcib;
605	int depth;
606
607	pci_class = devclass_find("pci");
608	for (depth = 1; ; depth++) {
609		bus = device_get_parent(child);
610		pcib = device_get_parent(bus);
611		if (device_get_devclass(device_get_parent(pcib)) !=
612		    pci_class)
613			return (depth);
614		child = pcib;
615	}
616}
617
618static void
619dmar_dev_path(device_t child, int *busno, ACPI_DMAR_PCI_PATH *path, int depth)
620{
621	devclass_t pci_class;
622	device_t bus, pcib;
623
624	pci_class = devclass_find("pci");
625	for (depth--; depth != -1; depth--) {
626		path[depth].Device = pci_get_slot(child);
627		path[depth].Function = pci_get_function(child);
628		bus = device_get_parent(child);
629		pcib = device_get_parent(bus);
630		if (device_get_devclass(device_get_parent(pcib)) !=
631		    pci_class) {
632			/* reached a host bridge */
633			*busno = pcib_get_bus(bus);
634			return;
635		}
636		child = pcib;
637	}
638	panic("wrong depth");
639}
640
641static int
642dmar_match_pathes(int busno1, const ACPI_DMAR_PCI_PATH *path1, int depth1,
643    int busno2, const ACPI_DMAR_PCI_PATH *path2, int depth2,
644    enum AcpiDmarScopeType scope_type)
645{
646	int i, depth;
647
648	if (busno1 != busno2)
649		return (0);
650	if (scope_type == ACPI_DMAR_SCOPE_TYPE_ENDPOINT && depth1 != depth2)
651		return (0);
652	depth = depth1;
653	if (depth2 < depth)
654		depth = depth2;
655	for (i = 0; i < depth; i++) {
656		if (path1[i].Device != path2[i].Device ||
657		    path1[i].Function != path2[i].Function)
658			return (0);
659	}
660	return (1);
661}
662
663static int
664dmar_match_devscope(ACPI_DMAR_DEVICE_SCOPE *devscope, device_t dev,
665    int dev_busno, const ACPI_DMAR_PCI_PATH *dev_path, int dev_path_len)
666{
667	ACPI_DMAR_PCI_PATH *path;
668	int path_len;
669
670	if (devscope->Length < sizeof(*devscope)) {
671		printf("dmar_find: corrupted DMAR table, dl %d\n",
672		    devscope->Length);
673		return (-1);
674	}
675	if (devscope->EntryType != ACPI_DMAR_SCOPE_TYPE_ENDPOINT &&
676	    devscope->EntryType != ACPI_DMAR_SCOPE_TYPE_BRIDGE)
677		return (0);
678	path_len = devscope->Length - sizeof(*devscope);
679	if (path_len % 2 != 0) {
680		printf("dmar_find_bsf: corrupted DMAR table, dl %d\n",
681		    devscope->Length);
682		return (-1);
683	}
684	path_len /= 2;
685	path = (ACPI_DMAR_PCI_PATH *)(devscope + 1);
686	if (path_len == 0) {
687		printf("dmar_find: corrupted DMAR table, dl %d\n",
688		    devscope->Length);
689		return (-1);
690	}
691	if (dmar_match_verbose)
692		dmar_print_path(dev, "DMAR", devscope->Bus, path_len, path);
693
694	return (dmar_match_pathes(devscope->Bus, path, path_len, dev_busno,
695	    dev_path, dev_path_len, devscope->EntryType));
696}
697
698struct dmar_unit *
699dmar_find(device_t dev)
700{
701	device_t dmar_dev;
702	ACPI_DMAR_HARDWARE_UNIT *dmarh;
703	ACPI_DMAR_DEVICE_SCOPE *devscope;
704	char *ptr, *ptrend;
705	int i, match, dev_domain, dev_busno, dev_path_len;
706
707	dmar_dev = NULL;
708	dev_domain = pci_get_domain(dev);
709	dev_path_len = dmar_dev_depth(dev);
710	ACPI_DMAR_PCI_PATH dev_path[dev_path_len];
711	dmar_dev_path(dev, &dev_busno, dev_path, dev_path_len);
712	if (dmar_match_verbose)
713		dmar_print_path(dev, "PCI", dev_busno, dev_path_len, dev_path);
714
715	for (i = 0; i < dmar_devcnt; i++) {
716		if (dmar_devs[i] == NULL)
717			continue;
718		dmarh = dmar_find_by_index(i);
719		if (dmarh == NULL)
720			continue;
721		if (dmarh->Segment != dev_domain)
722			continue;
723		if ((dmarh->Flags & ACPI_DMAR_INCLUDE_ALL) != 0) {
724			dmar_dev = dmar_devs[i];
725			if (dmar_match_verbose) {
726				device_printf(dev,
727				    "pci%d:%d:%d:%d matched dmar%d INCLUDE_ALL\n",
728				    dev_domain, pci_get_bus(dev),
729				    pci_get_slot(dev),
730				    pci_get_function(dev),
731				    ((struct dmar_unit *)device_get_softc(
732				    dmar_dev))->unit);
733			}
734			goto found;
735		}
736		ptr = (char *)dmarh + sizeof(*dmarh);
737		ptrend = (char *)dmarh + dmarh->Header.Length;
738		for (;;) {
739			if (ptr >= ptrend)
740				break;
741			devscope = (ACPI_DMAR_DEVICE_SCOPE *)ptr;
742			ptr += devscope->Length;
743			if (dmar_match_verbose) {
744				device_printf(dev,
745				    "pci%d:%d:%d:%d matching dmar%d\n",
746				    dev_domain, pci_get_bus(dev),
747				    pci_get_slot(dev),
748				    pci_get_function(dev),
749				    ((struct dmar_unit *)device_get_softc(
750				    dmar_devs[i]))->unit);
751			}
752			match = dmar_match_devscope(devscope, dev, dev_busno,
753			    dev_path, dev_path_len);
754			if (dmar_match_verbose) {
755				if (match == -1)
756					printf("table error\n");
757				else if (match == 0)
758					printf("not matched\n");
759				else
760					printf("matched\n");
761			}
762			if (match == -1)
763				return (NULL);
764			else if (match == 1) {
765				dmar_dev = dmar_devs[i];
766				goto found;
767			}
768		}
769	}
770	return (NULL);
771found:
772	return (device_get_softc(dmar_dev));
773}
774
775static struct dmar_unit *
776dmar_find_nonpci(u_int id, u_int entry_type, uint16_t *rid)
777{
778	device_t dmar_dev;
779	struct dmar_unit *unit;
780	ACPI_DMAR_HARDWARE_UNIT *dmarh;
781	ACPI_DMAR_DEVICE_SCOPE *devscope;
782	ACPI_DMAR_PCI_PATH *path;
783	char *ptr, *ptrend;
784	int i;
785
786	for (i = 0; i < dmar_devcnt; i++) {
787		dmar_dev = dmar_devs[i];
788		if (dmar_dev == NULL)
789			continue;
790		unit = (struct dmar_unit *)device_get_softc(dmar_dev);
791		dmarh = dmar_find_by_index(i);
792		if (dmarh == NULL)
793			continue;
794		ptr = (char *)dmarh + sizeof(*dmarh);
795		ptrend = (char *)dmarh + dmarh->Header.Length;
796		for (;;) {
797			if (ptr >= ptrend)
798				break;
799			devscope = (ACPI_DMAR_DEVICE_SCOPE *)ptr;
800			ptr += devscope->Length;
801			if (devscope->EntryType != entry_type)
802				continue;
803			if (devscope->EnumerationId != id)
804				continue;
805			if (devscope->Length - sizeof(ACPI_DMAR_DEVICE_SCOPE)
806			    == 2) {
807				if (rid != NULL) {
808					path = (ACPI_DMAR_PCI_PATH *)
809					    (devscope + 1);
810					*rid = PCI_RID(devscope->Bus,
811					    path->Device, path->Function);
812				}
813				return (unit);
814			} else {
815				/* XXXKIB */
816				printf(
817		       "dmar_find_nonpci: id %d type %d path length != 2\n",
818				    id, entry_type);
819			}
820		}
821	}
822	return (NULL);
823}
824
825
826struct dmar_unit *
827dmar_find_hpet(device_t dev, uint16_t *rid)
828{
829
830	return (dmar_find_nonpci(hpet_get_uid(dev), ACPI_DMAR_SCOPE_TYPE_HPET,
831	    rid));
832}
833
834struct dmar_unit *
835dmar_find_ioapic(u_int apic_id, uint16_t *rid)
836{
837
838	return (dmar_find_nonpci(apic_id, ACPI_DMAR_SCOPE_TYPE_IOAPIC, rid));
839}
840
841struct rmrr_iter_args {
842	struct dmar_domain *domain;
843	device_t dev;
844	int dev_domain;
845	int dev_busno;
846	ACPI_DMAR_PCI_PATH *dev_path;
847	int dev_path_len;
848	struct dmar_map_entries_tailq *rmrr_entries;
849};
850
851static int
852dmar_rmrr_iter(ACPI_DMAR_HEADER *dmarh, void *arg)
853{
854	struct rmrr_iter_args *ria;
855	ACPI_DMAR_RESERVED_MEMORY *resmem;
856	ACPI_DMAR_DEVICE_SCOPE *devscope;
857	struct dmar_map_entry *entry;
858	char *ptr, *ptrend;
859	int match;
860
861	if (dmarh->Type != ACPI_DMAR_TYPE_RESERVED_MEMORY)
862		return (1);
863
864	ria = arg;
865	resmem = (ACPI_DMAR_RESERVED_MEMORY *)dmarh;
866	if (dmar_match_verbose) {
867		printf("RMRR [%jx,%jx] segment %d\n",
868		    (uintmax_t)resmem->BaseAddress,
869		    (uintmax_t)resmem->EndAddress,
870		    resmem->Segment);
871	}
872	if (resmem->Segment != ria->dev_domain)
873		return (1);
874
875	ptr = (char *)resmem + sizeof(*resmem);
876	ptrend = (char *)resmem + resmem->Header.Length;
877	for (;;) {
878		if (ptr >= ptrend)
879			break;
880		devscope = (ACPI_DMAR_DEVICE_SCOPE *)ptr;
881		ptr += devscope->Length;
882		match = dmar_match_devscope(devscope, ria->dev, ria->dev_busno,
883		    ria->dev_path, ria->dev_path_len);
884		if (match == 1) {
885			if (dmar_match_verbose)
886				printf("matched\n");
887			entry = dmar_gas_alloc_entry(ria->domain,
888			    DMAR_PGF_WAITOK);
889			entry->start = resmem->BaseAddress;
890			/* The RMRR entry end address is inclusive. */
891			entry->end = resmem->EndAddress;
892			TAILQ_INSERT_TAIL(ria->rmrr_entries, entry,
893			    unroll_link);
894		} else if (dmar_match_verbose) {
895			printf("not matched, err %d\n", match);
896		}
897	}
898
899	return (1);
900}
901
902void
903dmar_dev_parse_rmrr(struct dmar_domain *domain, device_t dev,
904    struct dmar_map_entries_tailq *rmrr_entries)
905{
906	struct rmrr_iter_args ria;
907
908	ria.dev_domain = pci_get_domain(dev);
909	ria.dev_path_len = dmar_dev_depth(dev);
910	ACPI_DMAR_PCI_PATH dev_path[ria.dev_path_len];
911	dmar_dev_path(dev, &ria.dev_busno, dev_path, ria.dev_path_len);
912
913	if (dmar_match_verbose) {
914		device_printf(dev, "parsing RMRR entries for ");
915		dmar_print_path(dev, "PCI", ria.dev_busno, ria.dev_path_len,
916		    dev_path);
917	}
918
919	ria.domain = domain;
920	ria.dev = dev;
921	ria.dev_path = dev_path;
922	ria.rmrr_entries = rmrr_entries;
923	dmar_iterate_tbl(dmar_rmrr_iter, &ria);
924}
925
926struct inst_rmrr_iter_args {
927	struct dmar_unit *dmar;
928};
929
930static device_t
931dmar_path_dev(int segment, int path_len, int busno,
932    const ACPI_DMAR_PCI_PATH *path)
933{
934	devclass_t pci_class;
935	device_t bus, pcib, dev;
936	int i;
937
938	pci_class = devclass_find("pci");
939	dev = NULL;
940	for (i = 0; i < path_len; i++, path++) {
941		dev = pci_find_dbsf(segment, busno, path->Device,
942		    path->Function);
943		if (dev == NULL)
944			break;
945		if (i != path_len - 1) {
946			bus = device_get_parent(dev);
947			pcib = device_get_parent(bus);
948			if (device_get_devclass(device_get_parent(pcib)) !=
949			    pci_class)
950				return (NULL);
951		}
952		busno = pcib_get_bus(dev);
953	}
954	return (dev);
955}
956
957static int
958dmar_inst_rmrr_iter(ACPI_DMAR_HEADER *dmarh, void *arg)
959{
960	const ACPI_DMAR_RESERVED_MEMORY *resmem;
961	const ACPI_DMAR_DEVICE_SCOPE *devscope;
962	struct inst_rmrr_iter_args *iria;
963	const char *ptr, *ptrend;
964	struct dmar_unit *dev_dmar;
965	device_t dev;
966
967	if (dmarh->Type != ACPI_DMAR_TYPE_RESERVED_MEMORY)
968		return (1);
969
970	iria = arg;
971	resmem = (ACPI_DMAR_RESERVED_MEMORY *)dmarh;
972	if (resmem->Segment != iria->dmar->segment)
973		return (1);
974	if (dmar_match_verbose) {
975		printf("dmar%d: RMRR [%jx,%jx]\n", iria->dmar->unit,
976		    (uintmax_t)resmem->BaseAddress,
977		    (uintmax_t)resmem->EndAddress);
978	}
979
980	ptr = (const char *)resmem + sizeof(*resmem);
981	ptrend = (const char *)resmem + resmem->Header.Length;
982	for (;;) {
983		if (ptr >= ptrend)
984			break;
985		devscope = (const ACPI_DMAR_DEVICE_SCOPE *)ptr;
986		ptr += devscope->Length;
987		/* XXXKIB bridge */
988		if (devscope->EntryType != ACPI_DMAR_SCOPE_TYPE_ENDPOINT)
989			continue;
990		if (dmar_match_verbose) {
991			dmar_print_path(iria->dmar->dev, "RMRR scope",
992			    devscope->Bus, (devscope->Length -
993			    sizeof(ACPI_DMAR_DEVICE_SCOPE)) / 2,
994			    (const ACPI_DMAR_PCI_PATH *)(devscope + 1));
995		}
996		dev = dmar_path_dev(resmem->Segment, (devscope->Length -
997		    sizeof(ACPI_DMAR_DEVICE_SCOPE)) / 2, devscope->Bus,
998		    (const ACPI_DMAR_PCI_PATH *)(devscope + 1));
999		if (dev == NULL) {
1000			if (dmar_match_verbose)
1001				printf("null dev\n");
1002			continue;
1003		}
1004		dev_dmar = dmar_find(dev);
1005		if (dev_dmar != iria->dmar) {
1006			if (dmar_match_verbose) {
1007				printf("dmar%d matched, skipping\n",
1008				    dev_dmar->unit);
1009			}
1010			continue;
1011		}
1012		if (dmar_match_verbose)
1013			printf("matched, instantiating RMRR context\n");
1014		dmar_instantiate_ctx(iria->dmar, dev, true);
1015	}
1016
1017	return (1);
1018
1019}
1020
1021/*
1022 * Pre-create all contexts for the DMAR which have RMRR entries.
1023 */
1024int
1025dmar_instantiate_rmrr_ctxs(struct dmar_unit *dmar)
1026{
1027	struct inst_rmrr_iter_args iria;
1028	int error;
1029
1030	if (!dmar_barrier_enter(dmar, DMAR_BARRIER_RMRR))
1031		return (0);
1032
1033	error = 0;
1034	iria.dmar = dmar;
1035	if (dmar_match_verbose)
1036		printf("dmar%d: instantiating RMRR contexts\n", dmar->unit);
1037	dmar_iterate_tbl(dmar_inst_rmrr_iter, &iria);
1038	DMAR_LOCK(dmar);
1039	if (!LIST_EMPTY(&dmar->domains)) {
1040		KASSERT((dmar->hw_gcmd & DMAR_GCMD_TE) == 0,
1041	    ("dmar%d: RMRR not handled but translation is already enabled",
1042		    dmar->unit));
1043		error = dmar_enable_translation(dmar);
1044	}
1045	dmar_barrier_exit(dmar, DMAR_BARRIER_RMRR);
1046	return (error);
1047}
1048
1049#ifdef DDB
1050#include <ddb/ddb.h>
1051#include <ddb/db_lex.h>
1052
1053static void
1054dmar_print_domain_entry(const struct dmar_map_entry *entry)
1055{
1056	struct dmar_map_entry *l, *r;
1057
1058	db_printf(
1059	    "    start %jx end %jx free_after %jx free_down %jx flags %x ",
1060	    entry->start, entry->end, entry->free_after, entry->free_down,
1061	    entry->flags);
1062	db_printf("left ");
1063	l = RB_LEFT(entry, rb_entry);
1064	if (l == NULL)
1065		db_printf("NULL ");
1066	else
1067		db_printf("%jx ", l->start);
1068	db_printf("right ");
1069	r = RB_RIGHT(entry, rb_entry);
1070	if (r == NULL)
1071		db_printf("NULL");
1072	else
1073		db_printf("%jx", r->start);
1074	db_printf("\n");
1075}
1076
1077static void
1078dmar_print_ctx(struct dmar_ctx *ctx)
1079{
1080
1081	db_printf(
1082	    "    @%p pci%d:%d:%d refs %d flags %x loads %lu unloads %lu\n",
1083	    ctx, pci_get_bus(ctx->ctx_tag.owner),
1084	    pci_get_slot(ctx->ctx_tag.owner),
1085	    pci_get_function(ctx->ctx_tag.owner), ctx->refs, ctx->flags,
1086	    ctx->loads, ctx->unloads);
1087}
1088
1089static void
1090dmar_print_domain(struct dmar_domain *domain, bool show_mappings)
1091{
1092	struct dmar_map_entry *entry;
1093	struct dmar_ctx *ctx;
1094
1095	db_printf(
1096	    "  @%p dom %d mgaw %d agaw %d pglvl %d end %jx refs %d\n"
1097	    "   ctx_cnt %d flags %x pgobj %p map_ents %u\n",
1098	    domain, domain->domain, domain->mgaw, domain->agaw, domain->pglvl,
1099	    (uintmax_t)domain->end, domain->refs, domain->ctx_cnt,
1100	    domain->flags, domain->pgtbl_obj, domain->entries_cnt);
1101	if (!LIST_EMPTY(&domain->contexts)) {
1102		db_printf("  Contexts:\n");
1103		LIST_FOREACH(ctx, &domain->contexts, link)
1104			dmar_print_ctx(ctx);
1105	}
1106	if (!show_mappings)
1107		return;
1108	db_printf("    mapped:\n");
1109	RB_FOREACH(entry, dmar_gas_entries_tree, &domain->rb_root) {
1110		dmar_print_domain_entry(entry);
1111		if (db_pager_quit)
1112			break;
1113	}
1114	if (db_pager_quit)
1115		return;
1116	db_printf("    unloading:\n");
1117	TAILQ_FOREACH(entry, &domain->unload_entries, dmamap_link) {
1118		dmar_print_domain_entry(entry);
1119		if (db_pager_quit)
1120			break;
1121	}
1122}
1123
1124DB_FUNC(dmar_domain, db_dmar_print_domain, db_show_table, CS_OWN, NULL)
1125{
1126	struct dmar_unit *unit;
1127	struct dmar_domain *domain;
1128	struct dmar_ctx *ctx;
1129	bool show_mappings, valid;
1130	int pci_domain, bus, device, function, i, t;
1131	db_expr_t radix;
1132
1133	valid = false;
1134	radix = db_radix;
1135	db_radix = 10;
1136	t = db_read_token();
1137	if (t == tSLASH) {
1138		t = db_read_token();
1139		if (t != tIDENT) {
1140			db_printf("Bad modifier\n");
1141			db_radix = radix;
1142			db_skip_to_eol();
1143			return;
1144		}
1145		show_mappings = strchr(db_tok_string, 'm') != NULL;
1146		t = db_read_token();
1147	} else {
1148		show_mappings = false;
1149	}
1150	if (t == tNUMBER) {
1151		pci_domain = db_tok_number;
1152		t = db_read_token();
1153		if (t == tNUMBER) {
1154			bus = db_tok_number;
1155			t = db_read_token();
1156			if (t == tNUMBER) {
1157				device = db_tok_number;
1158				t = db_read_token();
1159				if (t == tNUMBER) {
1160					function = db_tok_number;
1161					valid = true;
1162				}
1163			}
1164		}
1165	}
1166			db_radix = radix;
1167	db_skip_to_eol();
1168	if (!valid) {
1169		db_printf("usage: show dmar_domain [/m] "
1170		    "<domain> <bus> <device> <func>\n");
1171		return;
1172	}
1173	for (i = 0; i < dmar_devcnt; i++) {
1174		unit = device_get_softc(dmar_devs[i]);
1175		LIST_FOREACH(domain, &unit->domains, link) {
1176			LIST_FOREACH(ctx, &domain->contexts, link) {
1177				if (pci_domain == unit->segment &&
1178				    bus == pci_get_bus(ctx->ctx_tag.owner) &&
1179				    device ==
1180				    pci_get_slot(ctx->ctx_tag.owner) &&
1181				    function ==
1182				    pci_get_function(ctx->ctx_tag.owner)) {
1183					dmar_print_domain(domain,
1184					    show_mappings);
1185					goto out;
1186				}
1187			}
1188		}
1189	}
1190out:;
1191}
1192
1193static void
1194dmar_print_one(int idx, bool show_domains, bool show_mappings)
1195{
1196	struct dmar_unit *unit;
1197	struct dmar_domain *domain;
1198	int i, frir;
1199
1200	unit = device_get_softc(dmar_devs[idx]);
1201	db_printf("dmar%d at %p, root at 0x%jx, ver 0x%x\n", unit->unit, unit,
1202	    dmar_read8(unit, DMAR_RTADDR_REG), dmar_read4(unit, DMAR_VER_REG));
1203	db_printf("cap 0x%jx ecap 0x%jx gsts 0x%x fsts 0x%x fectl 0x%x\n",
1204	    (uintmax_t)dmar_read8(unit, DMAR_CAP_REG),
1205	    (uintmax_t)dmar_read8(unit, DMAR_ECAP_REG),
1206	    dmar_read4(unit, DMAR_GSTS_REG),
1207	    dmar_read4(unit, DMAR_FSTS_REG),
1208	    dmar_read4(unit, DMAR_FECTL_REG));
1209	if (unit->ir_enabled) {
1210		db_printf("ir is enabled; IRT @%p phys 0x%jx maxcnt %d\n",
1211		    unit->irt, (uintmax_t)unit->irt_phys, unit->irte_cnt);
1212	}
1213	db_printf("fed 0x%x fea 0x%x feua 0x%x\n",
1214	    dmar_read4(unit, DMAR_FEDATA_REG),
1215	    dmar_read4(unit, DMAR_FEADDR_REG),
1216	    dmar_read4(unit, DMAR_FEUADDR_REG));
1217	db_printf("primary fault log:\n");
1218	for (i = 0; i < DMAR_CAP_NFR(unit->hw_cap); i++) {
1219		frir = (DMAR_CAP_FRO(unit->hw_cap) + i) * 16;
1220		db_printf("  %d at 0x%x: %jx %jx\n", i, frir,
1221		    (uintmax_t)dmar_read8(unit, frir),
1222		    (uintmax_t)dmar_read8(unit, frir + 8));
1223	}
1224	if (DMAR_HAS_QI(unit)) {
1225		db_printf("ied 0x%x iea 0x%x ieua 0x%x\n",
1226		    dmar_read4(unit, DMAR_IEDATA_REG),
1227		    dmar_read4(unit, DMAR_IEADDR_REG),
1228		    dmar_read4(unit, DMAR_IEUADDR_REG));
1229		if (unit->qi_enabled) {
1230			db_printf("qi is enabled: queue @0x%jx (IQA 0x%jx) "
1231			    "size 0x%jx\n"
1232		    "  head 0x%x tail 0x%x avail 0x%x status 0x%x ctrl 0x%x\n"
1233		    "  hw compl 0x%x@%p/phys@%jx next seq 0x%x gen 0x%x\n",
1234			    (uintmax_t)unit->inv_queue,
1235			    (uintmax_t)dmar_read8(unit, DMAR_IQA_REG),
1236			    (uintmax_t)unit->inv_queue_size,
1237			    dmar_read4(unit, DMAR_IQH_REG),
1238			    dmar_read4(unit, DMAR_IQT_REG),
1239			    unit->inv_queue_avail,
1240			    dmar_read4(unit, DMAR_ICS_REG),
1241			    dmar_read4(unit, DMAR_IECTL_REG),
1242			    unit->inv_waitd_seq_hw,
1243			    &unit->inv_waitd_seq_hw,
1244			    (uintmax_t)unit->inv_waitd_seq_hw_phys,
1245			    unit->inv_waitd_seq,
1246			    unit->inv_waitd_gen);
1247		} else {
1248			db_printf("qi is disabled\n");
1249		}
1250	}
1251	if (show_domains) {
1252		db_printf("domains:\n");
1253		LIST_FOREACH(domain, &unit->domains, link) {
1254			dmar_print_domain(domain, show_mappings);
1255			if (db_pager_quit)
1256				break;
1257		}
1258	}
1259}
1260
1261DB_SHOW_COMMAND(dmar, db_dmar_print)
1262{
1263	bool show_domains, show_mappings;
1264
1265	show_domains = strchr(modif, 'd') != NULL;
1266	show_mappings = strchr(modif, 'm') != NULL;
1267	if (!have_addr) {
1268		db_printf("usage: show dmar [/d] [/m] index\n");
1269		return;
1270	}
1271	dmar_print_one((int)addr, show_domains, show_mappings);
1272}
1273
1274DB_SHOW_ALL_COMMAND(dmars, db_show_all_dmars)
1275{
1276	int i;
1277	bool show_domains, show_mappings;
1278
1279	show_domains = strchr(modif, 'd') != NULL;
1280	show_mappings = strchr(modif, 'm') != NULL;
1281
1282	for (i = 0; i < dmar_devcnt; i++) {
1283		dmar_print_one(i, show_domains, show_mappings);
1284		if (db_pager_quit)
1285			break;
1286	}
1287}
1288#endif
1289