Changeset View
Changeset View
Standalone View
Standalone View
sys/x86/iommu/intel_utils.c
Show First 20 Lines • Show All 142 Lines • ▼ Show 20 Lines | |||||
/* | /* | ||||
* Find a best fit mgaw for the given maxaddr: | * Find a best fit mgaw for the given maxaddr: | ||||
* - if allow_less is false, must find sagaw which maps all requested | * - if allow_less is false, must find sagaw which maps all requested | ||||
* addresses (used by identity mappings); | * addresses (used by identity mappings); | ||||
* - if allow_less is true, and no supported sagaw can map all requested | * - if allow_less is true, and no supported sagaw can map all requested | ||||
* address space, accept the biggest sagaw, whatever is it. | * address space, accept the biggest sagaw, whatever is it. | ||||
*/ | */ | ||||
int | int | ||||
dmar_maxaddr2mgaw(struct dmar_unit *unit, dmar_gaddr_t maxaddr, bool allow_less) | dmar_maxaddr2mgaw(struct dmar_unit *unit, iommu_gaddr_t maxaddr, bool allow_less) | ||||
{ | { | ||||
int i; | int i; | ||||
for (i = 0; i < nitems(sagaw_bits); i++) { | for (i = 0; i < nitems(sagaw_bits); i++) { | ||||
if ((1ULL << sagaw_bits[i].agaw) >= maxaddr && | if ((1ULL << sagaw_bits[i].agaw) >= maxaddr && | ||||
(DMAR_CAP_SAGAW(unit->hw_cap) & sagaw_bits[i].cap) != 0) | (DMAR_CAP_SAGAW(unit->hw_cap) & sagaw_bits[i].cap) != 0) | ||||
break; | break; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 42 Lines • ▼ Show 20 Lines | static const int sagaw_sp[] = { | ||||
DMAR_CAP_SPS_1T | DMAR_CAP_SPS_1T | ||||
}; | }; | ||||
alvl = domain->pglvl - lvl - 1; | alvl = domain->pglvl - lvl - 1; | ||||
cap_sps = DMAR_CAP_SPS(domain->dmar->hw_cap); | cap_sps = DMAR_CAP_SPS(domain->dmar->hw_cap); | ||||
return (alvl < nitems(sagaw_sp) && (sagaw_sp[alvl] & cap_sps) != 0); | return (alvl < nitems(sagaw_sp) && (sagaw_sp[alvl] & cap_sps) != 0); | ||||
} | } | ||||
dmar_gaddr_t | iommu_gaddr_t | ||||
pglvl_page_size(int total_pglvl, int lvl) | pglvl_page_size(int total_pglvl, int lvl) | ||||
{ | { | ||||
int rlvl; | int rlvl; | ||||
static const dmar_gaddr_t pg_sz[] = { | static const iommu_gaddr_t pg_sz[] = { | ||||
(dmar_gaddr_t)DMAR_PAGE_SIZE, | (iommu_gaddr_t)DMAR_PAGE_SIZE, | ||||
(dmar_gaddr_t)DMAR_PAGE_SIZE << DMAR_NPTEPGSHIFT, | (iommu_gaddr_t)DMAR_PAGE_SIZE << DMAR_NPTEPGSHIFT, | ||||
(dmar_gaddr_t)DMAR_PAGE_SIZE << (2 * DMAR_NPTEPGSHIFT), | (iommu_gaddr_t)DMAR_PAGE_SIZE << (2 * DMAR_NPTEPGSHIFT), | ||||
(dmar_gaddr_t)DMAR_PAGE_SIZE << (3 * DMAR_NPTEPGSHIFT), | (iommu_gaddr_t)DMAR_PAGE_SIZE << (3 * DMAR_NPTEPGSHIFT), | ||||
(dmar_gaddr_t)DMAR_PAGE_SIZE << (4 * DMAR_NPTEPGSHIFT), | (iommu_gaddr_t)DMAR_PAGE_SIZE << (4 * DMAR_NPTEPGSHIFT), | ||||
(dmar_gaddr_t)DMAR_PAGE_SIZE << (5 * DMAR_NPTEPGSHIFT) | (iommu_gaddr_t)DMAR_PAGE_SIZE << (5 * DMAR_NPTEPGSHIFT) | ||||
}; | }; | ||||
KASSERT(lvl >= 0 && lvl < total_pglvl, | KASSERT(lvl >= 0 && lvl < total_pglvl, | ||||
("total %d lvl %d", total_pglvl, lvl)); | ("total %d lvl %d", total_pglvl, lvl)); | ||||
rlvl = total_pglvl - lvl - 1; | rlvl = total_pglvl - lvl - 1; | ||||
KASSERT(rlvl < nitems(pg_sz), ("sizeof pg_sz lvl %d", lvl)); | KASSERT(rlvl < nitems(pg_sz), ("sizeof pg_sz lvl %d", lvl)); | ||||
return (pg_sz[rlvl]); | return (pg_sz[rlvl]); | ||||
} | } | ||||
dmar_gaddr_t | iommu_gaddr_t | ||||
domain_page_size(struct dmar_domain *domain, int lvl) | domain_page_size(struct dmar_domain *domain, int lvl) | ||||
{ | { | ||||
return (pglvl_page_size(domain->pglvl, lvl)); | return (pglvl_page_size(domain->pglvl, lvl)); | ||||
} | } | ||||
int | int | ||||
calc_am(struct dmar_unit *unit, dmar_gaddr_t base, dmar_gaddr_t size, | calc_am(struct dmar_unit *unit, iommu_gaddr_t base, iommu_gaddr_t size, | ||||
dmar_gaddr_t *isizep) | iommu_gaddr_t *isizep) | ||||
{ | { | ||||
dmar_gaddr_t isize; | iommu_gaddr_t isize; | ||||
int am; | int am; | ||||
for (am = DMAR_CAP_MAMV(unit->hw_cap);; am--) { | for (am = DMAR_CAP_MAMV(unit->hw_cap);; am--) { | ||||
isize = 1ULL << (am + DMAR_PAGE_SHIFT); | isize = 1ULL << (am + DMAR_PAGE_SHIFT); | ||||
if ((base & (isize - 1)) == 0 && size >= isize) | if ((base & (isize - 1)) == 0 && size >= isize) | ||||
break; | break; | ||||
if (am == 0) | if (am == 0) | ||||
break; | break; | ||||
} | } | ||||
*isizep = isize; | *isizep = isize; | ||||
return (am); | return (am); | ||||
} | } | ||||
dmar_haddr_t dmar_high; | iommu_haddr_t dmar_high; | ||||
int haw; | int haw; | ||||
int dmar_tbl_pagecnt; | int dmar_tbl_pagecnt; | ||||
vm_page_t | vm_page_t | ||||
dmar_pgalloc(vm_object_t obj, vm_pindex_t idx, int flags) | dmar_pgalloc(vm_object_t obj, vm_pindex_t idx, int flags) | ||||
{ | { | ||||
vm_page_t m; | vm_page_t m; | ||||
int zeroed, aflags; | int zeroed, aflags; | ||||
▲ Show 20 Lines • Show All 213 Lines • ▼ Show 20 Lines | dmar_flush_write_bufs(struct dmar_unit *unit) | ||||
int error; | int error; | ||||
DMAR_ASSERT_LOCKED(unit); | DMAR_ASSERT_LOCKED(unit); | ||||
/* | /* | ||||
* DMAR_GCMD_WBF is only valid when CAP_RWBF is reported. | * DMAR_GCMD_WBF is only valid when CAP_RWBF is reported. | ||||
*/ | */ | ||||
KASSERT((unit->hw_cap & DMAR_CAP_RWBF) != 0, | KASSERT((unit->hw_cap & DMAR_CAP_RWBF) != 0, | ||||
("dmar%d: no RWBF", unit->unit)); | ("dmar%d: no RWBF", unit->iommu.unit)); | ||||
dmar_write4(unit, DMAR_GCMD_REG, unit->hw_gcmd | DMAR_GCMD_WBF); | dmar_write4(unit, DMAR_GCMD_REG, unit->hw_gcmd | DMAR_GCMD_WBF); | ||||
DMAR_WAIT_UNTIL(((dmar_read4(unit, DMAR_GSTS_REG) & DMAR_GSTS_WBFS) | DMAR_WAIT_UNTIL(((dmar_read4(unit, DMAR_GSTS_REG) & DMAR_GSTS_WBFS) | ||||
!= 0)); | != 0)); | ||||
return (error); | return (error); | ||||
} | } | ||||
int | int | ||||
▲ Show 20 Lines • Show All 87 Lines • ▼ Show 20 Lines | dmar_barrier_enter(struct dmar_unit *dmar, u_int barrier_id) | ||||
if ((dmar->barrier_flags & f_done) != 0) { | if ((dmar->barrier_flags & f_done) != 0) { | ||||
DMAR_UNLOCK(dmar); | DMAR_UNLOCK(dmar); | ||||
return (false); | return (false); | ||||
} | } | ||||
if ((dmar->barrier_flags & f_inproc) != 0) { | if ((dmar->barrier_flags & f_inproc) != 0) { | ||||
while ((dmar->barrier_flags & f_inproc) != 0) { | while ((dmar->barrier_flags & f_inproc) != 0) { | ||||
dmar->barrier_flags |= f_wakeup; | dmar->barrier_flags |= f_wakeup; | ||||
msleep(&dmar->barrier_flags, &dmar->lock, 0, | msleep(&dmar->barrier_flags, &dmar->iommu.lock, 0, | ||||
"dmarb", 0); | "dmarb", 0); | ||||
} | } | ||||
KASSERT((dmar->barrier_flags & f_done) != 0, | KASSERT((dmar->barrier_flags & f_done) != 0, | ||||
("dmar%d barrier %d missing done", dmar->unit, barrier_id)); | ("dmar%d barrier %d missing done", dmar->iommu.unit, | ||||
barrier_id)); | |||||
DMAR_UNLOCK(dmar); | DMAR_UNLOCK(dmar); | ||||
return (false); | return (false); | ||||
} | } | ||||
dmar->barrier_flags |= f_inproc; | dmar->barrier_flags |= f_inproc; | ||||
DMAR_UNLOCK(dmar); | DMAR_UNLOCK(dmar); | ||||
return (true); | return (true); | ||||
} | } | ||||
void | void | ||||
dmar_barrier_exit(struct dmar_unit *dmar, u_int barrier_id) | dmar_barrier_exit(struct dmar_unit *dmar, u_int barrier_id) | ||||
{ | { | ||||
BARRIER_F; | BARRIER_F; | ||||
DMAR_ASSERT_LOCKED(dmar); | DMAR_ASSERT_LOCKED(dmar); | ||||
KASSERT((dmar->barrier_flags & (f_done | f_inproc)) == f_inproc, | KASSERT((dmar->barrier_flags & (f_done | f_inproc)) == f_inproc, | ||||
("dmar%d barrier %d missed entry", dmar->unit, barrier_id)); | ("dmar%d barrier %d missed entry", dmar->iommu.unit, barrier_id)); | ||||
dmar->barrier_flags |= f_done; | dmar->barrier_flags |= f_done; | ||||
if ((dmar->barrier_flags & f_wakeup) != 0) | if ((dmar->barrier_flags & f_wakeup) != 0) | ||||
wakeup(&dmar->barrier_flags); | wakeup(&dmar->barrier_flags); | ||||
dmar->barrier_flags &= ~(f_inproc | f_wakeup); | dmar->barrier_flags &= ~(f_inproc | f_wakeup); | ||||
DMAR_UNLOCK(dmar); | DMAR_UNLOCK(dmar); | ||||
} | } | ||||
int dmar_batch_coalesce = 100; | int dmar_batch_coalesce = 100; | ||||
▲ Show 20 Lines • Show All 57 Lines • Show Last 20 Lines |