Changeset View
Changeset View
Standalone View
Standalone View
sys/x86/iommu/intel_utils.c
Show First 20 Lines • Show All 100 Lines • ▼ Show 20 Lines | int pglvl; | ||||
.pglvl = 4}, | .pglvl = 4}, | ||||
{.agaw = 57, .cap = DMAR_CAP_SAGAW_5LVL, .awlvl = DMAR_CTX2_AW_5LVL, | {.agaw = 57, .cap = DMAR_CAP_SAGAW_5LVL, .awlvl = DMAR_CTX2_AW_5LVL, | ||||
.pglvl = 5}, | .pglvl = 5}, | ||||
{.agaw = 64, .cap = DMAR_CAP_SAGAW_6LVL, .awlvl = DMAR_CTX2_AW_6LVL, | {.agaw = 64, .cap = DMAR_CAP_SAGAW_6LVL, .awlvl = DMAR_CTX2_AW_6LVL, | ||||
.pglvl = 6} | .pglvl = 6} | ||||
}; | }; | ||||
bool | bool | ||||
dmar_pglvl_supported(struct dmar_unit *unit, int pglvl) | dmar_pglvl_supported(struct iommu_unit *unit, int pglvl) | ||||
{ | { | ||||
struct dmar_unit *dmar; | |||||
int i; | int i; | ||||
dmar = (struct dmar_unit *)unit; | |||||
for (i = 0; i < nitems(sagaw_bits); i++) { | for (i = 0; i < nitems(sagaw_bits); i++) { | ||||
if (sagaw_bits[i].pglvl != pglvl) | if (sagaw_bits[i].pglvl != pglvl) | ||||
continue; | continue; | ||||
if ((DMAR_CAP_SAGAW(unit->hw_cap) & sagaw_bits[i].cap) != 0) | if ((DMAR_CAP_SAGAW(dmar->hw_cap) & sagaw_bits[i].cap) != 0) | ||||
return (true); | return (true); | ||||
} | } | ||||
return (false); | return (false); | ||||
} | } | ||||
int | int | ||||
domain_set_agaw(struct dmar_domain *domain, int mgaw) | domain_set_agaw(struct dmar_domain *domain, int mgaw) | ||||
{ | { | ||||
struct dmar_unit *dmar; | |||||
int sagaw, i; | int sagaw, i; | ||||
dmar = (struct dmar_unit *)domain->iodom.iommu; | |||||
domain->mgaw = mgaw; | domain->mgaw = mgaw; | ||||
sagaw = DMAR_CAP_SAGAW(domain->dmar->hw_cap); | sagaw = DMAR_CAP_SAGAW(dmar->hw_cap); | ||||
for (i = 0; i < nitems(sagaw_bits); i++) { | for (i = 0; i < nitems(sagaw_bits); i++) { | ||||
if (sagaw_bits[i].agaw >= mgaw) { | if (sagaw_bits[i].agaw >= mgaw) { | ||||
domain->agaw = sagaw_bits[i].agaw; | domain->agaw = sagaw_bits[i].agaw; | ||||
domain->pglvl = sagaw_bits[i].pglvl; | domain->pglvl = sagaw_bits[i].pglvl; | ||||
domain->awlvl = sagaw_bits[i].awlvl; | domain->awlvl = sagaw_bits[i].awlvl; | ||||
return (0); | return (0); | ||||
} | } | ||||
} | } | ||||
device_printf(domain->dmar->dev, | device_printf(dmar->dev, | ||||
"context request mgaw %d: no agaw found, sagaw %x\n", | "context request mgaw %d: no agaw found, sagaw %x\n", | ||||
mgaw, sagaw); | mgaw, sagaw); | ||||
return (EINVAL); | return (EINVAL); | ||||
} | } | ||||
/* | /* | ||||
* 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 | ||||
▲ Show 20 Lines • Show All 43 Lines • ▼ Show 20 Lines | |||||
/* | /* | ||||
* Return true if the page table level lvl supports the superpage for | * Return true if the page table level lvl supports the superpage for | ||||
* the context ctx. | * the context ctx. | ||||
*/ | */ | ||||
int | int | ||||
domain_is_sp_lvl(struct dmar_domain *domain, int lvl) | domain_is_sp_lvl(struct dmar_domain *domain, int lvl) | ||||
{ | { | ||||
struct dmar_unit *dmar; | |||||
int alvl, cap_sps; | int alvl, cap_sps; | ||||
static const int sagaw_sp[] = { | static const int sagaw_sp[] = { | ||||
DMAR_CAP_SPS_2M, | DMAR_CAP_SPS_2M, | ||||
DMAR_CAP_SPS_1G, | DMAR_CAP_SPS_1G, | ||||
DMAR_CAP_SPS_512G, | DMAR_CAP_SPS_512G, | ||||
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); | dmar = (struct dmar_unit *)domain->iodom.iommu; | ||||
cap_sps = DMAR_CAP_SPS(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 | dmar_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 dmar_gaddr_t pg_sz[] = { | ||||
▲ Show 20 Lines • Show All 262 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 |