xref: /freebsd-src/sys/x86/iommu/intel_fault.c (revision 5967352a923efe6676bdf794d6b73f7354719a43)
186be9f0dSKonstantin Belousov /*-
24d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
3ebf5747bSPedro F. Giffuni  *
486be9f0dSKonstantin Belousov  * Copyright (c) 2013 The FreeBSD Foundation
586be9f0dSKonstantin Belousov  *
686be9f0dSKonstantin Belousov  * This software was developed by Konstantin Belousov <kib@FreeBSD.org>
786be9f0dSKonstantin Belousov  * under sponsorship from the FreeBSD Foundation.
886be9f0dSKonstantin Belousov  *
986be9f0dSKonstantin Belousov  * Redistribution and use in source and binary forms, with or without
1086be9f0dSKonstantin Belousov  * modification, are permitted provided that the following conditions
1186be9f0dSKonstantin Belousov  * are met:
1286be9f0dSKonstantin Belousov  * 1. Redistributions of source code must retain the above copyright
1386be9f0dSKonstantin Belousov  *    notice, this list of conditions and the following disclaimer.
1486be9f0dSKonstantin Belousov  * 2. Redistributions in binary form must reproduce the above copyright
1586be9f0dSKonstantin Belousov  *    notice, this list of conditions and the following disclaimer in the
1686be9f0dSKonstantin Belousov  *    documentation and/or other materials provided with the distribution.
1786be9f0dSKonstantin Belousov  *
1886be9f0dSKonstantin Belousov  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1986be9f0dSKonstantin Belousov  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2086be9f0dSKonstantin Belousov  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2186be9f0dSKonstantin Belousov  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2286be9f0dSKonstantin Belousov  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2386be9f0dSKonstantin Belousov  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2486be9f0dSKonstantin Belousov  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2586be9f0dSKonstantin Belousov  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2686be9f0dSKonstantin Belousov  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2786be9f0dSKonstantin Belousov  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2886be9f0dSKonstantin Belousov  * SUCH DAMAGE.
2986be9f0dSKonstantin Belousov  */
3086be9f0dSKonstantin Belousov 
3186be9f0dSKonstantin Belousov #include "opt_acpi.h"
3286be9f0dSKonstantin Belousov 
3386be9f0dSKonstantin Belousov #include <sys/param.h>
3486be9f0dSKonstantin Belousov #include <sys/bus.h>
3586be9f0dSKonstantin Belousov #include <sys/kernel.h>
3686be9f0dSKonstantin Belousov #include <sys/malloc.h>
3786be9f0dSKonstantin Belousov #include <sys/memdesc.h>
3886be9f0dSKonstantin Belousov #include <sys/module.h>
3986be9f0dSKonstantin Belousov #include <sys/rman.h>
4086be9f0dSKonstantin Belousov #include <sys/taskqueue.h>
4186be9f0dSKonstantin Belousov #include <sys/tree.h>
420a110d5bSKonstantin Belousov #include <sys/vmem.h>
4386be9f0dSKonstantin Belousov #include <machine/bus.h>
4486be9f0dSKonstantin Belousov #include <contrib/dev/acpica/include/acpi.h>
4586be9f0dSKonstantin Belousov #include <contrib/dev/acpica/include/accommon.h>
4686be9f0dSKonstantin Belousov #include <dev/acpica/acpivar.h>
4767499354SRyan Stone #include <dev/pci/pcireg.h>
4867499354SRyan Stone #include <dev/pci/pcivar.h>
4986be9f0dSKonstantin Belousov #include <vm/vm.h>
5086be9f0dSKonstantin Belousov #include <vm/vm_extern.h>
5186be9f0dSKonstantin Belousov #include <vm/vm_kern.h>
5286be9f0dSKonstantin Belousov #include <vm/vm_page.h>
5386be9f0dSKonstantin Belousov #include <vm/vm_map.h>
5486be9f0dSKonstantin Belousov #include <x86/include/busdma_impl.h>
5586be9f0dSKonstantin Belousov #include <x86/iommu/intel_reg.h>
56f2b2f317SRuslan Bukin #include <dev/iommu/busdma_iommu.h>
5740d951bcSKonstantin Belousov #include <x86/iommu/x86_iommu.h>
5886be9f0dSKonstantin Belousov #include <x86/iommu/intel_dmar.h>
5986be9f0dSKonstantin Belousov 
6086be9f0dSKonstantin Belousov /*
6186be9f0dSKonstantin Belousov  * Fault interrupt handling for DMARs.  If advanced fault logging is
6286be9f0dSKonstantin Belousov  * not implemented by hardware, the code emulates it.  Fast interrupt
6386be9f0dSKonstantin Belousov  * handler flushes the fault registers into circular buffer at
6486be9f0dSKonstantin Belousov  * unit->fault_log, and schedules a task.
6586be9f0dSKonstantin Belousov  *
6686be9f0dSKonstantin Belousov  * The fast handler is used since faults usually come in bursts, and
6786be9f0dSKonstantin Belousov  * number of fault log registers is limited, e.g. down to one for 5400
6886be9f0dSKonstantin Belousov  * MCH.  We are trying to reduce the latency for clearing the fault
6986be9f0dSKonstantin Belousov  * register file.  The task is usually long-running, since printf() is
7086be9f0dSKonstantin Belousov  * slow, but this is not problematic because bursts are rare.
7186be9f0dSKonstantin Belousov  *
7286be9f0dSKonstantin Belousov  * For the same reason, each translation unit task is executed in its
7386be9f0dSKonstantin Belousov  * own thread.
7486be9f0dSKonstantin Belousov  *
7586be9f0dSKonstantin Belousov  * XXXKIB It seems there is no hardware available which implements
7686be9f0dSKonstantin Belousov  * advanced fault logging, so the code to handle AFL is not written.
7786be9f0dSKonstantin Belousov  */
7886be9f0dSKonstantin Belousov 
7986be9f0dSKonstantin Belousov static int
8086be9f0dSKonstantin Belousov dmar_fault_next(struct dmar_unit *unit, int faultp)
8186be9f0dSKonstantin Belousov {
8286be9f0dSKonstantin Belousov 
8386be9f0dSKonstantin Belousov 	faultp += 2;
8486be9f0dSKonstantin Belousov 	if (faultp == unit->fault_log_size)
8586be9f0dSKonstantin Belousov 		faultp = 0;
8686be9f0dSKonstantin Belousov 	return (faultp);
8786be9f0dSKonstantin Belousov }
8886be9f0dSKonstantin Belousov 
8986be9f0dSKonstantin Belousov static void
9068eeb96aSKonstantin Belousov dmar_fault_intr_clear(struct dmar_unit *unit, uint32_t fsts)
9186be9f0dSKonstantin Belousov {
9286be9f0dSKonstantin Belousov 	uint32_t clear;
9386be9f0dSKonstantin Belousov 
9486be9f0dSKonstantin Belousov 	clear = 0;
9586be9f0dSKonstantin Belousov 	if ((fsts & DMAR_FSTS_ITE) != 0) {
9659e37c8aSRuslan Bukin 		printf("DMAR%d: Invalidation timed out\n", unit->iommu.unit);
9786be9f0dSKonstantin Belousov 		clear |= DMAR_FSTS_ITE;
9886be9f0dSKonstantin Belousov 	}
9986be9f0dSKonstantin Belousov 	if ((fsts & DMAR_FSTS_ICE) != 0) {
10086be9f0dSKonstantin Belousov 		printf("DMAR%d: Invalidation completion error\n",
10159e37c8aSRuslan Bukin 		    unit->iommu.unit);
10286be9f0dSKonstantin Belousov 		clear |= DMAR_FSTS_ICE;
10386be9f0dSKonstantin Belousov 	}
10486be9f0dSKonstantin Belousov 	if ((fsts & DMAR_FSTS_IQE) != 0) {
10586be9f0dSKonstantin Belousov 		printf("DMAR%d: Invalidation queue error\n",
10659e37c8aSRuslan Bukin 		    unit->iommu.unit);
10786be9f0dSKonstantin Belousov 		clear |= DMAR_FSTS_IQE;
10886be9f0dSKonstantin Belousov 	}
10986be9f0dSKonstantin Belousov 	if ((fsts & DMAR_FSTS_APF) != 0) {
11059e37c8aSRuslan Bukin 		printf("DMAR%d: Advanced pending fault\n", unit->iommu.unit);
11186be9f0dSKonstantin Belousov 		clear |= DMAR_FSTS_APF;
11286be9f0dSKonstantin Belousov 	}
11386be9f0dSKonstantin Belousov 	if ((fsts & DMAR_FSTS_AFO) != 0) {
11459e37c8aSRuslan Bukin 		printf("DMAR%d: Advanced fault overflow\n", unit->iommu.unit);
11586be9f0dSKonstantin Belousov 		clear |= DMAR_FSTS_AFO;
11686be9f0dSKonstantin Belousov 	}
11786be9f0dSKonstantin Belousov 	if (clear != 0)
11886be9f0dSKonstantin Belousov 		dmar_write4(unit, DMAR_FSTS_REG, clear);
11986be9f0dSKonstantin Belousov }
12086be9f0dSKonstantin Belousov 
12186be9f0dSKonstantin Belousov int
12268eeb96aSKonstantin Belousov dmar_fault_intr(void *arg)
12386be9f0dSKonstantin Belousov {
12486be9f0dSKonstantin Belousov 	struct dmar_unit *unit;
12586be9f0dSKonstantin Belousov 	uint64_t fault_rec[2];
12686be9f0dSKonstantin Belousov 	uint32_t fsts;
12786be9f0dSKonstantin Belousov 	int fri, frir, faultp;
12886be9f0dSKonstantin Belousov 	bool enqueue;
12986be9f0dSKonstantin Belousov 
130*5967352aSKonstantin Belousov 	unit = IOMMU2DMAR((struct iommu_unit *)arg);
13186be9f0dSKonstantin Belousov 	enqueue = false;
13286be9f0dSKonstantin Belousov 	fsts = dmar_read4(unit, DMAR_FSTS_REG);
13368eeb96aSKonstantin Belousov 	dmar_fault_intr_clear(unit, fsts);
13486be9f0dSKonstantin Belousov 
13586be9f0dSKonstantin Belousov 	if ((fsts & DMAR_FSTS_PPF) == 0)
13686be9f0dSKonstantin Belousov 		goto done;
13786be9f0dSKonstantin Belousov 
13886be9f0dSKonstantin Belousov 	fri = DMAR_FSTS_FRI(fsts);
13986be9f0dSKonstantin Belousov 	for (;;) {
14086be9f0dSKonstantin Belousov 		frir = (DMAR_CAP_FRO(unit->hw_cap) + fri) * 16;
14186be9f0dSKonstantin Belousov 		fault_rec[1] = dmar_read8(unit, frir + 8);
14286be9f0dSKonstantin Belousov 		if ((fault_rec[1] & DMAR_FRCD2_F) == 0)
14386be9f0dSKonstantin Belousov 			break;
14486be9f0dSKonstantin Belousov 		fault_rec[0] = dmar_read8(unit, frir);
14586be9f0dSKonstantin Belousov 		dmar_write4(unit, frir + 12, DMAR_FRCD2_F32);
14686be9f0dSKonstantin Belousov 		DMAR_FAULT_LOCK(unit);
14786be9f0dSKonstantin Belousov 		faultp = unit->fault_log_head;
14886be9f0dSKonstantin Belousov 		if (dmar_fault_next(unit, faultp) == unit->fault_log_tail) {
14986be9f0dSKonstantin Belousov 			/* XXXKIB log overflow */
15086be9f0dSKonstantin Belousov 		} else {
15186be9f0dSKonstantin Belousov 			unit->fault_log[faultp] = fault_rec[0];
15286be9f0dSKonstantin Belousov 			unit->fault_log[faultp + 1] = fault_rec[1];
15386be9f0dSKonstantin Belousov 			unit->fault_log_head = dmar_fault_next(unit, faultp);
15486be9f0dSKonstantin Belousov 			enqueue = true;
15586be9f0dSKonstantin Belousov 		}
15686be9f0dSKonstantin Belousov 		DMAR_FAULT_UNLOCK(unit);
15786be9f0dSKonstantin Belousov 		fri += 1;
15886be9f0dSKonstantin Belousov 		if (fri >= DMAR_CAP_NFR(unit->hw_cap))
15986be9f0dSKonstantin Belousov 			fri = 0;
16086be9f0dSKonstantin Belousov 	}
16186be9f0dSKonstantin Belousov 
16286be9f0dSKonstantin Belousov done:
16386be9f0dSKonstantin Belousov 	/*
16486be9f0dSKonstantin Belousov 	 * On SandyBridge, due to errata BJ124, IvyBridge errata
16586be9f0dSKonstantin Belousov 	 * BV100, and Haswell errata HSD40, "Spurious Intel VT-d
16686be9f0dSKonstantin Belousov 	 * Interrupts May Occur When the PFO Bit is Set".  Handle the
16786be9f0dSKonstantin Belousov 	 * cases by clearing overflow bit even if no fault is
16886be9f0dSKonstantin Belousov 	 * reported.
16986be9f0dSKonstantin Belousov 	 *
17086be9f0dSKonstantin Belousov 	 * On IvyBridge, errata BV30 states that clearing clear
17186be9f0dSKonstantin Belousov 	 * DMAR_FRCD2_F bit in the fault register causes spurious
17286be9f0dSKonstantin Belousov 	 * interrupt.  Do nothing.
17386be9f0dSKonstantin Belousov 	 *
17486be9f0dSKonstantin Belousov 	 */
17586be9f0dSKonstantin Belousov 	if ((fsts & DMAR_FSTS_PFO) != 0) {
17659e37c8aSRuslan Bukin 		printf("DMAR%d: Fault Overflow\n", unit->iommu.unit);
17786be9f0dSKonstantin Belousov 		dmar_write4(unit, DMAR_FSTS_REG, DMAR_FSTS_PFO);
17886be9f0dSKonstantin Belousov 	}
17986be9f0dSKonstantin Belousov 
18086be9f0dSKonstantin Belousov 	if (enqueue) {
181cbc4d2dbSJohn Baldwin 		taskqueue_enqueue(unit->fault_taskqueue,
18286be9f0dSKonstantin Belousov 		    &unit->fault_task);
18386be9f0dSKonstantin Belousov 	}
18486be9f0dSKonstantin Belousov 	return (FILTER_HANDLED);
18586be9f0dSKonstantin Belousov }
18686be9f0dSKonstantin Belousov 
18786be9f0dSKonstantin Belousov static void
18886be9f0dSKonstantin Belousov dmar_fault_task(void *arg, int pending __unused)
18986be9f0dSKonstantin Belousov {
19086be9f0dSKonstantin Belousov 	struct dmar_unit *unit;
19186be9f0dSKonstantin Belousov 	struct dmar_ctx *ctx;
19286be9f0dSKonstantin Belousov 	uint64_t fault_rec[2];
19386be9f0dSKonstantin Belousov 	int sid, bus, slot, func, faultp;
19486be9f0dSKonstantin Belousov 
19586be9f0dSKonstantin Belousov 	unit = arg;
19686be9f0dSKonstantin Belousov 	DMAR_FAULT_LOCK(unit);
19786be9f0dSKonstantin Belousov 	for (;;) {
19886be9f0dSKonstantin Belousov 		faultp = unit->fault_log_tail;
19986be9f0dSKonstantin Belousov 		if (faultp == unit->fault_log_head)
20086be9f0dSKonstantin Belousov 			break;
20186be9f0dSKonstantin Belousov 
20286be9f0dSKonstantin Belousov 		fault_rec[0] = unit->fault_log[faultp];
20386be9f0dSKonstantin Belousov 		fault_rec[1] = unit->fault_log[faultp + 1];
20486be9f0dSKonstantin Belousov 		unit->fault_log_tail = dmar_fault_next(unit, faultp);
20586be9f0dSKonstantin Belousov 		DMAR_FAULT_UNLOCK(unit);
20686be9f0dSKonstantin Belousov 
20786be9f0dSKonstantin Belousov 		sid = DMAR_FRCD2_SID(fault_rec[1]);
20859e37c8aSRuslan Bukin 		printf("DMAR%d: ", unit->iommu.unit);
20986be9f0dSKonstantin Belousov 		DMAR_LOCK(unit);
21067499354SRyan Stone 		ctx = dmar_find_ctx_locked(unit, sid);
21186be9f0dSKonstantin Belousov 		if (ctx == NULL) {
21286be9f0dSKonstantin Belousov 			printf("<unknown dev>:");
21367499354SRyan Stone 
21467499354SRyan Stone 			/*
21567499354SRyan Stone 			 * Note that the slot and function will not be correct
21667499354SRyan Stone 			 * if ARI is in use, but without a ctx entry we have
21767499354SRyan Stone 			 * no way of knowing whether ARI is in use or not.
21867499354SRyan Stone 			 */
21967499354SRyan Stone 			bus = PCI_RID2BUS(sid);
22067499354SRyan Stone 			slot = PCI_RID2SLOT(sid);
22167499354SRyan Stone 			func = PCI_RID2FUNC(sid);
22286be9f0dSKonstantin Belousov 		} else {
22359e37c8aSRuslan Bukin 			ctx->context.flags |= IOMMU_CTX_FAULTED;
22486be9f0dSKonstantin Belousov 			ctx->last_fault_rec[0] = fault_rec[0];
22586be9f0dSKonstantin Belousov 			ctx->last_fault_rec[1] = fault_rec[1];
22659e37c8aSRuslan Bukin 			device_print_prettyname(ctx->context.tag->owner);
22759e37c8aSRuslan Bukin 			bus = pci_get_bus(ctx->context.tag->owner);
22859e37c8aSRuslan Bukin 			slot = pci_get_slot(ctx->context.tag->owner);
22959e37c8aSRuslan Bukin 			func = pci_get_function(ctx->context.tag->owner);
23086be9f0dSKonstantin Belousov 		}
23186be9f0dSKonstantin Belousov 		DMAR_UNLOCK(unit);
23286be9f0dSKonstantin Belousov 		printf(
23334e8337bSKonstantin Belousov 		    "pci%d:%d:%d sid %x fault acc %x adt 0x%x reason 0x%x "
23434e8337bSKonstantin Belousov 		    "addr %jx\n",
23534e8337bSKonstantin Belousov 		    bus, slot, func, sid, DMAR_FRCD2_T(fault_rec[1]),
23686be9f0dSKonstantin Belousov 		    DMAR_FRCD2_AT(fault_rec[1]), DMAR_FRCD2_FR(fault_rec[1]),
23786be9f0dSKonstantin Belousov 		    (uintmax_t)fault_rec[0]);
23886be9f0dSKonstantin Belousov 		DMAR_FAULT_LOCK(unit);
23986be9f0dSKonstantin Belousov 	}
24086be9f0dSKonstantin Belousov 	DMAR_FAULT_UNLOCK(unit);
24186be9f0dSKonstantin Belousov }
24286be9f0dSKonstantin Belousov 
24386be9f0dSKonstantin Belousov static void
24486be9f0dSKonstantin Belousov dmar_clear_faults(struct dmar_unit *unit)
24586be9f0dSKonstantin Belousov {
24686be9f0dSKonstantin Belousov 	uint32_t frec, frir, fsts;
24786be9f0dSKonstantin Belousov 	int i;
24886be9f0dSKonstantin Belousov 
24986be9f0dSKonstantin Belousov 	for (i = 0; i < DMAR_CAP_NFR(unit->hw_cap); i++) {
25086be9f0dSKonstantin Belousov 		frir = (DMAR_CAP_FRO(unit->hw_cap) + i) * 16;
25186be9f0dSKonstantin Belousov 		frec = dmar_read4(unit, frir + 12);
25286be9f0dSKonstantin Belousov 		if ((frec & DMAR_FRCD2_F32) == 0)
25386be9f0dSKonstantin Belousov 			continue;
25486be9f0dSKonstantin Belousov 		dmar_write4(unit, frir + 12, DMAR_FRCD2_F32);
25586be9f0dSKonstantin Belousov 	}
25686be9f0dSKonstantin Belousov 	fsts = dmar_read4(unit, DMAR_FSTS_REG);
25786be9f0dSKonstantin Belousov 	dmar_write4(unit, DMAR_FSTS_REG, fsts);
25886be9f0dSKonstantin Belousov }
25986be9f0dSKonstantin Belousov 
26086be9f0dSKonstantin Belousov int
26186be9f0dSKonstantin Belousov dmar_init_fault_log(struct dmar_unit *unit)
26286be9f0dSKonstantin Belousov {
26386be9f0dSKonstantin Belousov 
26486be9f0dSKonstantin Belousov 	mtx_init(&unit->fault_lock, "dmarflt", NULL, MTX_SPIN);
26586be9f0dSKonstantin Belousov 	unit->fault_log_size = 256; /* 128 fault log entries */
26686be9f0dSKonstantin Belousov 	TUNABLE_INT_FETCH("hw.dmar.fault_log_size", &unit->fault_log_size);
26786be9f0dSKonstantin Belousov 	if (unit->fault_log_size % 2 != 0)
26886be9f0dSKonstantin Belousov 		panic("hw.dmar_fault_log_size must be even");
26986be9f0dSKonstantin Belousov 	unit->fault_log = malloc(sizeof(uint64_t) * unit->fault_log_size,
27086be9f0dSKonstantin Belousov 	    M_DEVBUF, M_WAITOK | M_ZERO);
27186be9f0dSKonstantin Belousov 
27286be9f0dSKonstantin Belousov 	TASK_INIT(&unit->fault_task, 0, dmar_fault_task, unit);
27385d99487SKonstantin Belousov 	unit->fault_taskqueue = taskqueue_create_fast("dmarff", M_WAITOK,
27486be9f0dSKonstantin Belousov 	    taskqueue_thread_enqueue, &unit->fault_taskqueue);
27586be9f0dSKonstantin Belousov 	taskqueue_start_threads(&unit->fault_taskqueue, 1, PI_AV,
27659e37c8aSRuslan Bukin 	    "dmar%d fault taskq", unit->iommu.unit);
27786be9f0dSKonstantin Belousov 
27868eeb96aSKonstantin Belousov 	DMAR_LOCK(unit);
279*5967352aSKonstantin Belousov 	dmar_disable_fault_intr(&unit->iommu);
28086be9f0dSKonstantin Belousov 	dmar_clear_faults(unit);
281*5967352aSKonstantin Belousov 	dmar_enable_fault_intr(&unit->iommu);
28268eeb96aSKonstantin Belousov 	DMAR_UNLOCK(unit);
28386be9f0dSKonstantin Belousov 
28486be9f0dSKonstantin Belousov 	return (0);
28586be9f0dSKonstantin Belousov }
28686be9f0dSKonstantin Belousov 
28786be9f0dSKonstantin Belousov void
28886be9f0dSKonstantin Belousov dmar_fini_fault_log(struct dmar_unit *unit)
28986be9f0dSKonstantin Belousov {
29086be9f0dSKonstantin Belousov 
29124408112SRyan Libby 	if (unit->fault_taskqueue == NULL)
29224408112SRyan Libby 		return;
29324408112SRyan Libby 
29468eeb96aSKonstantin Belousov 	DMAR_LOCK(unit);
295*5967352aSKonstantin Belousov 	dmar_disable_fault_intr(&unit->iommu);
29668eeb96aSKonstantin Belousov 	DMAR_UNLOCK(unit);
29786be9f0dSKonstantin Belousov 
29886be9f0dSKonstantin Belousov 	taskqueue_drain(unit->fault_taskqueue, &unit->fault_task);
29986be9f0dSKonstantin Belousov 	taskqueue_free(unit->fault_taskqueue);
30068eeb96aSKonstantin Belousov 	unit->fault_taskqueue = NULL;
30186be9f0dSKonstantin Belousov 	mtx_destroy(&unit->fault_lock);
30286be9f0dSKonstantin Belousov 
30386be9f0dSKonstantin Belousov 	free(unit->fault_log, M_DEVBUF);
30486be9f0dSKonstantin Belousov 	unit->fault_log = NULL;
30586be9f0dSKonstantin Belousov 	unit->fault_log_head = unit->fault_log_tail = 0;
30686be9f0dSKonstantin Belousov }
30768eeb96aSKonstantin Belousov 
30868eeb96aSKonstantin Belousov void
309*5967352aSKonstantin Belousov dmar_enable_fault_intr(struct iommu_unit *iommu)
31068eeb96aSKonstantin Belousov {
311*5967352aSKonstantin Belousov 	struct dmar_unit *unit;
31268eeb96aSKonstantin Belousov 	uint32_t fectl;
31368eeb96aSKonstantin Belousov 
314*5967352aSKonstantin Belousov 	unit = IOMMU2DMAR(iommu);
31568eeb96aSKonstantin Belousov 	DMAR_ASSERT_LOCKED(unit);
31668eeb96aSKonstantin Belousov 	fectl = dmar_read4(unit, DMAR_FECTL_REG);
31768eeb96aSKonstantin Belousov 	fectl &= ~DMAR_FECTL_IM;
31868eeb96aSKonstantin Belousov 	dmar_write4(unit, DMAR_FECTL_REG, fectl);
31968eeb96aSKonstantin Belousov }
32068eeb96aSKonstantin Belousov 
32168eeb96aSKonstantin Belousov void
322*5967352aSKonstantin Belousov dmar_disable_fault_intr(struct iommu_unit *iommu)
32368eeb96aSKonstantin Belousov {
324*5967352aSKonstantin Belousov 	struct dmar_unit *unit;
32568eeb96aSKonstantin Belousov 	uint32_t fectl;
32668eeb96aSKonstantin Belousov 
327*5967352aSKonstantin Belousov 	unit = IOMMU2DMAR(iommu);
32868eeb96aSKonstantin Belousov 	DMAR_ASSERT_LOCKED(unit);
32968eeb96aSKonstantin Belousov 	fectl = dmar_read4(unit, DMAR_FECTL_REG);
33068eeb96aSKonstantin Belousov 	dmar_write4(unit, DMAR_FECTL_REG, fectl | DMAR_FECTL_IM);
33168eeb96aSKonstantin Belousov }
332