MFC r203637:

Improve checking whether an ARM VA has a valid mapping before performing cache
sync.

VIPT/PIPT caches need valid VA-PA mapping in PTE for a cache operation to
succeed (unlike VIVT). Prior to this fix pmap was using l2pte_valid() for that
check, but this is not sufficient as the function merely checks if a PTE
exists (there can be existing but _invalid_ entries in the table).

A new pmap_has_valid_mapping() routine is introduced to do this job right by
checking proper PTE flags.

Among other potential problems this cures coherency issues with L2 caches on
MV-78100.

Submitted by:	Grzegorz Bernacki, Piotr Ziecik
Reviewed, tested by:	marcel
Obtained from:	Semihalf
This commit is contained in:
Rafal Jaworowski 2010-02-15 15:00:40 +00:00
parent 60d2ff2cd9
commit a911d19dfe
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/stable/8/; revision=203925

View File

@ -1199,79 +1199,38 @@ pmap_tlb_flushD(pmap_t pm)
cpu_tlb_flushD(); cpu_tlb_flushD();
} }
static PMAP_INLINE void static int
pmap_l2cache_wbinv_range(pmap_t pm, vm_offset_t va, vm_size_t len) pmap_has_valid_mapping(pmap_t pm, vm_offset_t va)
{ {
vm_size_t rest;
pd_entry_t *pde; pd_entry_t *pde;
pt_entry_t *ptep; pt_entry_t *ptep;
rest = MIN(PAGE_SIZE - (va & PAGE_MASK), len); if (pmap_get_pde_pte(pm, va, &pde, &ptep) &&
ptep && ((*ptep & L2_TYPE_MASK) != L2_TYPE_INV))
return (1);
while (len > 0) { return (0);
CTR4(KTR_PMAP, "pmap_l2cache_wbinv_range: pmap %p is_kernel %d "
"va 0x%08x len 0x%x ", pm, pm == pmap_kernel(), va, rest);
if (pmap_get_pde_pte(pm, va, &pde, &ptep) && l2pte_valid(*ptep))
cpu_l2cache_wbinv_range(va, rest);
len -= rest;
va += rest;
rest = MIN(PAGE_SIZE, len);
}
} }
static PMAP_INLINE void static PMAP_INLINE void
pmap_idcache_wbinv_range(pmap_t pm, vm_offset_t va, vm_size_t len) pmap_idcache_wbinv_range(pmap_t pm, vm_offset_t va, vm_size_t len)
{
if (pmap_is_current(pm)) {
cpu_idcache_wbinv_range(va, len);
pmap_l2cache_wbinv_range(pm, va, len);
}
}
static PMAP_INLINE void
pmap_l2cache_wb_range(pmap_t pm, vm_offset_t va, vm_size_t len)
{ {
vm_size_t rest; vm_size_t rest;
pd_entry_t *pde;
pt_entry_t *ptep;
rest = MIN(PAGE_SIZE - (va & PAGE_MASK), len); CTR4(KTR_PMAP, "pmap_dcache_wbinv_range: pmap %p is_kernel %d va 0x%08x"
" len 0x%x ", pm, pm == pmap_kernel(), va, len);
while (len > 0) { if (pmap_is_current(pm) || pm == pmap_kernel()) {
CTR4(KTR_PMAP, "pmap_l2cache_wb_range: pmap %p is_kernel %d " rest = MIN(PAGE_SIZE - (va & PAGE_MASK), len);
"va 0x%08x len 0x%x ", pm, pm == pmap_kernel(), va, rest); while (len > 0) {
if (pmap_get_pde_pte(pm, va, &pde, &ptep) && l2pte_valid(*ptep)) if (pmap_has_valid_mapping(pm, va)) {
cpu_l2cache_wb_range(va, rest); cpu_idcache_wbinv_range(va, rest);
cpu_l2cache_wbinv_range(va, rest);
len -= rest; }
va += rest; len -= rest;
va += rest;
rest = MIN(PAGE_SIZE, len); rest = MIN(PAGE_SIZE, len);
} }
}
static PMAP_INLINE void
pmap_l2cache_inv_range(pmap_t pm, vm_offset_t va, vm_size_t len)
{
vm_size_t rest;
pd_entry_t *pde;
pt_entry_t *ptep;
rest = MIN(PAGE_SIZE - (va & PAGE_MASK), len);
while (len > 0) {
CTR4(KTR_PMAP, "pmap_l2cache_wb_range: pmap %p is_kernel %d "
"va 0x%08x len 0x%x ", pm, pm == pmap_kernel(), va, rest);
if (pmap_get_pde_pte(pm, va, &pde, &ptep) && l2pte_valid(*ptep))
cpu_l2cache_inv_range(va, rest);
len -= rest;
va += rest;
rest = MIN(PAGE_SIZE, len);
} }
} }
@ -1279,24 +1238,31 @@ static PMAP_INLINE void
pmap_dcache_wb_range(pmap_t pm, vm_offset_t va, vm_size_t len, boolean_t do_inv, pmap_dcache_wb_range(pmap_t pm, vm_offset_t va, vm_size_t len, boolean_t do_inv,
boolean_t rd_only) boolean_t rd_only)
{ {
vm_size_t rest;
CTR4(KTR_PMAP, "pmap_dcache_wb_range: pmap %p is_kernel %d va 0x%08x " CTR4(KTR_PMAP, "pmap_dcache_wb_range: pmap %p is_kernel %d va 0x%08x "
"len 0x%x ", pm, pm == pmap_kernel(), va, len); "len 0x%x ", pm, pm == pmap_kernel(), va, len);
CTR2(KTR_PMAP, " do_inv %d rd_only %d", do_inv, rd_only); CTR2(KTR_PMAP, " do_inv %d rd_only %d", do_inv, rd_only);
if (pmap_is_current(pm)) { if (pmap_is_current(pm)) {
if (do_inv) { rest = MIN(PAGE_SIZE - (va & PAGE_MASK), len);
if (rd_only) { while (len > 0) {
cpu_dcache_inv_range(va, len); if (pmap_has_valid_mapping(pm, va)) {
pmap_l2cache_inv_range(pm, va, len); if (do_inv && rd_only) {
cpu_dcache_inv_range(va, rest);
cpu_l2cache_inv_range(va, rest);
} else if (do_inv) {
cpu_dcache_wbinv_range(va, rest);
cpu_l2cache_wbinv_range(va, rest);
} else if (!rd_only) {
cpu_dcache_wb_range(va, rest);
cpu_l2cache_wb_range(va, rest);
}
} }
else { len -= rest;
cpu_dcache_wbinv_range(va, len); va += rest;
pmap_l2cache_wbinv_range(pm, va, len);
} rest = MIN(PAGE_SIZE, len);
} else if (!rd_only) {
cpu_dcache_wb_range(va, len);
pmap_l2cache_wb_range(pm, va, len);
} }
} }
} }
@ -3225,7 +3191,8 @@ pmap_remove_all(vm_page_t m)
*/ */
if (pmap_is_current(pv->pv_pmap)) { if (pmap_is_current(pv->pv_pmap)) {
cpu_dcache_inv_range(pv->pv_va, PAGE_SIZE); cpu_dcache_inv_range(pv->pv_va, PAGE_SIZE);
cpu_l2cache_inv_range(pv->pv_va, PAGE_SIZE); if (pmap_has_valid_mapping(pv->pv_pmap, pv->pv_va))
cpu_l2cache_inv_range(pv->pv_va, PAGE_SIZE);
} }
if (pv->pv_flags & PVF_UNMAN) { if (pv->pv_flags & PVF_UNMAN) {
@ -3512,9 +3479,10 @@ pmap_enter_locked(pmap_t pmap, vm_offset_t va, vm_page_t m, vm_prot_t prot,
if (pmap_is_current(pmap) && if (pmap_is_current(pmap) &&
(oflags & PVF_NC) == 0 && (oflags & PVF_NC) == 0 &&
(opte & L2_S_PROT_W) != 0 && (opte & L2_S_PROT_W) != 0 &&
(prot & VM_PROT_WRITE) == 0) { (prot & VM_PROT_WRITE) == 0 &&
(opte & L2_TYPE_MASK) != L2_TYPE_INV) {
cpu_dcache_wb_range(va, PAGE_SIZE); cpu_dcache_wb_range(va, PAGE_SIZE);
pmap_l2cache_wb_range(pmap, va, PAGE_SIZE); cpu_l2cache_wb_range(va, PAGE_SIZE);
} }
} else { } else {
/* /*