Changeset View
Changeset View
Standalone View
Standalone View
sys/x86/iommu/intel_qi.c
Show All 35 Lines | |||||
#include <sys/bus.h> | #include <sys/bus.h> | ||||
#include <sys/kernel.h> | #include <sys/kernel.h> | ||||
#include <sys/malloc.h> | #include <sys/malloc.h> | ||||
#include <sys/memdesc.h> | #include <sys/memdesc.h> | ||||
#include <sys/module.h> | #include <sys/module.h> | ||||
#include <sys/rman.h> | #include <sys/rman.h> | ||||
#include <sys/taskqueue.h> | #include <sys/taskqueue.h> | ||||
#include <sys/tree.h> | #include <sys/tree.h> | ||||
#include <sys/vmem.h> | |||||
#include <machine/bus.h> | #include <machine/bus.h> | ||||
#include <contrib/dev/acpica/include/acpi.h> | #include <contrib/dev/acpica/include/acpi.h> | ||||
#include <contrib/dev/acpica/include/accommon.h> | #include <contrib/dev/acpica/include/accommon.h> | ||||
#include <dev/acpica/acpivar.h> | #include <dev/acpica/acpivar.h> | ||||
#include <vm/vm.h> | #include <vm/vm.h> | ||||
#include <vm/vm_extern.h> | #include <vm/vm_extern.h> | ||||
#include <vm/vm_kern.h> | #include <vm/vm_kern.h> | ||||
#include <vm/vm_page.h> | #include <vm/vm_page.h> | ||||
▲ Show 20 Lines • Show All 137 Lines • ▼ Show 20 Lines | dmar_qi_emit_wait_seq(struct dmar_unit *unit, struct dmar_qi_genseq *pseq) | ||||
} | } | ||||
seq = unit->inv_waitd_seq++; | seq = unit->inv_waitd_seq++; | ||||
pseq->gen = unit->inv_waitd_gen; | pseq->gen = unit->inv_waitd_gen; | ||||
pseq->seq = seq; | pseq->seq = seq; | ||||
dmar_qi_emit_wait_descr(unit, seq, true, true, false); | dmar_qi_emit_wait_descr(unit, seq, true, true, false); | ||||
} | } | ||||
static void | static void | ||||
dmar_qi_wait_for_seq(struct dmar_unit *unit, const struct dmar_qi_genseq *gseq) | dmar_qi_wait_for_seq(struct dmar_unit *unit, const struct dmar_qi_genseq *gseq, | ||||
bool nowait) | |||||
{ | { | ||||
DMAR_ASSERT_LOCKED(unit); | DMAR_ASSERT_LOCKED(unit); | ||||
unit->inv_seq_waiters++; | unit->inv_seq_waiters++; | ||||
while (!dmar_qi_seq_processed(unit, gseq)) { | while (!dmar_qi_seq_processed(unit, gseq)) { | ||||
if (cold) { | if (cold || nowait) { | ||||
cpu_spinwait(); | cpu_spinwait(); | ||||
} else { | } else { | ||||
msleep(&unit->inv_seq_waiters, &unit->lock, 0, | msleep(&unit->inv_seq_waiters, &unit->lock, 0, | ||||
"dmarse", hz); | "dmarse", hz); | ||||
} | } | ||||
} | } | ||||
unit->inv_seq_waiters--; | unit->inv_seq_waiters--; | ||||
} | } | ||||
Show All 29 Lines | |||||
{ | { | ||||
struct dmar_qi_genseq gseq; | struct dmar_qi_genseq gseq; | ||||
DMAR_ASSERT_LOCKED(unit); | DMAR_ASSERT_LOCKED(unit); | ||||
dmar_qi_ensure(unit, 2); | dmar_qi_ensure(unit, 2); | ||||
dmar_qi_emit(unit, DMAR_IQ_DESCR_CTX_INV | DMAR_IQ_DESCR_CTX_GLOB, 0); | dmar_qi_emit(unit, DMAR_IQ_DESCR_CTX_INV | DMAR_IQ_DESCR_CTX_GLOB, 0); | ||||
dmar_qi_emit_wait_seq(unit, &gseq); | dmar_qi_emit_wait_seq(unit, &gseq); | ||||
dmar_qi_advance_tail(unit); | dmar_qi_advance_tail(unit); | ||||
dmar_qi_wait_for_seq(unit, &gseq); | dmar_qi_wait_for_seq(unit, &gseq, false); | ||||
} | } | ||||
void | void | ||||
dmar_qi_invalidate_iotlb_glob_locked(struct dmar_unit *unit) | dmar_qi_invalidate_iotlb_glob_locked(struct dmar_unit *unit) | ||||
{ | { | ||||
struct dmar_qi_genseq gseq; | struct dmar_qi_genseq gseq; | ||||
DMAR_ASSERT_LOCKED(unit); | DMAR_ASSERT_LOCKED(unit); | ||||
dmar_qi_ensure(unit, 2); | dmar_qi_ensure(unit, 2); | ||||
dmar_qi_emit(unit, DMAR_IQ_DESCR_IOTLB_INV | DMAR_IQ_DESCR_IOTLB_GLOB | | dmar_qi_emit(unit, DMAR_IQ_DESCR_IOTLB_INV | DMAR_IQ_DESCR_IOTLB_GLOB | | ||||
DMAR_IQ_DESCR_IOTLB_DW | DMAR_IQ_DESCR_IOTLB_DR, 0); | DMAR_IQ_DESCR_IOTLB_DW | DMAR_IQ_DESCR_IOTLB_DR, 0); | ||||
dmar_qi_emit_wait_seq(unit, &gseq); | dmar_qi_emit_wait_seq(unit, &gseq); | ||||
dmar_qi_advance_tail(unit); | dmar_qi_advance_tail(unit); | ||||
dmar_qi_wait_for_seq(unit, &gseq); | dmar_qi_wait_for_seq(unit, &gseq, false); | ||||
} | } | ||||
void | |||||
dmar_qi_invalidate_iec_glob(struct dmar_unit *unit) | |||||
{ | |||||
struct dmar_qi_genseq gseq; | |||||
DMAR_ASSERT_LOCKED(unit); | |||||
dmar_qi_ensure(unit, 2); | |||||
dmar_qi_emit(unit, DMAR_IQ_DESCR_IEC_INV, 0); | |||||
dmar_qi_emit_wait_seq(unit, &gseq); | |||||
dmar_qi_advance_tail(unit); | |||||
dmar_qi_wait_for_seq(unit, &gseq, false); | |||||
} | |||||
void | |||||
dmar_qi_invalidate_iec(struct dmar_unit *unit, u_int start, u_int cnt) | |||||
{ | |||||
struct dmar_qi_genseq gseq; | |||||
u_int c, l; | |||||
DMAR_ASSERT_LOCKED(unit); | |||||
KASSERT(start < unit->irte_cnt && start < start + cnt && | |||||
start + cnt < unit->irte_cnt, | |||||
neel: start + cnt <= unit->irte_cnt | |||||
("inv iec overflow %d %d %d", unit->irte_cnt, start, cnt)); | |||||
for (; cnt > 0; cnt -= c, start += c) { | |||||
l = ffs(start | cnt) - 1; | |||||
c = 1 << l; | |||||
dmar_qi_ensure(unit, 1); | |||||
dmar_qi_emit(unit, DMAR_IQ_DESCR_IEC_INV | | |||||
DMAR_IQ_DESCR_IEC_IDX | DMAR_IQ_DESCR_IEC_IIDX(start) | | |||||
DMAR_IQ_DESCR_IEC_IM(l), 0); | |||||
} | |||||
dmar_qi_ensure(unit, 1); | |||||
dmar_qi_emit_wait_seq(unit, &gseq); | |||||
dmar_qi_advance_tail(unit); | |||||
/* | |||||
* The caller of the function, in particular, | |||||
* dmar_ir_program_irte(), may be called from the context | |||||
* where the sleeping is forbidden (in fact, the | |||||
* intr_table_lock mutex may be held, locked from | |||||
* intr_shuffle_irqs()). Wait for the invalidation completion | |||||
* using the busy wait. | |||||
* | |||||
* The impact on the interrupt input setup code is small, the | |||||
* expected overhead is comparable with the chipset register | |||||
* read. It is more harmful for the parallel DMA operations, | |||||
* since we own the dmar unit lock until whole invalidation | |||||
* queue is processed, which includes requests possibly issued | |||||
* before our request. | |||||
*/ | |||||
dmar_qi_wait_for_seq(unit, &gseq, true); | |||||
} | |||||
int | int | ||||
dmar_qi_intr(void *arg) | dmar_qi_intr(void *arg) | ||||
{ | { | ||||
struct dmar_unit *unit; | struct dmar_unit *unit; | ||||
unit = arg; | unit = arg; | ||||
KASSERT(unit->qi_enabled, ("dmar%d: QI is not enabled", unit->unit)); | KASSERT(unit->qi_enabled, ("dmar%d: QI is not enabled", unit->unit)); | ||||
taskqueue_enqueue_fast(unit->qi_taskqueue, &unit->qi_task); | taskqueue_enqueue_fast(unit->qi_taskqueue, &unit->qi_task); | ||||
▲ Show 20 Lines • Show All 98 Lines • ▼ Show 20 Lines | dmar_fini_qi(struct dmar_unit *unit) | ||||
taskqueue_free(unit->qi_taskqueue); | taskqueue_free(unit->qi_taskqueue); | ||||
unit->qi_taskqueue = NULL; | unit->qi_taskqueue = NULL; | ||||
DMAR_LOCK(unit); | DMAR_LOCK(unit); | ||||
/* quisce */ | /* quisce */ | ||||
dmar_qi_ensure(unit, 1); | dmar_qi_ensure(unit, 1); | ||||
dmar_qi_emit_wait_seq(unit, &gseq); | dmar_qi_emit_wait_seq(unit, &gseq); | ||||
dmar_qi_advance_tail(unit); | dmar_qi_advance_tail(unit); | ||||
dmar_qi_wait_for_seq(unit, &gseq); | dmar_qi_wait_for_seq(unit, &gseq, false); | ||||
/* only after the quisce, disable queue */ | /* only after the quisce, disable queue */ | ||||
dmar_disable_qi(unit); | dmar_disable_qi(unit); | ||||
KASSERT(unit->inv_seq_waiters == 0, | KASSERT(unit->inv_seq_waiters == 0, | ||||
("dmar%d: waiters on disabled queue", unit->unit)); | ("dmar%d: waiters on disabled queue", unit->unit)); | ||||
DMAR_UNLOCK(unit); | DMAR_UNLOCK(unit); | ||||
kmem_free(kernel_arena, unit->inv_queue, unit->inv_queue_size); | kmem_free(kernel_arena, unit->inv_queue, unit->inv_queue_size); | ||||
unit->inv_queue = 0; | unit->inv_queue = 0; | ||||
Show All 26 Lines |
start + cnt <= unit->irte_cnt