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 <sys/mutex.h>
 #include <sys/proc.h>
 #include <sys/systm.h>
-#include <sys/tree.h>
 
 #include <vm/vm.h>
 #include <vm/pmap.h>
@@ -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 *);
 
_______________________________________________
[email protected] mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "[email protected]"

Reply via email to