Changeset View
Changeset View
Standalone View
Standalone View
sys/x86/iommu/intel_fault.c
Show First 20 Lines • Show All 90 Lines • ▼ Show 20 Lines | |||||
static void | static void | ||||
dmar_fault_intr_clear(struct dmar_unit *unit, uint32_t fsts) | dmar_fault_intr_clear(struct dmar_unit *unit, uint32_t fsts) | ||||
{ | { | ||||
uint32_t clear; | uint32_t clear; | ||||
clear = 0; | clear = 0; | ||||
if ((fsts & DMAR_FSTS_ITE) != 0) { | if ((fsts & DMAR_FSTS_ITE) != 0) { | ||||
printf("DMAR%d: Invalidation timed out\n", unit->unit); | printf("DMAR%d: Invalidation timed out\n", unit->iommu.unit); | ||||
clear |= DMAR_FSTS_ITE; | clear |= DMAR_FSTS_ITE; | ||||
} | } | ||||
if ((fsts & DMAR_FSTS_ICE) != 0) { | if ((fsts & DMAR_FSTS_ICE) != 0) { | ||||
printf("DMAR%d: Invalidation completion error\n", | printf("DMAR%d: Invalidation completion error\n", | ||||
unit->unit); | unit->iommu.unit); | ||||
clear |= DMAR_FSTS_ICE; | clear |= DMAR_FSTS_ICE; | ||||
} | } | ||||
if ((fsts & DMAR_FSTS_IQE) != 0) { | if ((fsts & DMAR_FSTS_IQE) != 0) { | ||||
printf("DMAR%d: Invalidation queue error\n", | printf("DMAR%d: Invalidation queue error\n", | ||||
unit->unit); | unit->iommu.unit); | ||||
clear |= DMAR_FSTS_IQE; | clear |= DMAR_FSTS_IQE; | ||||
} | } | ||||
if ((fsts & DMAR_FSTS_APF) != 0) { | if ((fsts & DMAR_FSTS_APF) != 0) { | ||||
printf("DMAR%d: Advanced pending fault\n", unit->unit); | printf("DMAR%d: Advanced pending fault\n", unit->iommu.unit); | ||||
clear |= DMAR_FSTS_APF; | clear |= DMAR_FSTS_APF; | ||||
} | } | ||||
if ((fsts & DMAR_FSTS_AFO) != 0) { | if ((fsts & DMAR_FSTS_AFO) != 0) { | ||||
printf("DMAR%d: Advanced fault overflow\n", unit->unit); | printf("DMAR%d: Advanced fault overflow\n", unit->iommu.unit); | ||||
clear |= DMAR_FSTS_AFO; | clear |= DMAR_FSTS_AFO; | ||||
} | } | ||||
if (clear != 0) | if (clear != 0) | ||||
dmar_write4(unit, DMAR_FSTS_REG, clear); | dmar_write4(unit, DMAR_FSTS_REG, clear); | ||||
} | } | ||||
int | int | ||||
dmar_fault_intr(void *arg) | dmar_fault_intr(void *arg) | ||||
▲ Show 20 Lines • Show All 45 Lines • ▼ Show 20 Lines | done: | ||||
* reported. | * reported. | ||||
* | * | ||||
* On IvyBridge, errata BV30 states that clearing clear | * On IvyBridge, errata BV30 states that clearing clear | ||||
* DMAR_FRCD2_F bit in the fault register causes spurious | * DMAR_FRCD2_F bit in the fault register causes spurious | ||||
* interrupt. Do nothing. | * interrupt. Do nothing. | ||||
* | * | ||||
*/ | */ | ||||
if ((fsts & DMAR_FSTS_PFO) != 0) { | if ((fsts & DMAR_FSTS_PFO) != 0) { | ||||
printf("DMAR%d: Fault Overflow\n", unit->unit); | printf("DMAR%d: Fault Overflow\n", unit->iommu.unit); | ||||
dmar_write4(unit, DMAR_FSTS_REG, DMAR_FSTS_PFO); | dmar_write4(unit, DMAR_FSTS_REG, DMAR_FSTS_PFO); | ||||
} | } | ||||
if (enqueue) { | if (enqueue) { | ||||
taskqueue_enqueue(unit->fault_taskqueue, | taskqueue_enqueue(unit->fault_taskqueue, | ||||
&unit->fault_task); | &unit->fault_task); | ||||
} | } | ||||
return (FILTER_HANDLED); | return (FILTER_HANDLED); | ||||
Show All 15 Lines | if (faultp == unit->fault_log_head) | ||||
break; | break; | ||||
fault_rec[0] = unit->fault_log[faultp]; | fault_rec[0] = unit->fault_log[faultp]; | ||||
fault_rec[1] = unit->fault_log[faultp + 1]; | fault_rec[1] = unit->fault_log[faultp + 1]; | ||||
unit->fault_log_tail = dmar_fault_next(unit, faultp); | unit->fault_log_tail = dmar_fault_next(unit, faultp); | ||||
DMAR_FAULT_UNLOCK(unit); | DMAR_FAULT_UNLOCK(unit); | ||||
sid = DMAR_FRCD2_SID(fault_rec[1]); | sid = DMAR_FRCD2_SID(fault_rec[1]); | ||||
printf("DMAR%d: ", unit->unit); | printf("DMAR%d: ", unit->iommu.unit); | ||||
DMAR_LOCK(unit); | DMAR_LOCK(unit); | ||||
ctx = dmar_find_ctx_locked(unit, sid); | ctx = dmar_find_ctx_locked(unit, sid); | ||||
if (ctx == NULL) { | if (ctx == NULL) { | ||||
printf("<unknown dev>:"); | printf("<unknown dev>:"); | ||||
/* | /* | ||||
* Note that the slot and function will not be correct | * Note that the slot and function will not be correct | ||||
* if ARI is in use, but without a ctx entry we have | * if ARI is in use, but without a ctx entry we have | ||||
* no way of knowing whether ARI is in use or not. | * no way of knowing whether ARI is in use or not. | ||||
*/ | */ | ||||
bus = PCI_RID2BUS(sid); | bus = PCI_RID2BUS(sid); | ||||
slot = PCI_RID2SLOT(sid); | slot = PCI_RID2SLOT(sid); | ||||
func = PCI_RID2FUNC(sid); | func = PCI_RID2FUNC(sid); | ||||
} else { | } else { | ||||
ctx->flags |= DMAR_CTX_FAULTED; | ctx->device.flags |= DMAR_CTX_FAULTED; | ||||
ctx->last_fault_rec[0] = fault_rec[0]; | ctx->last_fault_rec[0] = fault_rec[0]; | ||||
ctx->last_fault_rec[1] = fault_rec[1]; | ctx->last_fault_rec[1] = fault_rec[1]; | ||||
device_print_prettyname(ctx->ctx_tag.owner); | device_print_prettyname(ctx->device.tag.owner); | ||||
bus = pci_get_bus(ctx->ctx_tag.owner); | bus = pci_get_bus(ctx->device.tag.owner); | ||||
slot = pci_get_slot(ctx->ctx_tag.owner); | slot = pci_get_slot(ctx->device.tag.owner); | ||||
func = pci_get_function(ctx->ctx_tag.owner); | func = pci_get_function(ctx->device.tag.owner); | ||||
} | } | ||||
DMAR_UNLOCK(unit); | DMAR_UNLOCK(unit); | ||||
printf( | printf( | ||||
"pci%d:%d:%d sid %x fault acc %x adt 0x%x reason 0x%x " | "pci%d:%d:%d sid %x fault acc %x adt 0x%x reason 0x%x " | ||||
"addr %jx\n", | "addr %jx\n", | ||||
bus, slot, func, sid, DMAR_FRCD2_T(fault_rec[1]), | bus, slot, func, sid, DMAR_FRCD2_T(fault_rec[1]), | ||||
DMAR_FRCD2_AT(fault_rec[1]), DMAR_FRCD2_FR(fault_rec[1]), | DMAR_FRCD2_AT(fault_rec[1]), DMAR_FRCD2_FR(fault_rec[1]), | ||||
(uintmax_t)fault_rec[0]); | (uintmax_t)fault_rec[0]); | ||||
Show All 30 Lines | if (unit->fault_log_size % 2 != 0) | ||||
panic("hw.dmar_fault_log_size must be even"); | panic("hw.dmar_fault_log_size must be even"); | ||||
unit->fault_log = malloc(sizeof(uint64_t) * unit->fault_log_size, | unit->fault_log = malloc(sizeof(uint64_t) * unit->fault_log_size, | ||||
M_DEVBUF, M_WAITOK | M_ZERO); | M_DEVBUF, M_WAITOK | M_ZERO); | ||||
TASK_INIT(&unit->fault_task, 0, dmar_fault_task, unit); | TASK_INIT(&unit->fault_task, 0, dmar_fault_task, unit); | ||||
unit->fault_taskqueue = taskqueue_create_fast("dmarff", M_WAITOK, | unit->fault_taskqueue = taskqueue_create_fast("dmarff", M_WAITOK, | ||||
taskqueue_thread_enqueue, &unit->fault_taskqueue); | taskqueue_thread_enqueue, &unit->fault_taskqueue); | ||||
taskqueue_start_threads(&unit->fault_taskqueue, 1, PI_AV, | taskqueue_start_threads(&unit->fault_taskqueue, 1, PI_AV, | ||||
"dmar%d fault taskq", unit->unit); | "dmar%d fault taskq", unit->iommu.unit); | ||||
DMAR_LOCK(unit); | DMAR_LOCK(unit); | ||||
dmar_disable_fault_intr(unit); | dmar_disable_fault_intr(unit); | ||||
dmar_clear_faults(unit); | dmar_clear_faults(unit); | ||||
dmar_enable_fault_intr(unit); | dmar_enable_fault_intr(unit); | ||||
DMAR_UNLOCK(unit); | DMAR_UNLOCK(unit); | ||||
return (0); | return (0); | ||||
▲ Show 20 Lines • Show All 43 Lines • Show Last 20 Lines |