summaryrefslogtreecommitdiffstats
path: root/sys/powerpc/aim
diff options
context:
space:
mode:
authornwhitehorn <nwhitehorn@FreeBSD.org>2012-04-28 00:12:23 +0000
committernwhitehorn <nwhitehorn@FreeBSD.org>2012-04-28 00:12:23 +0000
commitd4577289f5bcc75fd682e6b0410353b3cde2e447 (patch)
tree3102db284eeaec1b26f9d14e15593c1e106f24e2 /sys/powerpc/aim
parentefc4ec38135cb9d6f07e84cf00a8423288397c4a (diff)
downloadFreeBSD-src-d4577289f5bcc75fd682e6b0410353b3cde2e447.zip
FreeBSD-src-d4577289f5bcc75fd682e6b0410353b3cde2e447.tar.gz
After switching mutexes to use lwsync, they no longer provide sufficient
guarantees on acquire for the tlbie mutex. Conversely, the TLB invalidation sequence provides guarantees that do not need to be redundantly applied on release. Roll a small custom lock that is just right. Simultaneously, convert the SLB tree changes back to lwsync, as changing them to sync was a misdiagnosis of the tlbie barrier problem this commit actually fixes.
Diffstat (limited to 'sys/powerpc/aim')
-rw-r--r--sys/powerpc/aim/moea64_native.c45
-rw-r--r--sys/powerpc/aim/slb.c4
2 files changed, 19 insertions, 30 deletions
diff --git a/sys/powerpc/aim/moea64_native.c b/sys/powerpc/aim/moea64_native.c
index 93187ca..41e8593 100644
--- a/sys/powerpc/aim/moea64_native.c
+++ b/sys/powerpc/aim/moea64_native.c
@@ -133,36 +133,31 @@ __FBSDID("$FreeBSD$");
#define VSID_HASH_MASK 0x0000007fffffffffULL
-/*
- * The tlbie instruction must be executed in 64-bit mode
- * so we have to twiddle MSR[SF] around every invocation.
- * Just to add to the fun, exceptions must be off as well
- * so that we can't trap in 64-bit mode. What a pain.
- */
-static struct mtx tlbie_mutex;
-
static __inline void
TLBIE(uint64_t vpn) {
#ifndef __powerpc64__
register_t vpn_hi, vpn_lo;
register_t msr;
- register_t scratch;
+ register_t scratch, intr;
#endif
+ static volatile u_int tlbie_lock = 0;
+
vpn <<= ADDR_PIDX_SHFT;
vpn &= ~(0xffffULL << 48);
+ /* Hobo spinlock: we need stronger guarantees than mutexes provide */
+ while (!atomic_cmpset_int(&tlbie_lock, 0, 1));
+ isync(); /* Flush instruction queue once lock acquired */
+
#ifdef __powerpc64__
- mtx_lock(&tlbie_mutex);
__asm __volatile("tlbie %0" :: "r"(vpn) : "memory");
- mtx_unlock(&tlbie_mutex);
- __asm __volatile("eieio; tlbsync; ptesync");
+ __asm __volatile("eieio; tlbsync; ptesync" ::: "memory");
#else
vpn_hi = (uint32_t)(vpn >> 32);
vpn_lo = (uint32_t)vpn;
- /* Note: spin mutex is to disable exceptions while fiddling MSR */
- mtx_lock_spin(&tlbie_mutex);
+ intr = intr_disable();
__asm __volatile("\
mfmsr %0; \
mr %1, %0; \
@@ -179,8 +174,11 @@ TLBIE(uint64_t vpn) {
ptesync;"
: "=r"(msr), "=r"(scratch) : "r"(vpn_hi), "r"(vpn_lo), "r"(32), "r"(1)
: "memory");
- mtx_unlock_spin(&tlbie_mutex);
+ intr_enable();
#endif
+
+ /* No barriers or special ops -- taken care of by ptesync above */
+ tlbie_lock = 0;
}
#define DISABLE_TRANS(msr) msr = mfmsr(); mtmsr(msr & ~PSL_DR)
@@ -261,9 +259,9 @@ moea64_pte_clear_native(mmu_t mmu, uintptr_t pt_cookie, struct lpte *pvo_pt,
* As shown in Section 7.6.3.2.3
*/
pt->pte_lo &= ~ptebit;
- sched_pin();
+ critical_enter();
TLBIE(vpn);
- sched_unpin();
+ critical_exit();
}
static void
@@ -297,12 +295,12 @@ moea64_pte_unset_native(mmu_t mmu, uintptr_t pt_cookie, struct lpte *pvo_pt,
* Invalidate the pte.
*/
isync();
- sched_pin();
+ critical_enter();
pvo_pt->pte_hi &= ~LPTE_VALID;
pt->pte_hi &= ~LPTE_VALID;
PTESYNC();
TLBIE(vpn);
- sched_unpin();
+ critical_exit();
/*
* Save the reg & chg bits.
@@ -405,15 +403,6 @@ moea64_bootstrap_native(mmu_t mmup, vm_offset_t kernelstart,
CTR1(KTR_PMAP, "moea64_bootstrap: PTEG table at %p", moea64_pteg_table);
- /*
- * Initialize the TLBIE lock. TLBIE can only be executed by one CPU.
- */
-#ifdef __powerpc64__
- mtx_init(&tlbie_mutex, "tlbie", NULL, MTX_DEF);
-#else
- mtx_init(&tlbie_mutex, "tlbie", NULL, MTX_SPIN);
-#endif
-
moea64_mid_bootstrap(mmup, kernelstart, kernelend);
/*
diff --git a/sys/powerpc/aim/slb.c b/sys/powerpc/aim/slb.c
index 7f4b2ef..162c7fb 100644
--- a/sys/powerpc/aim/slb.c
+++ b/sys/powerpc/aim/slb.c
@@ -139,7 +139,7 @@ make_new_leaf(uint64_t esid, uint64_t slbv, struct slbtnode *parent)
* that a lockless searcher always sees a valid path through
* the tree.
*/
- powerpc_sync();
+ mb();
idx = esid2idx(esid, parent->ua_level);
parent->u.ua_child[idx] = child;
@@ -187,7 +187,7 @@ make_intermediate(uint64_t esid, struct slbtnode *parent)
idx = esid2idx(child->ua_base, inter->ua_level);
inter->u.ua_child[idx] = child;
setbit(&inter->ua_alloc, idx);
- powerpc_sync();
+ mb();
/* Set up parent to point to intermediate node ... */
idx = esid2idx(inter->ua_base, parent->ua_level);
OpenPOWER on IntegriCloud