diff options
author | jhibbits <jhibbits@FreeBSD.org> | 2013-08-06 01:01:15 +0000 |
---|---|---|
committer | jhibbits <jhibbits@FreeBSD.org> | 2013-08-06 01:01:15 +0000 |
commit | 271fe456c422e9d69c3d1c276aba7e8572c9124d (patch) | |
tree | ba6527ad564cba0edbe53d5ae4921e65f48a4f05 /sys/powerpc/aim | |
parent | c3a8e703896854a4f73b2602d7692169a0fbcc57 (diff) | |
download | FreeBSD-src-271fe456c422e9d69c3d1c276aba7e8572c9124d.zip FreeBSD-src-271fe456c422e9d69c3d1c276aba7e8572c9124d.tar.gz |
Evict pages from the PTEG when it's full and trying to insert a new PTE,
rather than panicking.
Reviewed by: nwhitehorn
MFC after: 3 weeks
Diffstat (limited to 'sys/powerpc/aim')
-rw-r--r-- | sys/powerpc/aim/mmu_oea.c | 84 |
1 files changed, 77 insertions, 7 deletions
diff --git a/sys/powerpc/aim/mmu_oea.c b/sys/powerpc/aim/mmu_oea.c index 17dcf66..5bb6d09 100644 --- a/sys/powerpc/aim/mmu_oea.c +++ b/sys/powerpc/aim/mmu_oea.c @@ -548,7 +548,7 @@ moea_pte_set(struct pte *pt, struct pte *pvo_pt) /* * Update the PTE as defined in section 7.6.3.1. - * Note that the REF/CHG bits are from pvo_pt and thus should havce + * Note that the REF/CHG bits are from pvo_pt and thus should have * been saved so this routine can restore them (if desired). */ pt->pte_lo = pvo_pt->pte_lo; @@ -2021,10 +2021,8 @@ moea_pvo_enter(pmap_t pm, uma_zone_t zone, struct pvo_head *pvo_head, pm->pm_stats.wired_count++; pm->pm_stats.resident_count++; - /* - * We hope this succeeds but it isn't required. - */ i = moea_pte_insert(ptegidx, &pvo->pvo_pte.pte); + KASSERT(i < 8, ("Invalid PTE index")); if (i >= 0) { PVO_PTEGIDX_SET(pvo, i); } else { @@ -2163,6 +2161,9 @@ moea_pvo_to_pte(const struct pvo_entry *pvo, int pteidx) "pvo but no valid pte", pvo); } + if (pvo->pvo_pte.pte.pte_hi != pt->pte_hi) { + panic("moea_pvo_to_pte: pvo does not match pte: pvo hi: %8x, pte hi: %8x", pvo->pvo_pte.pte.pte_hi, pt->pte_hi); + } if ((pt->pte_hi ^ (pvo->pvo_pte.pte.pte_hi & ~PTE_VALID)) == PTE_VALID) { if ((pvo->pvo_pte.pte.pte_hi & PTE_VALID) == 0) { panic("moea_pvo_to_pte: pvo %p has valid pte in " @@ -2181,7 +2182,7 @@ moea_pvo_to_pte(const struct pvo_entry *pvo, int pteidx) if (pvo->pvo_pte.pte.pte_hi & PTE_VALID) { panic("moea_pvo_to_pte: pvo %p has invalid pte %p in " - "moea_pteg_table but valid in pvo", pvo, pt); + "moea_pteg_table but valid in pvo: %8x, %8x", pvo, pt, pvo->pvo_pte.pte.pte_hi, pt->pte_hi); } mtx_unlock(&moea_table_mutex); @@ -2305,11 +2306,42 @@ moea_pte_spill(vm_offset_t addr) return (1); } +static __inline struct pvo_entry * +moea_pte_spillable_ident(u_int ptegidx) +{ + struct pte *pt; + struct pvo_entry *pvo_walk, *pvo = NULL; + + LIST_FOREACH(pvo_walk, &moea_pvo_table[ptegidx], pvo_olink) { + if (pvo_walk->pvo_vaddr & PVO_WIRED) + continue; + + if (!(pvo_walk->pvo_pte.pte.pte_hi & PTE_VALID)) + continue; + + pt = moea_pvo_to_pte(pvo_walk, -1); + + if (pt == NULL) + continue; + + pvo = pvo_walk; + + mtx_unlock(&moea_table_mutex); + if (!(pt->pte_lo & PTE_REF)) + return (pvo_walk); + } + + return (pvo); +} + static int moea_pte_insert(u_int ptegidx, struct pte *pvo_pt) { struct pte *pt; + struct pvo_entry *victim_pvo; int i; + int victim_idx; + u_int pteg_bkpidx = ptegidx; mtx_assert(&moea_table_mutex, MA_OWNED); @@ -2337,8 +2369,46 @@ moea_pte_insert(u_int ptegidx, struct pte *pvo_pt) } } - panic("moea_pte_insert: overflow"); - return (-1); + /* Try again, but this time try to force a PTE out. */ + ptegidx = pteg_bkpidx; + + victim_pvo = moea_pte_spillable_ident(ptegidx); + if (victim_pvo == NULL) { + ptegidx ^= moea_pteg_mask; + victim_pvo = moea_pte_spillable_ident(ptegidx); + } + + if (victim_pvo == NULL) { + panic("moea_pte_insert: overflow"); + return (-1); + } + + victim_idx = moea_pvo_pte_index(victim_pvo, ptegidx); + + if (pteg_bkpidx == ptegidx) + pvo_pt->pte_hi &= ~PTE_HID; + else + pvo_pt->pte_hi |= PTE_HID; + + /* + * Synchronize the sacrifice PTE with its PVO, then mark both + * invalid. The PVO will be reused when/if the VM system comes + * here after a fault. + */ + pt = &moea_pteg_table[victim_idx >> 3].pt[victim_idx & 7]; + + if (pt->pte_hi != victim_pvo->pvo_pte.pte.pte_hi) + panic("Victim PVO doesn't match PTE! PVO: %8x, PTE: %8x", victim_pvo->pvo_pte.pte.pte_hi, pt->pte_hi); + + /* + * Set the new PTE. + */ + moea_pte_unset(pt, &victim_pvo->pvo_pte.pte, victim_pvo->pvo_vaddr); + PVO_PTEGIDX_CLR(victim_pvo); + moea_pte_overflow++; + moea_pte_set(pt, pvo_pt); + + return (victim_idx & 7); } static boolean_t |