#include <linux/mm.h>
 #include <linux/export.h>
 #include <asm/reg.h>
+#include <asm/copro.h>
 
 /*
  * This ought to be kept in sync with the powerpc specific do_page_fault
        return ret;
 }
 EXPORT_SYMBOL_GPL(copro_handle_mm_fault);
+
+int copro_calculate_slb(struct mm_struct *mm, u64 ea, struct copro_slb *slb)
+{
+       u64 vsid;
+       int psize, ssize;
+
+       slb->esid = (ea & ESID_MASK) | SLB_ESID_V;
+
+       switch (REGION_ID(ea)) {
+       case USER_REGION_ID:
+               pr_devel("%s: 0x%llx -- USER_REGION_ID\n", __func__, ea);
+               psize = get_slice_psize(mm, ea);
+               ssize = user_segment_size(ea);
+               vsid = get_vsid(mm->context.id, ea, ssize);
+               break;
+       case VMALLOC_REGION_ID:
+               pr_devel("%s: 0x%llx -- VMALLOC_REGION_ID\n", __func__, ea);
+               if (ea < VMALLOC_END)
+                       psize = mmu_vmalloc_psize;
+               else
+                       psize = mmu_io_psize;
+               ssize = mmu_kernel_ssize;
+               vsid = get_kernel_vsid(ea, mmu_kernel_ssize);
+               break;
+       case KERNEL_REGION_ID:
+               pr_devel("%s: 0x%llx -- KERNEL_REGION_ID\n", __func__, ea);
+               psize = mmu_linear_psize;
+               ssize = mmu_kernel_ssize;
+               vsid = get_kernel_vsid(ea, mmu_kernel_ssize);
+               break;
+       default:
+               pr_debug("%s: invalid region access at %016llx\n", __func__, ea);
+               return 1;
+       }
+
+       vsid = (vsid << slb_vsid_shift(ssize)) | SLB_VSID_USER;
+
+       vsid |= mmu_psize_defs[psize].sllp |
+               ((ssize == MMU_SEGSIZE_1T) ? SLB_VSID_B_1T : 0);
+
+       slb->vsid = vsid;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(copro_calculate_slb);
 
 static DEFINE_SPINLOCK(spu_full_list_lock);
 static DEFINE_MUTEX(spu_full_list_mutex);
 
-struct spu_slb {
-       u64 esid, vsid;
-};
-
 void spu_invalidate_slbs(struct spu *spu)
 {
        struct spu_priv2 __iomem *priv2 = spu->priv2;
        }
 }
 
-static inline void spu_load_slb(struct spu *spu, int slbe, struct spu_slb *slb)
+static inline void spu_load_slb(struct spu *spu, int slbe, struct copro_slb *slb)
 {
        struct spu_priv2 __iomem *priv2 = spu->priv2;
 
 
 static int __spu_trap_data_seg(struct spu *spu, unsigned long ea)
 {
-       struct mm_struct *mm = spu->mm;
-       struct spu_slb slb;
-       int psize;
-
-       pr_debug("%s\n", __func__);
-
-       slb.esid = (ea & ESID_MASK) | SLB_ESID_V;
+       struct copro_slb slb;
+       int ret;
 
-       switch(REGION_ID(ea)) {
-       case USER_REGION_ID:
-#ifdef CONFIG_PPC_MM_SLICES
-               psize = get_slice_psize(mm, ea);
-#else
-               psize = mm->context.user_psize;
-#endif
-               slb.vsid = (get_vsid(mm->context.id, ea, MMU_SEGSIZE_256M)
-                               << SLB_VSID_SHIFT) | SLB_VSID_USER;
-               break;
-       case VMALLOC_REGION_ID:
-               if (ea < VMALLOC_END)
-                       psize = mmu_vmalloc_psize;
-               else
-                       psize = mmu_io_psize;
-               slb.vsid = (get_kernel_vsid(ea, MMU_SEGSIZE_256M)
-                               << SLB_VSID_SHIFT) | SLB_VSID_KERNEL;
-               break;
-       case KERNEL_REGION_ID:
-               psize = mmu_linear_psize;
-               slb.vsid = (get_kernel_vsid(ea, MMU_SEGSIZE_256M)
-                               << SLB_VSID_SHIFT) | SLB_VSID_KERNEL;
-               break;
-       default:
-               /* Future: support kernel segments so that drivers
-                * can use SPUs.
-                */
-               pr_debug("invalid region access at %016lx\n", ea);
-               return 1;
-       }
-       slb.vsid |= mmu_psize_defs[psize].sllp;
+       ret = copro_calculate_slb(spu->mm, ea, &slb);
+       if (ret)
+               return ret;
 
        spu_load_slb(spu, spu->slb_replace, &slb);
 
        return 0;
 }
 
-static void __spu_kernel_slb(void *addr, struct spu_slb *slb)
+static void __spu_kernel_slb(void *addr, struct copro_slb *slb)
 {
        unsigned long ea = (unsigned long)addr;
        u64 llp;
  * Given an array of @nr_slbs SLB entries, @slbs, return non-zero if the
  * address @new_addr is present.
  */
-static inline int __slb_present(struct spu_slb *slbs, int nr_slbs,
+static inline int __slb_present(struct copro_slb *slbs, int nr_slbs,
                void *new_addr)
 {
        unsigned long ea = (unsigned long)new_addr;
 void spu_setup_kernel_slbs(struct spu *spu, struct spu_lscsa *lscsa,
                void *code, int code_size)
 {
-       struct spu_slb slbs[4];
+       struct copro_slb slbs[4];
        int i, nr_slbs = 0;
        /* start and end addresses of both mappings */
        void *addrs[] = {