From owner-svn-src-head@FreeBSD.ORG Thu Sep 16 00:22:25 2010 Return-Path: Delivered-To: svn-src-head@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 6B71E106564A; Thu, 16 Sep 2010 00:22:25 +0000 (UTC) (envelope-from nwhitehorn@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 5894B8FC19; Thu, 16 Sep 2010 00:22:25 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id o8G0MPl0055541; Thu, 16 Sep 2010 00:22:25 GMT (envelope-from nwhitehorn@svn.freebsd.org) Received: (from nwhitehorn@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id o8G0MPr5055534; Thu, 16 Sep 2010 00:22:25 GMT (envelope-from nwhitehorn@svn.freebsd.org) Message-Id: <201009160022.o8G0MPr5055534@svn.freebsd.org> From: Nathan Whitehorn Date: Thu, 16 Sep 2010 00:22:25 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r212715 - in head/sys/powerpc: aim include X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 16 Sep 2010 00:22:25 -0000 Author: nwhitehorn Date: Thu Sep 16 00:22:25 2010 New Revision: 212715 URL: http://svn.freebsd.org/changeset/base/212715 Log: Replace the SLB backing store splay tree used on 64-bit PowerPC AIM hardware with a lockless sparse tree design. This marginally improves the performance of PMAP and allows copyin()/copyout() to run without acquiring locks when used on wired mappings. Submitted by: mdf Modified: head/sys/powerpc/aim/copyinout.c head/sys/powerpc/aim/mmu_oea64.c head/sys/powerpc/aim/slb.c head/sys/powerpc/aim/trap.c head/sys/powerpc/include/pcb.h head/sys/powerpc/include/pmap.h Modified: head/sys/powerpc/aim/copyinout.c ============================================================================== --- head/sys/powerpc/aim/copyinout.c Wed Sep 15 23:56:25 2010 (r212714) +++ head/sys/powerpc/aim/copyinout.c Thu Sep 16 00:22:25 2010 (r212715) @@ -80,16 +80,28 @@ int setfault(faultbuf); /* defined in lo static __inline void set_user_sr(pmap_t pm, const void *addr) { + struct slb *slb; register_t esid, vsid, slb1, slb2; esid = USER_ADDR >> ADDR_SR_SHFT; - PMAP_LOCK(pm); - vsid = va_to_vsid(pm, (vm_offset_t)addr); - PMAP_UNLOCK(pm); + + /* Try lockless look-up first */ + slb = user_va_to_slb_entry(pm, (vm_offset_t)addr); + + if (slb == NULL) { + /* If it isn't there, we need to pre-fault the VSID */ + PMAP_LOCK(pm); + vsid = va_to_vsid(pm, (vm_offset_t)addr); + PMAP_UNLOCK(pm); + } else { + vsid = slb->slbv >> SLBV_VSID_SHIFT; + } slb1 = vsid << SLBV_VSID_SHIFT; slb2 = (esid << SLBE_ESID_SHIFT) | SLBE_VALID | USER_SR; + curthread->td_pcb->pcb_cpu.aim.usr_segm = + (uintptr_t)addr >> ADDR_SR_SHFT; __asm __volatile ("slbie %0; slbmte %1, %2" :: "r"(esid << 28), "r"(slb1), "r"(slb2)); isync(); Modified: head/sys/powerpc/aim/mmu_oea64.c ============================================================================== --- head/sys/powerpc/aim/mmu_oea64.c Wed Sep 15 23:56:25 2010 (r212714) +++ head/sys/powerpc/aim/mmu_oea64.c Thu Sep 16 00:22:25 2010 (r212715) @@ -2097,7 +2097,7 @@ moea64_pinit(mmu_t mmu, pmap_t pmap) { PMAP_LOCK_INIT(pmap); - SPLAY_INIT(&pmap->pm_slbtree); + pmap->pm_slb_tree_root = slb_alloc_tree(); pmap->pm_slb = slb_alloc_user_cache(); } #else @@ -2252,7 +2252,7 @@ moea64_release(mmu_t mmu, pmap_t pmap) * Free segment registers' VSIDs */ #ifdef __powerpc64__ - free_vsids(pmap); + slb_free_tree(pmap); slb_free_user_cache(pmap->pm_slb); #else KASSERT(pmap->pm_sr[0] != 0, ("moea64_release: pm_sr[0] = 0")); @@ -2622,18 +2622,25 @@ moea64_pvo_find_va(pmap_t pm, vm_offset_ int ptegidx; uint64_t vsid; #ifdef __powerpc64__ - struct slb slb; + uint64_t slbv; - /* The page is not mapped if the segment isn't */ - if (va_to_slb_entry(pm, va, &slb) != 0) - return NULL; + if (pm == kernel_pmap) { + slbv = kernel_va_to_slbv(va); + } else { + struct slb *slb; + slb = user_va_to_slb_entry(pm, va); + /* The page is not mapped if the segment isn't */ + if (slb == NULL) + return NULL; + slbv = slb->slbv; + } - vsid = (slb.slbv & SLBV_VSID_MASK) >> SLBV_VSID_SHIFT; - if (slb.slbv & SLBV_L) + vsid = (slbv & SLBV_VSID_MASK) >> SLBV_VSID_SHIFT; + if (slbv & SLBV_L) va &= ~moea64_large_page_mask; else va &= ~ADDR_POFF; - ptegidx = va_to_pteg(vsid, va, slb.slbv & SLBV_L); + ptegidx = va_to_pteg(vsid, va, slbv & SLBV_L); #else va &= ~ADDR_POFF; vsid = va_to_vsid(pm, va); Modified: head/sys/powerpc/aim/slb.c ============================================================================== --- head/sys/powerpc/aim/slb.c Wed Sep 15 23:56:25 2010 (r212714) +++ head/sys/powerpc/aim/slb.c Thu Sep 16 00:22:25 2010 (r212715) @@ -32,7 +32,6 @@ #include #include #include -#include #include #include @@ -45,65 +44,212 @@ uintptr_t moea64_get_unique_vsid(void); void moea64_release_vsid(uint64_t vsid); +static void slb_zone_init(void *); + +uma_zone_t slbt_zone; +uma_zone_t slb_cache_zone; -struct slbcontainer { - struct slb slb; - SPLAY_ENTRY(slbcontainer) slb_node; +SYSINIT(slb_zone_init, SI_SUB_KMEM, SI_ORDER_ANY, slb_zone_init, NULL); + +struct slbtnode { + uint16_t ua_alloc; + uint8_t ua_level; + /* Only 36 bits needed for full 64-bit address space. */ + uint64_t ua_base; + union { + struct slbtnode *ua_child[16]; + struct slb slb_entries[16]; + } u; }; -static int slb_compare(struct slbcontainer *a, struct slbcontainer *b); -static void slb_zone_init(void *); +/* + * For a full 64-bit address space, there are 36 bits in play in an + * esid, so 8 levels, with the leaf being at level 0. + * + * |3333|3322|2222|2222|1111|1111|11 | | | esid + * |5432|1098|7654|3210|9876|5432|1098|7654|3210| bits + * +----+----+----+----+----+----+----+----+----+-------- + * | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | level + */ +#define UAD_ROOT_LEVEL 8 +#define UAD_LEAF_LEVEL 0 + +static inline int +esid2idx(uint64_t esid, int level) +{ + int shift; -SPLAY_PROTOTYPE(slb_tree, slbcontainer, slb_node, slb_compare); -SPLAY_GENERATE(slb_tree, slbcontainer, slb_node, slb_compare); + shift = level * 4; + return ((esid >> shift) & 0xF); +} -uma_zone_t slb_zone; -uma_zone_t slb_cache_zone; +/* + * The ua_base field should have 0 bits after the first 4*(level+1) + * bits; i.e. only + */ +#define uad_baseok(ua) \ + (esid2base(ua->ua_base, ua->ua_level) == ua->ua_base) -SYSINIT(slb_zone_init, SI_SUB_KMEM, SI_ORDER_ANY, slb_zone_init, NULL); -int -va_to_slb_entry(pmap_t pm, vm_offset_t va, struct slb *slb) +static inline uint64_t +esid2base(uint64_t esid, int level) { - struct slbcontainer cont, *found; - uint64_t esid; + uint64_t mask; + int shift; - esid = (uintptr_t)va >> ADDR_SR_SHFT; - slb->slbe = (esid << SLBE_ESID_SHIFT) | SLBE_VALID; + shift = (level + 1) * 4; + mask = ~((1ULL << shift) - 1); + return (esid & mask); +} - if (pm == kernel_pmap) { - /* Set kernel VSID to deterministic value */ - slb->slbv = va_to_vsid(kernel_pmap, va) << SLBV_VSID_SHIFT; - - /* Figure out if this is a large-page mapping */ - if (hw_direct_map && va < VM_MIN_KERNEL_ADDRESS) { - /* - * XXX: If we have set up a direct map, assumes - * all physical memory is mapped with large pages. - */ - if (mem_valid(va, 0) == 0) - slb->slbv |= SLBV_L; - } - - return (0); - } +/* + * Allocate a new leaf node for the specified esid/vmhandle from the + * parent node. + */ +static struct slb * +make_new_leaf(uint64_t esid, uint64_t slbv, struct slbtnode *parent) +{ + struct slbtnode *child; + struct slb *retval; + int idx; + + idx = esid2idx(esid, parent->ua_level); + KASSERT(parent->u.ua_child[idx] == NULL, ("Child already exists!")); + + /* unlock and M_WAITOK and loop? */ + child = uma_zalloc(slbt_zone, M_NOWAIT | M_ZERO); + KASSERT(child != NULL, ("unhandled NULL case")); + + child->ua_level = UAD_LEAF_LEVEL; + child->ua_base = esid2base(esid, child->ua_level); + idx = esid2idx(esid, child->ua_level); + child->u.slb_entries[idx].slbv = slbv; + child->u.slb_entries[idx].slbe = (esid << SLBE_ESID_SHIFT) | SLBE_VALID; + setbit(&child->ua_alloc, idx); - PMAP_LOCK_ASSERT(pm, MA_OWNED); + retval = &child->u.slb_entries[idx]; + + /* + * The above stores must be visible before the next one, so + * that a lockless searcher always sees a valid path through + * the tree. + */ + powerpc_sync(); + + idx = esid2idx(esid, parent->ua_level); + parent->u.ua_child[idx] = child; + setbit(&parent->ua_alloc, idx); + + return (retval); +} + +/* + * Allocate a new intermediate node to fit between the parent and + * esid. + */ +static struct slbtnode* +make_intermediate(uint64_t esid, struct slbtnode *parent) +{ + struct slbtnode *child, *inter; + int idx, level; + + idx = esid2idx(esid, parent->ua_level); + child = parent->u.ua_child[idx]; + KASSERT(esid2base(esid, child->ua_level) != child->ua_base, + ("No need for an intermediate node?")); + + /* + * Find the level where the existing child and our new esid + * meet. It must be lower than parent->ua_level or we would + * have chosen a different index in parent. + */ + level = child->ua_level + 1; + while (esid2base(esid, level) != + esid2base(child->ua_base, level)) + level++; + KASSERT(level < parent->ua_level, + ("Found splitting level %d for %09jx and %09jx, " + "but it's the same as %p's", + level, esid, child->ua_base, parent)); + + /* unlock and M_WAITOK and loop? */ + inter = uma_zalloc(slbt_zone, M_NOWAIT | M_ZERO); + KASSERT(inter != NULL, ("unhandled NULL case")); + + /* Set up intermediate node to point to child ... */ + inter->ua_level = level; + inter->ua_base = esid2base(esid, inter->ua_level); + idx = esid2idx(child->ua_base, inter->ua_level); + inter->u.ua_child[idx] = child; + setbit(&inter->ua_alloc, idx); + powerpc_sync(); + + /* Set up parent to point to intermediate node ... */ + idx = esid2idx(inter->ua_base, parent->ua_level); + parent->u.ua_child[idx] = inter; + setbit(&parent->ua_alloc, idx); + + return (inter); +} + +uint64_t +kernel_va_to_slbv(vm_offset_t va) +{ + uint64_t esid, slbv; - cont.slb.slbe = slb->slbe; - found = SPLAY_FIND(slb_tree, &pm->pm_slbtree, &cont); + esid = (uintptr_t)va >> ADDR_SR_SHFT; - if (found == NULL) - return (-1); + /* Set kernel VSID to deterministic value */ + slbv = va_to_vsid(kernel_pmap, va) << SLBV_VSID_SHIFT; - slb->slbv = found->slb.slbv; - return (0); + /* Figure out if this is a large-page mapping */ + if (hw_direct_map && va < VM_MIN_KERNEL_ADDRESS) { + /* + * XXX: If we have set up a direct map, assumes + * all physical memory is mapped with large pages. + */ + if (mem_valid(va, 0) == 0) + slbv |= SLBV_L; + } + + return (slbv); +} + +struct slb * +user_va_to_slb_entry(pmap_t pm, vm_offset_t va) +{ + uint64_t esid = va >> ADDR_SR_SHFT; + struct slbtnode *ua; + int idx; + + ua = pm->pm_slb_tree_root; + + for (;;) { + KASSERT(uad_baseok(ua), ("uad base %016jx level %d bad!", + ua->ua_base, ua->ua_level)); + idx = esid2idx(esid, ua->ua_level); + + /* + * This code is specific to ppc64 where a load is + * atomic, so no need for atomic_load macro. + */ + if (ua->ua_level == UAD_LEAF_LEVEL) + return ((ua->u.slb_entries[idx].slbe & SLBE_VALID) ? + &ua->u.slb_entries[idx] : NULL); + + ua = ua->u.ua_child[idx]; + if (ua == NULL || + esid2base(esid, ua->ua_level) != ua->ua_base) + return (NULL); + } + + return (NULL); } uint64_t va_to_vsid(pmap_t pm, vm_offset_t va) { - struct slb entry; + struct slb *entry; /* Shortcut kernel case */ if (pm == kernel_pmap) @@ -114,56 +260,149 @@ va_to_vsid(pmap_t pm, vm_offset_t va) * to the PMAP's segment table. */ - if (va_to_slb_entry(pm, va, &entry) != 0) + entry = user_va_to_slb_entry(pm, va); + + if (entry == NULL) return (allocate_vsid(pm, (uintptr_t)va >> ADDR_SR_SHFT, 0)); - return ((entry.slbv & SLBV_VSID_MASK) >> SLBV_VSID_SHIFT); + return ((entry->slbv & SLBV_VSID_MASK) >> SLBV_VSID_SHIFT); } uint64_t allocate_vsid(pmap_t pm, uint64_t esid, int large) { - uint64_t vsid; - struct slbcontainer *slb_entry, kern_entry; - struct slb *prespill; - - prespill = NULL; - - if (pm == kernel_pmap) { - vsid = va_to_vsid(pm, esid << ADDR_SR_SHFT); - slb_entry = &kern_entry; - prespill = PCPU_GET(slb); - } else { - vsid = moea64_get_unique_vsid(); - slb_entry = uma_zalloc(slb_zone, M_NOWAIT); + uint64_t vsid, slbv; + struct slbtnode *ua, *next, *inter; + struct slb *slb; + int idx; - if (slb_entry == NULL) - panic("Could not allocate SLB mapping!"); - - prespill = pm->pm_slb; - } + KASSERT(pm != kernel_pmap, ("Attempting to allocate a kernel VSID")); - slb_entry->slb.slbe = (esid << SLBE_ESID_SHIFT) | SLBE_VALID; - slb_entry->slb.slbv = vsid << SLBV_VSID_SHIFT; + PMAP_LOCK_ASSERT(pm, MA_OWNED); + vsid = moea64_get_unique_vsid(); + slbv = vsid << SLBV_VSID_SHIFT; if (large) - slb_entry->slb.slbv |= SLBV_L; + slbv |= SLBV_L; + + ua = pm->pm_slb_tree_root; + + /* Descend to the correct leaf or NULL pointer. */ + for (;;) { + KASSERT(uad_baseok(ua), + ("uad base %09jx level %d bad!", ua->ua_base, ua->ua_level)); + idx = esid2idx(esid, ua->ua_level); + + if (ua->ua_level == UAD_LEAF_LEVEL) { + ua->u.slb_entries[idx].slbv = slbv; + eieio(); + ua->u.slb_entries[idx].slbe = (esid << SLBE_ESID_SHIFT) + | SLBE_VALID; + setbit(&ua->ua_alloc, idx); + slb = &ua->u.slb_entries[idx]; + break; + } + + next = ua->u.ua_child[idx]; + if (next == NULL) { + slb = make_new_leaf(esid, slbv, ua); + break; + } + + /* + * Check if the next item down has an okay ua_base. + * If not, we need to allocate an intermediate node. + */ + if (esid2base(esid, next->ua_level) != next->ua_base) { + inter = make_intermediate(esid, ua); + slb = make_new_leaf(esid, slbv, inter); + break; + } - if (pm != kernel_pmap) { - PMAP_LOCK_ASSERT(pm, MA_OWNED); - SPLAY_INSERT(slb_tree, &pm->pm_slbtree, slb_entry); + ua = next; } /* * Someone probably wants this soon, and it may be a wired * SLB mapping, so pre-spill this entry. */ - if (prespill != NULL) - slb_insert(pm, prespill, &slb_entry->slb); + eieio(); + slb_insert(pm, pm->pm_slb, slb); return (vsid); } +void +free_vsid(pmap_t pm, uint64_t esid, int large) +{ + struct slbtnode *ua; + int idx; + + PMAP_LOCK_ASSERT(pm, MA_OWNED); + + ua = pm->pm_slb_tree_root; + /* Descend to the correct leaf. */ + for (;;) { + KASSERT(uad_baseok(ua), + ("uad base %09jx level %d bad!", ua->ua_base, ua->ua_level)); + + idx = esid2idx(esid, ua->ua_level); + if (ua->ua_level == UAD_LEAF_LEVEL) { + ua->u.slb_entries[idx].slbv = 0; + eieio(); + ua->u.slb_entries[idx].slbe = 0; + clrbit(&ua->ua_alloc, idx); + return; + } + + ua = ua->u.ua_child[idx]; + if (ua == NULL || + esid2base(esid, ua->ua_level) != ua->ua_base) { + /* Perhaps just return instead of assert? */ + KASSERT(0, + ("Asked to remove an entry that was never inserted!")); + return; + } + } +} + +static void +free_slb_tree_node(struct slbtnode *ua) +{ + int idx; + + for (idx = 0; idx < 16; idx++) { + if (ua->ua_level != UAD_LEAF_LEVEL) { + if (ua->u.ua_child[idx] != NULL) + free_slb_tree_node(ua->u.ua_child[idx]); + } else { + if (ua->u.slb_entries[idx].slbv != 0) + moea64_release_vsid(ua->u.slb_entries[idx].slbv + >> SLBV_VSID_SHIFT); + } + } + + uma_zfree(slbt_zone, ua); +} + +void +slb_free_tree(pmap_t pm) +{ + + free_slb_tree_node(pm->pm_slb_tree_root); +} + +struct slbtnode * +slb_alloc_tree(void) +{ + struct slbtnode *root; + + root = uma_zalloc(slbt_zone, M_NOWAIT | M_ZERO); + root->ua_level = UAD_ROOT_LEVEL; + + return (root); +} + /* Lock entries mapping kernel text and stacks */ #define SLB_SPILLABLE(slbe) \ @@ -222,62 +461,12 @@ slb_insert(pmap_t pm, struct slb *slbcac critical_exit(); } -int -vsid_to_esid(pmap_t pm, uint64_t vsid, uint64_t *esid) -{ - uint64_t slbv; - struct slbcontainer *entry; - -#ifdef INVARIANTS - if (pm == kernel_pmap) - panic("vsid_to_esid only works on user pmaps"); - - PMAP_LOCK_ASSERT(pm, MA_OWNED); -#endif - - slbv = vsid << SLBV_VSID_SHIFT; - - SPLAY_FOREACH(entry, slb_tree, &pm->pm_slbtree) { - if (slbv == entry->slb.slbv) { - *esid = entry->slb.slbe >> SLBE_ESID_SHIFT; - return (0); - } - } - - return (-1); -} - -void -free_vsids(pmap_t pm) -{ - struct slbcontainer *entry; - - while (!SPLAY_EMPTY(&pm->pm_slbtree)) { - entry = SPLAY_MIN(slb_tree, &pm->pm_slbtree); - - SPLAY_REMOVE(slb_tree, &pm->pm_slbtree, entry); - - moea64_release_vsid(entry->slb.slbv >> SLBV_VSID_SHIFT); - uma_zfree(slb_zone, entry); - } -} - -static int -slb_compare(struct slbcontainer *a, struct slbcontainer *b) -{ - if (a->slb.slbe == b->slb.slbe) - return (0); - else if (a->slb.slbe < b->slb.slbe) - return (-1); - else - return (1); -} static void slb_zone_init(void *dummy) { - slb_zone = uma_zcreate("SLB segment", sizeof(struct slbcontainer), + slbt_zone = uma_zcreate("SLB tree node", sizeof(struct slbtnode), NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_VM); slb_cache_zone = uma_zcreate("SLB cache", 64*sizeof(struct slb), NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_VM); Modified: head/sys/powerpc/aim/trap.c ============================================================================== --- head/sys/powerpc/aim/trap.c Wed Sep 15 23:56:25 2010 (r212714) +++ head/sys/powerpc/aim/trap.c Thu Sep 16 00:22:25 2010 (r212715) @@ -445,33 +445,37 @@ syscall(struct trapframe *frame) static int handle_slb_spill(pmap_t pm, vm_offset_t addr) { - struct slb slb_entry; - int error, i; + struct slb kern_entry, *user_entry; + uint64_t esid; + int i; + + esid = (uintptr_t)addr >> ADDR_SR_SHFT; if (pm == kernel_pmap) { - error = va_to_slb_entry(pm, addr, &slb_entry); - if (error) - return (error); + kern_entry.slbv = kernel_va_to_slbv(addr); + kern_entry.slbe = (esid << SLBE_ESID_SHIFT) | SLBE_VALID; - slb_insert(pm, PCPU_GET(slb), &slb_entry); + slb_insert(pm, PCPU_GET(slb), &kern_entry); return (0); } PMAP_LOCK(pm); - error = va_to_slb_entry(pm, addr, &slb_entry); - if (error != 0) - (void)allocate_vsid(pm, (uintptr_t)addr >> ADDR_SR_SHFT, 0); - else { + user_entry = user_va_to_slb_entry(pm, addr); + + if (user_entry == NULL) { + /* allocate_vsid auto-spills it */ + (void)allocate_vsid(pm, esid, 0); + } else { /* * Check that another CPU has not already mapped this. * XXX: Per-thread SLB caches would be better. */ for (i = 0; i < 64; i++) - if (pm->pm_slb[i].slbe == (slb_entry.slbe | i)) + if (pm->pm_slb[i].slbe == (user_entry->slbe | i)) break; if (i == 64) - slb_insert(pm, pm->pm_slb, &slb_entry); + slb_insert(pm, pm->pm_slb, user_entry); } PMAP_UNLOCK(pm); @@ -513,19 +517,7 @@ trap_pfault(struct trapframe *frame, int map = &p->p_vmspace->vm_map; #ifdef __powerpc64__ - user_sr = 0; - __asm ("slbmfev %0, %1" - : "=r"(user_sr) - : "r"(USER_SR)); - - PMAP_LOCK(&p->p_vmspace->vm_pmap); - user_sr >>= SLBV_VSID_SHIFT; - rv = vsid_to_esid(&p->p_vmspace->vm_pmap, user_sr, - &user_sr); - PMAP_UNLOCK(&p->p_vmspace->vm_pmap); - - if (rv != 0) - return (SIGSEGV); + user_sr = td->td_pcb->pcb_cpu.aim.usr_segm; #else __asm ("mfsr %0, %1" : "=r"(user_sr) Modified: head/sys/powerpc/include/pcb.h ============================================================================== --- head/sys/powerpc/include/pcb.h Wed Sep 15 23:56:25 2010 (r212714) +++ head/sys/powerpc/include/pcb.h Thu Sep 16 00:22:25 2010 (r212715) @@ -66,6 +66,7 @@ struct pcb { union { struct { + vm_offset_t usr_segm; /* Base address */ register_t usr_esid; /* USER_SR segment */ register_t usr_vsid; /* USER_SR segment */ } aim; Modified: head/sys/powerpc/include/pmap.h ============================================================================== --- head/sys/powerpc/include/pmap.h Wed Sep 15 23:56:25 2010 (r212714) +++ head/sys/powerpc/include/pmap.h Thu Sep 16 00:22:25 2010 (r212715) @@ -86,15 +86,13 @@ struct pmap_md { #define NPMAPS 32768 #endif /* !defined(NPMAPS) */ -struct slbcontainer; - -SPLAY_HEAD(slb_tree, slbcontainer); +struct slbtnode; struct pmap { struct mtx pm_mtx; #ifdef __powerpc64__ - struct slb_tree pm_slbtree; + struct slbtnode *pm_slb_tree_root; struct slb *pm_slb; #else register_t pm_sr[16]; @@ -139,12 +137,17 @@ struct md_page { * NB: The PMAP MUST be locked already. */ uint64_t va_to_vsid(pmap_t pm, vm_offset_t va); -int va_to_slb_entry(pmap_t pm, vm_offset_t va, struct slb *); + +/* Lock-free, non-allocating lookup routines */ +uint64_t kernel_va_to_slbv(vm_offset_t va); +struct slb *user_va_to_slb_entry(pmap_t pm, vm_offset_t va); uint64_t allocate_vsid(pmap_t pm, uint64_t esid, int large); -void slb_insert(pmap_t pm, struct slb *dst, struct slb *); -int vsid_to_esid(pmap_t pm, uint64_t vsid, uint64_t *esid); -void free_vsids(pmap_t pm); +void free_vsid(pmap_t pm, uint64_t esid, int large); +void slb_insert(pmap_t pm, struct slb *dst, struct slb *); + +struct slbtnode *slb_alloc_tree(void); +void slb_free_tree(pmap_t pm); struct slb *slb_alloc_user_cache(void); void slb_free_user_cache(struct slb *);