1*0f5116d7SKonstantin Belousov /*- 2*0f5116d7SKonstantin Belousov * SPDX-License-Identifier: BSD-2-Clause 3*0f5116d7SKonstantin Belousov * 4*0f5116d7SKonstantin Belousov * Copyright (c) 2024 The FreeBSD Foundation 5*0f5116d7SKonstantin Belousov * 6*0f5116d7SKonstantin Belousov * This software was developed by Konstantin Belousov <kib@FreeBSD.org> 7*0f5116d7SKonstantin Belousov * under sponsorship from the FreeBSD Foundation. 8*0f5116d7SKonstantin Belousov * 9*0f5116d7SKonstantin Belousov * Redistribution and use in source and binary forms, with or without 10*0f5116d7SKonstantin Belousov * modification, are permitted provided that the following conditions 11*0f5116d7SKonstantin Belousov * are met: 12*0f5116d7SKonstantin Belousov * 1. Redistributions of source code must retain the above copyright 13*0f5116d7SKonstantin Belousov * notice, this list of conditions and the following disclaimer. 14*0f5116d7SKonstantin Belousov * 2. Redistributions in binary form must reproduce the above copyright 15*0f5116d7SKonstantin Belousov * notice, this list of conditions and the following disclaimer in the 16*0f5116d7SKonstantin Belousov * documentation and/or other materials provided with the distribution. 17*0f5116d7SKonstantin Belousov * 18*0f5116d7SKonstantin Belousov * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19*0f5116d7SKonstantin Belousov * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20*0f5116d7SKonstantin Belousov * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21*0f5116d7SKonstantin Belousov * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22*0f5116d7SKonstantin Belousov * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23*0f5116d7SKonstantin Belousov * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24*0f5116d7SKonstantin Belousov * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25*0f5116d7SKonstantin Belousov * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26*0f5116d7SKonstantin Belousov * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27*0f5116d7SKonstantin Belousov * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28*0f5116d7SKonstantin Belousov * SUCH DAMAGE. 29*0f5116d7SKonstantin Belousov */ 30*0f5116d7SKonstantin Belousov 31*0f5116d7SKonstantin Belousov #include "opt_acpi.h" 32*0f5116d7SKonstantin Belousov 33*0f5116d7SKonstantin Belousov #include <sys/param.h> 34*0f5116d7SKonstantin Belousov #include <sys/bus.h> 35*0f5116d7SKonstantin Belousov #include <sys/kernel.h> 36*0f5116d7SKonstantin Belousov #include <sys/lock.h> 37*0f5116d7SKonstantin Belousov #include <sys/malloc.h> 38*0f5116d7SKonstantin Belousov #include <sys/memdesc.h> 39*0f5116d7SKonstantin Belousov #include <sys/module.h> 40*0f5116d7SKonstantin Belousov #include <sys/mutex.h> 41*0f5116d7SKonstantin Belousov #include <sys/rman.h> 42*0f5116d7SKonstantin Belousov #include <sys/rwlock.h> 43*0f5116d7SKonstantin Belousov #include <sys/smp.h> 44*0f5116d7SKonstantin Belousov #include <sys/taskqueue.h> 45*0f5116d7SKonstantin Belousov #include <sys/tree.h> 46*0f5116d7SKonstantin Belousov #include <sys/vmem.h> 47*0f5116d7SKonstantin Belousov #include <vm/vm.h> 48*0f5116d7SKonstantin Belousov #include <vm/vm_extern.h> 49*0f5116d7SKonstantin Belousov #include <vm/vm_object.h> 50*0f5116d7SKonstantin Belousov #include <vm/vm_page.h> 51*0f5116d7SKonstantin Belousov #include <vm/vm_pageout.h> 52*0f5116d7SKonstantin Belousov #include <vm/vm_pager.h> 53*0f5116d7SKonstantin Belousov #include <contrib/dev/acpica/include/acpi.h> 54*0f5116d7SKonstantin Belousov #include <contrib/dev/acpica/include/accommon.h> 55*0f5116d7SKonstantin Belousov #include <dev/acpica/acpivar.h> 56*0f5116d7SKonstantin Belousov #include <dev/pci/pcireg.h> 57*0f5116d7SKonstantin Belousov #include <dev/pci/pcivar.h> 58*0f5116d7SKonstantin Belousov #include <machine/bus.h> 59*0f5116d7SKonstantin Belousov #include <machine/pci_cfgreg.h> 60*0f5116d7SKonstantin Belousov #include "pcib_if.h" 61*0f5116d7SKonstantin Belousov #include <machine/intr_machdep.h> 62*0f5116d7SKonstantin Belousov #include <machine/md_var.h> 63*0f5116d7SKonstantin Belousov #include <machine/cputypes.h> 64*0f5116d7SKonstantin Belousov #include <x86/apicreg.h> 65*0f5116d7SKonstantin Belousov #include <x86/apicvar.h> 66*0f5116d7SKonstantin Belousov #include <dev/iommu/iommu.h> 67*0f5116d7SKonstantin Belousov #include <dev/iommu/busdma_iommu.h> 68*0f5116d7SKonstantin Belousov #include <x86/iommu/amd_reg.h> 69*0f5116d7SKonstantin Belousov #include <x86/iommu/x86_iommu.h> 70*0f5116d7SKonstantin Belousov #include <x86/iommu/amd_iommu.h> 71*0f5116d7SKonstantin Belousov 72*0f5116d7SKonstantin Belousov static void 73*0f5116d7SKonstantin Belousov amdiommu_event_rearm_intr(struct amdiommu_unit *unit) 74*0f5116d7SKonstantin Belousov { 75*0f5116d7SKonstantin Belousov amdiommu_write8(unit, AMDIOMMU_CMDEV_STATUS, 76*0f5116d7SKonstantin Belousov AMDIOMMU_CMDEVS_EVLOGINT); 77*0f5116d7SKonstantin Belousov } 78*0f5116d7SKonstantin Belousov 79*0f5116d7SKonstantin Belousov static void 80*0f5116d7SKonstantin Belousov amdiommu_event_log_inc_head(struct amdiommu_unit *unit) 81*0f5116d7SKonstantin Belousov { 82*0f5116d7SKonstantin Belousov unit->event_log_head++; 83*0f5116d7SKonstantin Belousov if (unit->event_log_head >= unit->event_log_size) 84*0f5116d7SKonstantin Belousov unit->event_log_head = 0; 85*0f5116d7SKonstantin Belousov } 86*0f5116d7SKonstantin Belousov 87*0f5116d7SKonstantin Belousov static void 88*0f5116d7SKonstantin Belousov amdiommu_event_log_print(struct amdiommu_unit *unit, 89*0f5116d7SKonstantin Belousov const struct amdiommu_event_generic *evp, bool fancy) 90*0f5116d7SKonstantin Belousov { 91*0f5116d7SKonstantin Belousov printf("amdiommu%d: event type 0x%x 0x%08x 0x%08x 0x%08x 0x%08x\n", 92*0f5116d7SKonstantin Belousov unit->iommu.unit, evp->code, evp->w0, evp->ww1, evp->w2, evp->w3); 93*0f5116d7SKonstantin Belousov if (!fancy) 94*0f5116d7SKonstantin Belousov return; 95*0f5116d7SKonstantin Belousov 96*0f5116d7SKonstantin Belousov AMDIOMMU_ASSERT_LOCKED(unit); 97*0f5116d7SKonstantin Belousov if (evp->code == AMDIOMMU_EV_ILL_DEV_TABLE_ENTRY) { 98*0f5116d7SKonstantin Belousov const struct amdiommu_event_ill_dev_table_entry *ev_dte_p; 99*0f5116d7SKonstantin Belousov const struct amdiommu_dte *dte; 100*0f5116d7SKonstantin Belousov const uint32_t *x; 101*0f5116d7SKonstantin Belousov int i; 102*0f5116d7SKonstantin Belousov 103*0f5116d7SKonstantin Belousov ev_dte_p = (const struct 104*0f5116d7SKonstantin Belousov amdiommu_event_ill_dev_table_entry *)evp; 105*0f5116d7SKonstantin Belousov dte = &unit->dev_tbl[ev_dte_p->devid]; 106*0f5116d7SKonstantin Belousov 107*0f5116d7SKonstantin Belousov printf("\tIllegal Dev Tab Entry dte@%p:", dte); 108*0f5116d7SKonstantin Belousov for (i = 0, x = (const uint32_t *)dte; i < sizeof(*dte) / 109*0f5116d7SKonstantin Belousov sizeof(uint32_t); i++, x++) 110*0f5116d7SKonstantin Belousov printf(" 0x%08x", *x); 111*0f5116d7SKonstantin Belousov printf("\n"); 112*0f5116d7SKonstantin Belousov } else if (evp->code == AMDIOMMU_EV_IO_PAGE_FAULT) { 113*0f5116d7SKonstantin Belousov const struct amdiommu_event_io_page_fault_entry *ev_iopf_p; 114*0f5116d7SKonstantin Belousov struct amdiommu_ctx *ctx; 115*0f5116d7SKonstantin Belousov device_t dev; 116*0f5116d7SKonstantin Belousov 117*0f5116d7SKonstantin Belousov ev_iopf_p = (const struct 118*0f5116d7SKonstantin Belousov amdiommu_event_io_page_fault_entry *)evp; 119*0f5116d7SKonstantin Belousov printf("\tPage Fault rid %#x dom %d", 120*0f5116d7SKonstantin Belousov ev_iopf_p->devid, ev_iopf_p->pasid); 121*0f5116d7SKonstantin Belousov ctx = amdiommu_find_ctx_locked(unit, ev_iopf_p->devid); 122*0f5116d7SKonstantin Belousov if (ctx != NULL) { 123*0f5116d7SKonstantin Belousov dev = ctx->context.tag->owner; 124*0f5116d7SKonstantin Belousov if (dev != NULL) 125*0f5116d7SKonstantin Belousov printf(" %s", device_get_nameunit(dev)); 126*0f5116d7SKonstantin Belousov } 127*0f5116d7SKonstantin Belousov printf("\n\t" 128*0f5116d7SKonstantin Belousov "gn %d nx %d us %d i %d pr %d rw %d pe %d rz %d tr %d" 129*0f5116d7SKonstantin Belousov "\n\tgaddr %#jx\n", 130*0f5116d7SKonstantin Belousov ev_iopf_p->gn, ev_iopf_p->nx, ev_iopf_p->us, ev_iopf_p->i, 131*0f5116d7SKonstantin Belousov ev_iopf_p->pr, ev_iopf_p->rw, ev_iopf_p->pe, ev_iopf_p->rz, 132*0f5116d7SKonstantin Belousov ev_iopf_p->tr, 133*0f5116d7SKonstantin Belousov (((uintmax_t)(ev_iopf_p->addr2)) << 32) | 134*0f5116d7SKonstantin Belousov ev_iopf_p->addr1); 135*0f5116d7SKonstantin Belousov } 136*0f5116d7SKonstantin Belousov } 137*0f5116d7SKonstantin Belousov 138*0f5116d7SKonstantin Belousov static u_int 139*0f5116d7SKonstantin Belousov amdiommu_event_log_tail(struct amdiommu_unit *unit) 140*0f5116d7SKonstantin Belousov { 141*0f5116d7SKonstantin Belousov return (amdiommu_read8(unit, AMDIOMMU_EVNTLOG_TAIL) >> 142*0f5116d7SKonstantin Belousov AMDIOMMU_EV_SZ_SHIFT); 143*0f5116d7SKonstantin Belousov } 144*0f5116d7SKonstantin Belousov 145*0f5116d7SKonstantin Belousov static u_int 146*0f5116d7SKonstantin Belousov amdiommu_event_copy_log_inc(u_int idx) 147*0f5116d7SKonstantin Belousov { 148*0f5116d7SKonstantin Belousov idx++; 149*0f5116d7SKonstantin Belousov if (idx == nitems(((struct amdiommu_unit *)NULL)->event_copy_log)) 150*0f5116d7SKonstantin Belousov idx = 0; 151*0f5116d7SKonstantin Belousov return (idx); 152*0f5116d7SKonstantin Belousov } 153*0f5116d7SKonstantin Belousov 154*0f5116d7SKonstantin Belousov static bool 155*0f5116d7SKonstantin Belousov amdiommu_event_copy_log_hasspace(struct amdiommu_unit *unit) 156*0f5116d7SKonstantin Belousov { 157*0f5116d7SKonstantin Belousov return (unit->event_copy_tail != amdiommu_event_copy_log_inc( 158*0f5116d7SKonstantin Belousov unit->event_copy_head)); 159*0f5116d7SKonstantin Belousov } 160*0f5116d7SKonstantin Belousov 161*0f5116d7SKonstantin Belousov void 162*0f5116d7SKonstantin Belousov amdiommu_event_intr(struct amdiommu_unit *unit, uint64_t status) 163*0f5116d7SKonstantin Belousov { 164*0f5116d7SKonstantin Belousov struct amdiommu_event_generic *evp; 165*0f5116d7SKonstantin Belousov u_int hw_tail, hw_tail1; 166*0f5116d7SKonstantin Belousov bool enqueue; 167*0f5116d7SKonstantin Belousov 168*0f5116d7SKonstantin Belousov enqueue = (status & AMDIOMMU_CMDEVS_EVOVRFLW) != 0; 169*0f5116d7SKonstantin Belousov 170*0f5116d7SKonstantin Belousov hw_tail1 = amdiommu_event_log_tail(unit); 171*0f5116d7SKonstantin Belousov do { 172*0f5116d7SKonstantin Belousov hw_tail = hw_tail1; 173*0f5116d7SKonstantin Belousov for (; hw_tail != unit->event_log_head; 174*0f5116d7SKonstantin Belousov amdiommu_event_log_inc_head(unit)) { 175*0f5116d7SKonstantin Belousov evp = &unit->event_log[unit->event_log_head]; 176*0f5116d7SKonstantin Belousov mtx_lock_spin(&unit->event_lock); 177*0f5116d7SKonstantin Belousov if (amdiommu_event_copy_log_hasspace(unit)) { 178*0f5116d7SKonstantin Belousov unit->event_copy_log[unit->event_copy_head] = 179*0f5116d7SKonstantin Belousov *evp; 180*0f5116d7SKonstantin Belousov unit->event_copy_head = 181*0f5116d7SKonstantin Belousov amdiommu_event_copy_log_inc(unit-> 182*0f5116d7SKonstantin Belousov event_copy_head); 183*0f5116d7SKonstantin Belousov enqueue = true; 184*0f5116d7SKonstantin Belousov } else { 185*0f5116d7SKonstantin Belousov amdiommu_event_log_print(unit, evp, false); 186*0f5116d7SKonstantin Belousov } 187*0f5116d7SKonstantin Belousov mtx_unlock_spin(&unit->event_lock); 188*0f5116d7SKonstantin Belousov } 189*0f5116d7SKonstantin Belousov amdiommu_write8(unit, AMDIOMMU_EVNTLOG_HEAD, 190*0f5116d7SKonstantin Belousov unit->event_log_head << AMDIOMMU_EV_SZ_SHIFT); 191*0f5116d7SKonstantin Belousov hw_tail1 = amdiommu_event_log_tail(unit); 192*0f5116d7SKonstantin Belousov } while (hw_tail1 != hw_tail); 193*0f5116d7SKonstantin Belousov amdiommu_event_rearm_intr(unit); 194*0f5116d7SKonstantin Belousov 195*0f5116d7SKonstantin Belousov if (enqueue) 196*0f5116d7SKonstantin Belousov taskqueue_enqueue(unit->event_taskqueue, &unit->event_task); 197*0f5116d7SKonstantin Belousov } 198*0f5116d7SKonstantin Belousov 199*0f5116d7SKonstantin Belousov static void 200*0f5116d7SKonstantin Belousov amdiommu_event_task(void *arg, int pending __unused) 201*0f5116d7SKonstantin Belousov { 202*0f5116d7SKonstantin Belousov struct amdiommu_unit *unit; 203*0f5116d7SKonstantin Belousov uint64_t hwev_status, status; 204*0f5116d7SKonstantin Belousov struct amdiommu_event_generic hwev; 205*0f5116d7SKonstantin Belousov 206*0f5116d7SKonstantin Belousov unit = arg; 207*0f5116d7SKonstantin Belousov AMDIOMMU_LOCK(unit); 208*0f5116d7SKonstantin Belousov 209*0f5116d7SKonstantin Belousov if ((unit->efr & AMDIOMMU_EFR_HWEV_SUP) != 0) { 210*0f5116d7SKonstantin Belousov hwev_status = amdiommu_read8(unit, AMDIOMMU_HWEV_STATUS); 211*0f5116d7SKonstantin Belousov if ((hwev_status & AMDIOMMU_HWEVS_HEV) != 0) { 212*0f5116d7SKonstantin Belousov *(uint64_t *)&hwev = amdiommu_read8(unit, 213*0f5116d7SKonstantin Belousov AMDIOMMU_HWEV_LOWER); 214*0f5116d7SKonstantin Belousov *((uint64_t *)&hwev + 1) = amdiommu_read8(unit, 215*0f5116d7SKonstantin Belousov AMDIOMMU_HWEV_UPPER); 216*0f5116d7SKonstantin Belousov printf("amdiommu%d: hw event%s\n", unit->iommu.unit, 217*0f5116d7SKonstantin Belousov (hwev_status & AMDIOMMU_HWEVS_HEO) != 0 ? 218*0f5116d7SKonstantin Belousov " (overflown)" : ""); 219*0f5116d7SKonstantin Belousov amdiommu_event_log_print(unit, &hwev, true); 220*0f5116d7SKonstantin Belousov amdiommu_write8(unit, AMDIOMMU_HWEV_STATUS, 221*0f5116d7SKonstantin Belousov hwev_status); 222*0f5116d7SKonstantin Belousov } 223*0f5116d7SKonstantin Belousov } 224*0f5116d7SKonstantin Belousov 225*0f5116d7SKonstantin Belousov status = amdiommu_read8(unit, AMDIOMMU_CMDEV_STATUS); 226*0f5116d7SKonstantin Belousov if ((status & AMDIOMMU_CMDEVS_EVOVRFLW) != 0) { 227*0f5116d7SKonstantin Belousov printf("amdiommu%d: event log overflow\n", unit->iommu.unit); 228*0f5116d7SKonstantin Belousov 229*0f5116d7SKonstantin Belousov while ((status & AMDIOMMU_CMDEVS_EVLOGRUN) != 0) { 230*0f5116d7SKonstantin Belousov DELAY(1); 231*0f5116d7SKonstantin Belousov status = amdiommu_read8(unit, AMDIOMMU_CMDEV_STATUS); 232*0f5116d7SKonstantin Belousov } 233*0f5116d7SKonstantin Belousov 234*0f5116d7SKonstantin Belousov unit->hw_ctrl &= ~AMDIOMMU_CTRL_EVNTLOG_EN; 235*0f5116d7SKonstantin Belousov amdiommu_write8(unit, AMDIOMMU_CTRL, unit->hw_ctrl); 236*0f5116d7SKonstantin Belousov 237*0f5116d7SKonstantin Belousov unit->event_log_head = 0; 238*0f5116d7SKonstantin Belousov amdiommu_write8(unit, AMDIOMMU_EVNTLOG_HEAD, 0); 239*0f5116d7SKonstantin Belousov 240*0f5116d7SKonstantin Belousov amdiommu_write8(unit, AMDIOMMU_CMDEV_STATUS, 241*0f5116d7SKonstantin Belousov AMDIOMMU_CMDEVS_EVOVRFLW); /* RW1C */ 242*0f5116d7SKonstantin Belousov 243*0f5116d7SKonstantin Belousov unit->hw_ctrl |= AMDIOMMU_CTRL_EVNTLOG_EN; 244*0f5116d7SKonstantin Belousov amdiommu_write8(unit, AMDIOMMU_CTRL, unit->hw_ctrl); 245*0f5116d7SKonstantin Belousov 246*0f5116d7SKonstantin Belousov amdiommu_event_rearm_intr(unit); 247*0f5116d7SKonstantin Belousov } 248*0f5116d7SKonstantin Belousov 249*0f5116d7SKonstantin Belousov mtx_lock_spin(&unit->event_lock); 250*0f5116d7SKonstantin Belousov while (unit->event_copy_head != unit->event_copy_tail) { 251*0f5116d7SKonstantin Belousov mtx_unlock_spin(&unit->event_lock); 252*0f5116d7SKonstantin Belousov amdiommu_event_log_print(unit, &unit->event_copy_log[ 253*0f5116d7SKonstantin Belousov unit->event_copy_tail], true); 254*0f5116d7SKonstantin Belousov mtx_lock_spin(&unit->event_lock); 255*0f5116d7SKonstantin Belousov unit->event_copy_tail = amdiommu_event_copy_log_inc(unit-> 256*0f5116d7SKonstantin Belousov event_copy_tail); 257*0f5116d7SKonstantin Belousov } 258*0f5116d7SKonstantin Belousov mtx_unlock_spin(&unit->event_lock); 259*0f5116d7SKonstantin Belousov 260*0f5116d7SKonstantin Belousov AMDIOMMU_UNLOCK(unit); 261*0f5116d7SKonstantin Belousov } 262*0f5116d7SKonstantin Belousov 263*0f5116d7SKonstantin Belousov int 264*0f5116d7SKonstantin Belousov amdiommu_init_event(struct amdiommu_unit *unit) 265*0f5116d7SKonstantin Belousov { 266*0f5116d7SKonstantin Belousov uint64_t base_reg; 267*0f5116d7SKonstantin Belousov 268*0f5116d7SKonstantin Belousov mtx_init(&unit->event_lock, "amdevl", NULL, MTX_SPIN); 269*0f5116d7SKonstantin Belousov 270*0f5116d7SKonstantin Belousov /* event log entries */ 271*0f5116d7SKonstantin Belousov unit->event_log_size = AMDIOMMU_EVNTLOG_MIN; 272*0f5116d7SKonstantin Belousov TUNABLE_INT_FETCH("hw.amdiommu.event_log_size", &unit->event_log_size); 273*0f5116d7SKonstantin Belousov if (unit->event_log_size < AMDIOMMU_EVNTLOG_MIN || 274*0f5116d7SKonstantin Belousov unit->event_log_size > AMDIOMMU_EVNTLOG_MAX || 275*0f5116d7SKonstantin Belousov !powerof2(unit->event_log_size)) 276*0f5116d7SKonstantin Belousov panic("invalid hw.amdiommu.event_log_size"); 277*0f5116d7SKonstantin Belousov unit->event_log = kmem_alloc_contig(AMDIOMMU_EV_SZ * 278*0f5116d7SKonstantin Belousov unit->event_log_size, M_WAITOK | M_ZERO, 0, ~0ull, PAGE_SIZE, 279*0f5116d7SKonstantin Belousov 0, VM_MEMATTR_DEFAULT); 280*0f5116d7SKonstantin Belousov 281*0f5116d7SKonstantin Belousov TASK_INIT(&unit->event_task, 0, amdiommu_event_task, unit); 282*0f5116d7SKonstantin Belousov unit->event_taskqueue = taskqueue_create_fast("amdiommuff", M_WAITOK, 283*0f5116d7SKonstantin Belousov taskqueue_thread_enqueue, &unit->event_taskqueue); 284*0f5116d7SKonstantin Belousov taskqueue_start_threads(&unit->event_taskqueue, 1, PI_AV, 285*0f5116d7SKonstantin Belousov "amdiommu%d event taskq", unit->iommu.unit); 286*0f5116d7SKonstantin Belousov 287*0f5116d7SKonstantin Belousov base_reg = pmap_kextract((vm_offset_t)unit->event_log) | 288*0f5116d7SKonstantin Belousov (((uint64_t)0x8 + ilog2(unit->event_log_size / 289*0f5116d7SKonstantin Belousov AMDIOMMU_EVNTLOG_MIN)) << AMDIOMMU_EVNTLOG_BASE_SZSHIFT); 290*0f5116d7SKonstantin Belousov AMDIOMMU_LOCK(unit); 291*0f5116d7SKonstantin Belousov /* 292*0f5116d7SKonstantin Belousov * Re-arm before enabling interrupt, to not loose it when 293*0f5116d7SKonstantin Belousov * re-arming in the interrupt handler. 294*0f5116d7SKonstantin Belousov */ 295*0f5116d7SKonstantin Belousov amdiommu_event_rearm_intr(unit); 296*0f5116d7SKonstantin Belousov amdiommu_write8(unit, AMDIOMMU_EVNTLOG_BASE, base_reg); 297*0f5116d7SKonstantin Belousov unit->hw_ctrl |= AMDIOMMU_CTRL_EVNTLOG_EN | AMDIOMMU_CTRL_EVENTINT_EN; 298*0f5116d7SKonstantin Belousov amdiommu_write8(unit, AMDIOMMU_CTRL, unit->hw_ctrl); 299*0f5116d7SKonstantin Belousov AMDIOMMU_UNLOCK(unit); 300*0f5116d7SKonstantin Belousov 301*0f5116d7SKonstantin Belousov return (0); 302*0f5116d7SKonstantin Belousov } 303*0f5116d7SKonstantin Belousov 304*0f5116d7SKonstantin Belousov void 305*0f5116d7SKonstantin Belousov amdiommu_fini_event(struct amdiommu_unit *unit) 306*0f5116d7SKonstantin Belousov { 307*0f5116d7SKonstantin Belousov AMDIOMMU_LOCK(unit); 308*0f5116d7SKonstantin Belousov unit->hw_ctrl &= ~(AMDIOMMU_CTRL_EVNTLOG_EN | 309*0f5116d7SKonstantin Belousov AMDIOMMU_CTRL_EVENTINT_EN); 310*0f5116d7SKonstantin Belousov amdiommu_write8(unit, AMDIOMMU_CTRL, unit->hw_ctrl); 311*0f5116d7SKonstantin Belousov amdiommu_write8(unit, AMDIOMMU_EVNTLOG_BASE, 0); 312*0f5116d7SKonstantin Belousov AMDIOMMU_UNLOCK(unit); 313*0f5116d7SKonstantin Belousov 314*0f5116d7SKonstantin Belousov taskqueue_drain(unit->event_taskqueue, &unit->event_task); 315*0f5116d7SKonstantin Belousov taskqueue_free(unit->event_taskqueue); 316*0f5116d7SKonstantin Belousov unit->event_taskqueue = NULL; 317*0f5116d7SKonstantin Belousov 318*0f5116d7SKonstantin Belousov kmem_free(unit->event_log, unit->event_log_size * AMDIOMMU_EV_SZ); 319*0f5116d7SKonstantin Belousov unit->event_log = NULL; 320*0f5116d7SKonstantin Belousov unit->event_log_head = unit->event_log_tail = 0; 321*0f5116d7SKonstantin Belousov 322*0f5116d7SKonstantin Belousov mtx_destroy(&unit->event_lock); 323*0f5116d7SKonstantin Belousov } 324