|
From: Andy P. <at...@us...> - 2002-04-10 18:36:33
|
Update of /cvsroot/linux-vax/kernel-2.4/arch/sparc64/mm
In directory usw-pr-cvs1:/tmp/cvs-serv32333/sparc64/mm
Modified Files:
Makefile extable.c fault.c generic.c init.c modutil.c ultra.S
Log Message:
synch 2.4.15 commit 46
Index: Makefile
===================================================================
RCS file: /cvsroot/linux-vax/kernel-2.4/arch/sparc64/mm/Makefile,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -u -r1.1.1.1 -r1.2
Index: extable.c
===================================================================
RCS file: /cvsroot/linux-vax/kernel-2.4/arch/sparc64/mm/extable.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -u -r1.1.1.1 -r1.2
--- extable.c 14 Jan 2001 19:45:13 -0000 1.1.1.1
+++ extable.c 10 Apr 2002 15:21:24 -0000 1.2
@@ -43,27 +43,32 @@
return 0;
}
+extern spinlock_t modlist_lock;
+
unsigned long
search_exception_table(unsigned long addr, unsigned long *g2)
{
- unsigned long ret;
+ unsigned long ret = 0, flags;
#ifndef CONFIG_MODULES
/* There is only the kernel to search. */
ret = search_one_table(__start___ex_table,
__stop___ex_table-1, addr, g2);
- if (ret) return ret;
+ return ret;
#else
/* The kernel is the last "module" -- no need to treat it special. */
struct module *mp;
+
+ spin_lock_irqsave(&modlist_lock, flags);
for (mp = module_list; mp != NULL; mp = mp->next) {
- if (mp->ex_table_start == NULL)
+ if (mp->ex_table_start == NULL || !(mp->flags & (MOD_RUNNING | MOD_INITIALIZING)))
continue;
ret = search_one_table(mp->ex_table_start,
mp->ex_table_end-1, addr, g2);
- if (ret) return ret;
+ if (ret)
+ break;
}
+ spin_unlock_irqrestore(&modlist_lock, flags);
+ return ret;
#endif
-
- return 0;
}
Index: fault.c
===================================================================
RCS file: /cvsroot/linux-vax/kernel-2.4/arch/sparc64/mm/fault.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -u -r1.1.1.1 -r1.2
--- fault.c 14 Jan 2001 19:45:14 -0000 1.1.1.1
+++ fault.c 10 Apr 2002 15:21:24 -0000 1.2
@@ -22,11 +22,58 @@
#include <asm/openprom.h>
#include <asm/oplib.h>
#include <asm/uaccess.h>
+#include <asm/asi.h>
+#include <asm/lsu.h>
#define ELEMENTS(arr) (sizeof (arr)/sizeof (arr[0]))
extern struct sparc_phys_banks sp_banks[SPARC_PHYS_BANKS];
+/*
+ * To debug kernel during syscall entry.
+ */
+void syscall_trace_entry(struct pt_regs *regs)
+{
+ printk("scall entry: %s[%d]/cpu%d: %d\n", current->comm, current->pid, smp_processor_id(), (int) regs->u_regs[UREG_G1]);
+}
+
+/*
+ * To debug kernel during syscall exit.
+ */
+void syscall_trace_exit(struct pt_regs *regs)
+{
+ printk("scall exit: %s[%d]/cpu%d: %d\n", current->comm, current->pid, smp_processor_id(), (int) regs->u_regs[UREG_G1]);
+}
+
+/*
+ * To debug kernel to catch accesses to certain virtual/physical addresses.
+ * Mode = 0 selects physical watchpoints, mode = 1 selects virtual watchpoints.
+ * flags = VM_READ watches memread accesses, flags = VM_WRITE watches memwrite accesses.
+ * Caller passes in a 64bit aligned addr, with mask set to the bytes that need to be
+ * watched. This is only useful on a single cpu machine for now. After the watchpoint
+ * is detected, the process causing it will be killed, thus preventing an infinite loop.
+ */
+void set_brkpt(unsigned long addr, unsigned char mask, int flags, int mode)
+{
+ unsigned long lsubits = LSU_CONTROL_IC|LSU_CONTROL_DC|LSU_CONTROL_IM|LSU_CONTROL_DM;
+
+ __asm__ __volatile__("stxa %0, [%1] %2\n\t"
+ "membar #Sync"
+ : /* no outputs */
+ : "r" (addr), "r" (mode ? VIRT_WATCHPOINT : PHYS_WATCHPOINT),
+ "i" (ASI_DMMU));
+ lsubits |= ((unsigned long)mask << (mode ? 25 : 33));
+ if (flags & VM_READ)
+ lsubits |= (mode ? LSU_CONTROL_VR : LSU_CONTROL_PR);
+ if (flags & VM_WRITE)
+ lsubits |= (mode ? LSU_CONTROL_VW : LSU_CONTROL_PW);
+ __asm__ __volatile__("stxa %0, [%%g0] %1\n\t"
+ "membar #Sync"
+ : /* no outputs */
+ : "r" (lsubits), "i" (ASI_LSU_CONTROL)
+ : "memory");
+}
+
/* Nice, simple, prom library does all the sweating for us. ;) */
unsigned long __init prom_probe_memory (void)
{
@@ -92,6 +139,13 @@
die_if_kernel("Oops", regs);
}
+/*
+ * We now make sure that mmap_sem is held in all paths that call
+ * this. Additionally, to prevent kswapd from ripping ptes from
+ * under us, raise interrupts around the time that we look at the
+ * pte, kswapd will have to wait to get his smp ipi response from
+ * us. This saves us having to get page_table_lock.
+ */
static unsigned int get_user_insn(unsigned long tpc)
{
pgd_t *pgdp = pgd_offset(current->mm, tpc);
@@ -99,13 +153,17 @@
pte_t *ptep, pte;
unsigned long pa;
u32 insn = 0;
+ unsigned long pstate;
if (pgd_none(*pgdp))
- goto out;
+ goto outret;
pmdp = pmd_offset(pgdp, tpc);
if (pmd_none(*pmdp))
- goto out;
+ goto outret;
ptep = pte_offset(pmdp, tpc);
+ __asm__ __volatile__("rdpr %%pstate, %0" : "=r" (pstate));
+ __asm__ __volatile__("wrpr %0, %1, %%pstate"
+ : : "r" (pstate), "i" (PSTATE_IE));
pte = *ptep;
if (!pte_present(pte))
goto out;
@@ -119,6 +177,8 @@
: "r" (pa), "i" (ASI_PHYS_USE_EC));
out:
+ __asm__ __volatile__("wrpr %0, 0x0, %%pstate" : : "r" (pstate));
+outret:
return insn;
}
@@ -137,21 +197,28 @@
extern int handle_ldf_stq(u32, struct pt_regs *);
extern int handle_ld_nf(u32, struct pt_regs *);
-static void do_kernel_fault(struct pt_regs *regs, int si_code, int fault_code,
- unsigned int insn, unsigned long address)
+static inline unsigned int get_fault_insn(struct pt_regs *regs, unsigned int insn)
{
- unsigned long g2;
- unsigned char asi = ASI_P;
-
if (!insn) {
+ if (!regs->tpc || (regs->tpc & 0x3))
+ return 0;
if (regs->tstate & TSTATE_PRIV) {
- if (!regs->tpc || (regs->tpc & 0x3))
- goto cannot_handle;
insn = *(unsigned int *)regs->tpc;
} else {
insn = get_user_insn(regs->tpc);
}
}
+ return insn;
+}
+
+static void do_kernel_fault(struct pt_regs *regs, int si_code, int fault_code,
+ unsigned int insn, unsigned long address)
+{
+ unsigned long g2;
+ unsigned char asi = ASI_P;
+
+ if ((!insn) && (regs->tstate & TSTATE_PRIV))
+ goto cannot_handle;
/* If user insn could be read (thus insn is zero), that
* is fine. We will just gun down the process with a signal
@@ -232,9 +299,14 @@
* context, we must not take the fault..
*/
if (in_interrupt() || !mm)
- goto handle_kernel_fault;
+ goto intr_or_no_mm;
- down(&mm->mmap_sem);
+ if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
+ regs->tpc &= 0xffffffff;
+ address &= 0xffffffff;
+ }
+
+ down_read(&mm->mmap_sem);
vma = find_vma(mm, address);
if (!vma)
goto bad_area;
@@ -250,16 +322,9 @@
if (((fault_code &
(FAULT_CODE_DTLB | FAULT_CODE_WRITE | FAULT_CODE_WINFIXUP)) == FAULT_CODE_DTLB) &&
(vma->vm_flags & VM_WRITE) != 0) {
- unsigned long tpc = regs->tpc;
-
- if (tpc & 0x3)
+ insn = get_fault_insn(regs, 0);
+ if (!insn)
goto continue_fault;
-
- if (regs->tstate & TSTATE_PRIV)
- insn = *(unsigned int *)tpc;
- else
- insn = get_user_insn(tpc);
-
if ((insn & 0xc0200000) == 0xc0200000 &&
(insn & 0x1780000) != 0x1680000) {
/* Don't bother updating thread struct value,
@@ -286,7 +351,12 @@
if (fault_code & FAULT_CODE_WRITE) {
if (!(vma->vm_flags & VM_WRITE))
goto bad_area;
- if ((vma->vm_flags & VM_EXEC) != 0 &&
+
+ /* Spitfire has an icache which does not snoop
+ * processor stores. Later processors do...
+ */
+ if (tlb_type == spitfire &&
+ (vma->vm_flags & VM_EXEC) != 0 &&
vma->vm_file != NULL)
current->thread.use_blkcommit = 1;
} else {
@@ -308,7 +378,7 @@
goto out_of_memory;
}
- up(&mm->mmap_sem);
+ up_read(&mm->mmap_sem);
goto fault_done;
/*
@@ -316,7 +386,8 @@
* Fix it, but check if it's kernel or user first..
*/
bad_area:
- up(&mm->mmap_sem);
+ insn = get_fault_insn(regs, insn);
+ up_read(&mm->mmap_sem);
handle_kernel_fault:
do_kernel_fault(regs, si_code, fault_code, insn, address);
@@ -328,14 +399,20 @@
* us unable to handle the page fault gracefully.
*/
out_of_memory:
- up(&mm->mmap_sem);
+ insn = get_fault_insn(regs, insn);
+ up_read(&mm->mmap_sem);
printk("VM: killing process %s\n", current->comm);
if (!(regs->tstate & TSTATE_PRIV))
do_exit(SIGKILL);
goto handle_kernel_fault;
+intr_or_no_mm:
+ insn = get_fault_insn(regs, 0);
+ goto handle_kernel_fault;
+
do_sigbus:
- up(&mm->mmap_sem);
+ insn = get_fault_insn(regs, insn);
+ up_read(&mm->mmap_sem);
/*
* Send a sigbus, regardless of whether we were in kernel
Index: generic.c
===================================================================
RCS file: /cvsroot/linux-vax/kernel-2.4/arch/sparc64/mm/generic.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -u -r1.1.1.1 -r1.2
--- generic.c 14 Jan 2001 19:45:15 -0000 1.1.1.1
+++ generic.c 10 Apr 2002 15:21:24 -0000 1.2
@@ -8,6 +8,7 @@
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/swap.h>
+#include <linux/pagemap.h>
#include <asm/pgalloc.h>
#include <asm/pgtable.h>
@@ -21,11 +22,7 @@
struct page *ptpage = pte_page(page);
if ((!VALID_PAGE(ptpage)) || PageReserved(ptpage))
return;
- /*
- * free_page() used to be able to clear swap cache
- * entries. We may now have to do it manually.
- */
- free_page_and_swap_cache(ptpage);
+ page_cache_release(ptpage);
return;
}
swap_free(pte_to_swp_entry(page));
@@ -104,12 +101,10 @@
end = PGDIR_SIZE;
offset -= address;
do {
- pte_t * pte = pte_alloc(pmd, address);
+ pte_t * pte = pte_alloc(current->mm, pmd, address);
if (!pte)
return -ENOMEM;
- spin_lock(¤t->mm->page_table_lock);
io_remap_pte_range(pte, address, end - address, address + offset, prot, space);
- spin_unlock(¤t->mm->page_table_lock);
address = (address + PMD_SIZE) & PMD_MASK;
pmd++;
} while (address < end);
@@ -122,13 +117,16 @@
pgd_t * dir;
unsigned long beg = from;
unsigned long end = from + size;
+ struct mm_struct *mm = current->mm;
prot = __pgprot(pg_iobits);
offset -= from;
- dir = pgd_offset(current->mm, from);
- flush_cache_range(current->mm, beg, end);
+ dir = pgd_offset(mm, from);
+ flush_cache_range(mm, beg, end);
+
+ spin_lock(&mm->page_table_lock);
while (from < end) {
- pmd_t *pmd = pmd_alloc(dir, from);
+ pmd_t *pmd = pmd_alloc(current->mm, dir, from);
error = -ENOMEM;
if (!pmd)
break;
@@ -138,6 +136,8 @@
from = (from + PGDIR_SIZE) & PGDIR_MASK;
dir++;
}
+ spin_unlock(&mm->page_table_lock);
+
flush_tlb_range(current->mm, beg, end);
return error;
}
Index: init.c
===================================================================
RCS file: /cvsroot/linux-vax/kernel-2.4/arch/sparc64/mm/init.c,v
retrieving revision 1.1.1.2
retrieving revision 1.2
diff -u -r1.1.1.2 -r1.2
--- init.c 25 Feb 2001 23:15:20 -0000 1.1.1.2
+++ init.c 10 Apr 2002 15:21:24 -0000 1.2
@@ -16,6 +16,9 @@
#include <linux/blk.h>
#include <linux/swap.h>
#include <linux/swapctl.h>
+#include <linux/pagemap.h>
+#include <linux/fs.h>
+#include <linux/seq_file.h>
#include <asm/head.h>
#include <asm/system.h>
@@ -27,9 +30,12 @@
#include <asm/io.h>
[...1406 lines suppressed...]
+ unsigned long addr, initend;
- addr = (unsigned long)(&__init_begin);
- for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) {
+ /*
+ * The init section is aligned to 8k in vmlinux.lds. Page align for >8k pagesizes.
+ */
+ addr = PAGE_ALIGN((unsigned long)(&__init_begin));
+ initend = (unsigned long)(&__init_end) & PAGE_MASK;
+ for (; addr < initend; addr += PAGE_SIZE) {
unsigned long page;
struct page *p;
page = (addr +
((unsigned long) __va(phys_base)) -
- ((unsigned long) &empty_zero_page));
+ ((unsigned long) KERNBASE));
p = virt_to_page(page);
ClearPageReserved(p);
Index: modutil.c
===================================================================
RCS file: /cvsroot/linux-vax/kernel-2.4/arch/sparc64/mm/modutil.c,v
retrieving revision 1.1.1.2
retrieving revision 1.2
diff -u -r1.1.1.2 -r1.2
--- modutil.c 25 Feb 2001 23:15:20 -0000 1.1.1.2
+++ modutil.c 10 Apr 2002 15:21:24 -0000 1.2
@@ -10,7 +10,10 @@
#include <asm/uaccess.h>
#include <asm/system.h>
-#include <asm/vaddrs.h>
+
+#define MODULES_VADDR 0x0000000001000000ULL /* Where to map modules */
+#define MODULES_LEN 0x000000007f000000ULL
+#define MODULES_END 0x0000000080000000ULL
static struct vm_struct * modvmlist = NULL;
@@ -59,7 +62,7 @@
*p = area;
if (vmalloc_area_pages(VMALLOC_VMADDR(addr), size, GFP_KERNEL, PAGE_KERNEL)) {
- vfree(addr);
+ module_unmap(addr);
return NULL;
}
return addr;
Index: ultra.S
===================================================================
RCS file: /cvsroot/linux-vax/kernel-2.4/arch/sparc64/mm/ultra.S,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -u -r1.1.1.1 -r1.2
--- ultra.S 14 Jan 2001 19:45:13 -0000 1.1.1.1
+++ ultra.S 10 Apr 2002 15:21:24 -0000 1.2
@@ -9,6 +9,23 @@
#include <asm/pgtable.h>
#include <asm/page.h>
#include <asm/spitfire.h>
+#include <asm/mmu_context.h>
+
+ /* Basically, all this madness has to do with the
+ * fact that Cheetah does not support IMMU flushes
+ * out of the secondary context. Someone needs to
+ * throw a south lake birthday party for the folks
+ * in Microelectronics who refused to fix this shit.
+ */
+#define BRANCH_IF_CHEETAH(tmp1, tmp2, label) \
+ rdpr %ver, %tmp1; \
+ sethi %hi(0x003e0014), %tmp2; \
+ srlx %tmp1, 32, %tmp1; \
+ or %tmp2, %lo(0x003e0014), %tmp2; \
+ cmp %tmp1, %tmp2; \
+ be,pn %icc, label; \
+ nop; \
+ nop;
/* This file is meant to be read efficiently by the CPU, not humans.
* Staraj sie tego nikomu nie pierdolnac...
@@ -16,38 +33,78 @@
.text
.align 32
.globl __flush_tlb_page, __flush_tlb_mm, __flush_tlb_range
-__flush_tlb_page: /* %o0=(ctx & 0x3ff), %o1=page&PAGE_MASK, %o2=SECONDARY_CONTEXT */
-/*IC1*/ ldxa [%o2] ASI_DMMU, %g2
+__flush_tlb_page: /* %o0=(ctx & TAG_CONTEXT_BITS), %o1=page&PAGE_MASK, %o2=SECONDARY_CONTEXT */
+/*IC1*/ BRANCH_IF_CHEETAH(g2, g3, __cheetah_flush_tlb_page)
+__spitfire_flush_tlb_page:
+/*IC2*/ ldxa [%o2] ASI_DMMU, %g2
cmp %g2, %o0
- bne,pn %icc, __flush_tlb_page_slow
+ bne,pn %icc, __spitfire_flush_tlb_page_slow
or %o1, 0x10, %g3
stxa %g0, [%g3] ASI_DMMU_DEMAP
stxa %g0, [%g3] ASI_IMMU_DEMAP
retl
flush %g6
-__flush_tlb_mm: /* %o0=(ctx & 0x3ff), %o1=SECONDARY_CONTEXT */
-/*IC2*/ ldxa [%o1] ASI_DMMU, %g2
+__cheetah_flush_tlb_page:
+/*IC3*/ rdpr %pstate, %g5
+ andn %g5, PSTATE_IE, %g2
+ wrpr %g2, 0x0, %pstate
+ wrpr %g0, 1, %tl
+ mov PRIMARY_CONTEXT, %o2
+ ldxa [%o2] ASI_DMMU, %g2
+ stxa %o0, [%o2] ASI_DMMU
+ stxa %g0, [%o1] ASI_DMMU_DEMAP
+/*IC4*/ stxa %g0, [%o1] ASI_IMMU_DEMAP
+ stxa %g2, [%o2] ASI_DMMU
+ flush %g6
+ wrpr %g0, 0, %tl
+ retl
+ wrpr %g5, 0x0, %pstate
+ nop
+ nop
+__flush_tlb_mm: /* %o0=(ctx & TAG_CONTEXT_BITS), %o1=SECONDARY_CONTEXT */
+/*IC5*/ BRANCH_IF_CHEETAH(g2, g3, __cheetah_flush_tlb_mm)
+__spitfire_flush_tlb_mm:
+/*IC6*/ ldxa [%o1] ASI_DMMU, %g2
cmp %g2, %o0
- bne,pn %icc, __flush_tlb_mm_slow
+ bne,pn %icc, __spitfire_flush_tlb_mm_slow
mov 0x50, %g3
stxa %g0, [%g3] ASI_DMMU_DEMAP
stxa %g0, [%g3] ASI_IMMU_DEMAP
retl
flush %g6
-__flush_tlb_range: /* %o0=(ctx&0x3ff), %o1=start&PAGE_MASK, %o2=SECONDARY_CONTEXT,
+__cheetah_flush_tlb_mm:
+/*IC7*/ rdpr %pstate, %g5
+ andn %g5, PSTATE_IE, %g2
+ wrpr %g2, 0x0, %pstate
+ wrpr %g0, 1, %tl
+ mov PRIMARY_CONTEXT, %o2
+ mov 0x40, %g3
+ ldxa [%o2] ASI_DMMU, %g2
+ stxa %o0, [%o2] ASI_DMMU
+/*IC8*/ stxa %g0, [%g3] ASI_DMMU_DEMAP
+ stxa %g0, [%g3] ASI_IMMU_DEMAP
+ stxa %g2, [%o2] ASI_DMMU
+ flush %g6
+ wrpr %g0, 0, %tl
+ retl
+ wrpr %g5, 0x0, %pstate
+ nop
+__flush_tlb_range: /* %o0=(ctx&TAG_CONTEXT_BITS), %o1=start&PAGE_MASK, %o2=SECONDARY_CONTEXT,
* %o3=end&PAGE_MASK, %o4=PAGE_SIZE, %o5=(end - start)
*/
+/*IC9*/ BRANCH_IF_CHEETAH(g2, g3, __cheetah_flush_tlb_range)
+__spitfire_flush_tlb_range:
#define TLB_MAGIC 207 /* Students, do you know how I calculated this? -DaveM */
-/*IC3*/ cmp %o5, %o4
+/*IC10*/cmp %o5, %o4
bleu,pt %xcc, __flush_tlb_page
- srlx %o5, 13, %g5
+ srlx %o5, PAGE_SHIFT, %g5
cmp %g5, TLB_MAGIC
- bgeu,pn %icc, __flush_tlb_range_constant_time
+ bgeu,pn %icc, __spitfire_flush_tlb_range_constant_time
or %o1, 0x10, %g5
ldxa [%o2] ASI_DMMU, %g2
cmp %g2, %o0
-__flush_tlb_range_page_by_page:
-/*IC4*/ bne,pn %icc, __flush_tlb_range_pbp_slow
+__spitfire_flush_tlb_range_page_by_page:
+/*IC11*/bne,pn %icc, __spitfire_flush_tlb_range_pbp_slow
sub %o5, %o4, %o5
1: stxa %g0, [%g5 + %o5] ASI_DMMU_DEMAP
stxa %g0, [%g5 + %o5] ASI_IMMU_DEMAP
@@ -55,10 +112,11 @@
sub %o5, %o4, %o5
retl
flush %g6
-__flush_tlb_range_constant_time: /* %o0=ctx, %o1=start, %o3=end */
-/*IC5*/ rdpr %pstate, %g1
+__spitfire_flush_tlb_range_constant_time: /* %o0=ctx, %o1=start, %o3=end */
+/*IC12*/rdpr %pstate, %g1
wrpr %g1, PSTATE_IE, %pstate
mov TLB_TAG_ACCESS, %g3
+ /* XXX Spitfire dependency... */
mov (62 << 3), %g2
/* Spitfire Errata #32 workaround. */
@@ -67,18 +125,18 @@
flush %g6
1: ldxa [%g2] ASI_ITLB_TAG_READ, %o4
- and %o4, 0x3ff, %o5
+ and %o4, TAG_CONTEXT_BITS, %o5
cmp %o5, %o0
bne,pt %icc, 2f
-/*IC6*/ andn %o4, 0x3ff, %o4
+/*IC13*/ andn %o4, TAG_CONTEXT_BITS, %o4
cmp %o4, %o1
blu,pt %xcc, 2f
cmp %o4, %o3
blu,pn %xcc, 4f
2: ldxa [%g2] ASI_DTLB_TAG_READ, %o4
- and %o4, 0x3ff, %o5
+ and %o4, TAG_CONTEXT_BITS, %o5
cmp %o5, %o0
-/*IC7*/ andn %o4, 0x3ff, %o4
+/*IC14*/andn %o4, TAG_CONTEXT_BITS, %o4
bne,pt %icc, 3f
cmp %o4, %o1
blu,pt %xcc, 3f
@@ -86,7 +144,7 @@
blu,pn %xcc, 5f
nop
3: brnz,pt %g2, 1b
-/*IC8*/ sub %g2, (1 << 3), %g2
+/*IC15*/ sub %g2, (1 << 3), %g2
retl
wrpr %g1, 0x0, %pstate
4: stxa %g0, [%g3] ASI_IMMU
@@ -102,7 +160,7 @@
nop
5: stxa %g0, [%g3] ASI_DMMU
-/*IC9*/ stxa %g0, [%g2] ASI_DTLB_DATA_ACCESS
+/*IC16*/stxa %g0, [%g2] ASI_DTLB_DATA_ACCESS
flush %g6
/* Spitfire Errata #32 workaround. */
@@ -114,46 +172,81 @@
nop
.align 32
-__flush_tlb_mm_slow:
-/*IC10*/rdpr %pstate, %g1
+__cheetah_flush_tlb_range:
+ cmp %o5, %o4
+ bleu,pt %xcc, __cheetah_flush_tlb_page
+ nop
+/*IC17*/rdpr %pstate, %g5
+ andn %g5, PSTATE_IE, %g2
+ wrpr %g2, 0x0, %pstate
+ wrpr %g0, 1, %tl
+ mov PRIMARY_CONTEXT, %o2
+ sub %o5, %o4, %o5
+ ldxa [%o2] ASI_DMMU, %g2
+ stxa %o0, [%o2] ASI_DMMU
+
+/*IC18*/
+1: stxa %g0, [%o1 + %o5] ASI_DMMU_DEMAP
+ stxa %g0, [%o1 + %o5] ASI_IMMU_DEMAP
+ membar #Sync
+ brnz,pt %o5, 1b
+ sub %o5, %o4, %o5
+
+ stxa %g2, [%o2] ASI_DMMU
+ flush %g6
+ wrpr %g0, 0, %tl
+ retl
+/*IC19*/ wrpr %g5, 0x0, %pstate
+
+__spitfire_flush_tlb_mm_slow:
+ rdpr %pstate, %g1
wrpr %g1, PSTATE_IE, %pstate
stxa %o0, [%o1] ASI_DMMU
stxa %g0, [%g3] ASI_DMMU_DEMAP
stxa %g0, [%g3] ASI_IMMU_DEMAP
flush %g6
stxa %g2, [%o1] ASI_DMMU
- flush %g6
-/*IC11*/retl
+/*IC18*/flush %g6
+ retl
wrpr %g1, 0, %pstate
- .align 32
-__flush_tlb_page_slow:
-/*IC12*/rdpr %pstate, %g1
+__spitfire_flush_tlb_page_slow:
+ rdpr %pstate, %g1
wrpr %g1, PSTATE_IE, %pstate
stxa %o0, [%o2] ASI_DMMU
stxa %g0, [%g3] ASI_DMMU_DEMAP
stxa %g0, [%g3] ASI_IMMU_DEMAP
- flush %g6
+/*IC20*/flush %g6
stxa %g2, [%o2] ASI_DMMU
flush %g6
-/*IC13*/retl
+ retl
wrpr %g1, 0, %pstate
- .align 32
-__flush_tlb_range_pbp_slow:
-/*IC13*/rdpr %pstate, %g1
+__spitfire_flush_tlb_range_pbp_slow:
+ rdpr %pstate, %g1
wrpr %g1, PSTATE_IE, %pstate
stxa %o0, [%o2] ASI_DMMU
+/*IC21*/
2: stxa %g0, [%g5 + %o5] ASI_DMMU_DEMAP
stxa %g0, [%g5 + %o5] ASI_IMMU_DEMAP
brnz,pt %o5, 2b
sub %o5, %o4, %o5
flush %g6
-/*IC14*/stxa %g2, [%o2] ASI_DMMU
+ stxa %g2, [%o2] ASI_DMMU
flush %g6
retl
- wrpr %g1, 0x0, %pstate
+/*IC22*/ wrpr %g1, 0x0, %pstate
+/*
+ * The following code flushes one page_size worth.
+ */
+#if (PAGE_SHIFT == 13)
+#define ITAG_MASK 0xfe
+#elif (PAGE_SHIFT == 16)
+#define ITAG_MASK 0x7fe
+#else
+#error unsupported PAGE_SIZE
+#endif
.align 32
.globl __flush_icache_page
__flush_icache_page: /* %o0 = phys_page */
@@ -167,7 +260,7 @@
or %o0, %g1, %o0 ! VALID+phys-addr comparitor
sllx %g2, 1, %g2
- andn %g2, 0xfe, %g2 ! IC_tag mask
+ andn %g2, ITAG_MASK, %g2 ! IC_tag mask
nop
nop
nop
@@ -210,6 +303,37 @@
.globl __flush_dcache_page
__flush_dcache_page: /* %o0=kaddr, %o1=flush_icache */
sub %o0, %g4, %o0
+
+ rdpr %ver, %g1
+ sethi %hi(0x003e0014), %g2
+ srlx %g1, 32, %g1
+ or %g2, %lo(0x003e0014), %g2
+ cmp %g1, %g2
+ bne,pt %icc, flush_dcpage_spitfire
+ nop
+
+flush_dcpage_cheetah:
+ sethi %hi(PAGE_SIZE), %o4
+1: subcc %o4, (1 << 5), %o4
+ stxa %g0, [%o0 + %o4] ASI_DCACHE_INVALIDATE
+ bne,pt %icc, 1b
+ nop
+ membar #Sync
+ /* I-cache flush never needed on Cheetah, see callers. */
+ retl
+ nop
+
+#if (PAGE_SHIFT == 13)
+#define DTAG_MASK 0x3
+#elif (PAGE_SHIFT == 16)
+#define DTAG_MASK 0x1f
+#elif (PAGE_SHIFT == 19)
+#define DTAG_MASK 0xff
+#elif (PAGE_SHIFT == 22)
+#define DTAG_MASK 0x3ff
+#endif
+
+flush_dcpage_spitfire:
clr %o4
srlx %o0, 11, %o0
sethi %hi(1 << 14), %o2
@@ -219,19 +343,19 @@
add %o4, (1 << 5), %o4 ! IEU0
ldxa [%o4] ASI_DCACHE_TAG, %g2 ! LSU Group o3 available
add %o4, (1 << 5), %o4 ! IEU0
- andn %o3, 0x3, %o3 ! IEU1
+ andn %o3, DTAG_MASK, %o3 ! IEU1
ldxa [%o4] ASI_DCACHE_TAG, %g3 ! LSU Group
add %o4, (1 << 5), %o4 ! IEU0
- andn %g1, 0x3, %g1 ! IEU1
+ andn %g1, DTAG_MASK, %g1 ! IEU1
cmp %o0, %o3 ! IEU1 Group
be,a,pn %xcc, dflush1 ! CTI
sub %o4, (4 << 5), %o4 ! IEU0 (Group)
cmp %o0, %g1 ! IEU1 Group
- andn %g2, 0x3, %g2 ! IEU0
+ andn %g2, DTAG_MASK, %g2 ! IEU0
be,a,pn %xcc, dflush2 ! CTI
sub %o4, (3 << 5), %o4 ! IEU0 (Group)
cmp %o0, %g2 ! IEU1 Group
- andn %g3, 0x3, %g3 ! IEU0
+ andn %g3, DTAG_MASK, %g3 ! IEU0
be,a,pn %xcc, dflush3 ! CTI
sub %o4, (2 << 5), %o4 ! IEU0 (Group)
cmp %o0, %g3 ! IEU1 Group
@@ -284,14 +408,14 @@
.globl __update_mmu_cache
__update_mmu_cache: /* %o0=vma, %o1=address, %o2=pte */
ldub [%g6 + AOFF_task_thread + AOFF_thread_fault_code], %o3
- srlx %o1, 13, %o1
+ srlx %o1, PAGE_SHIFT, %o1
ldx [%o0 + 0x0], %o4 /* XXX vma->vm_mm */
brz,pn %o3, 1f
- sllx %o1, 13, %o0
+ sllx %o1, PAGE_SHIFT, %o0
ldx [%o4 + AOFF_mm_context], %o5
andcc %o3, FAULT_CODE_DTLB, %g0
mov %o2, %o1
- and %o5, 0x3ff, %o5
+ and %o5, TAG_CONTEXT_BITS, %o5
bne,pt %xcc, __prefill_dtlb
or %o0, %o5, %o0
ba,a,pt %xcc, __prefill_itlb
@@ -317,18 +441,18 @@
.align 32
.globl xcall_flush_tlb_page, xcall_flush_tlb_mm, xcall_flush_tlb_range
xcall_flush_tlb_page:
- mov SECONDARY_CONTEXT, %g2
- or %g1, 0x10, %g4
+ mov PRIMARY_CONTEXT, %g2
ldxa [%g2] ASI_DMMU, %g3
stxa %g5, [%g2] ASI_DMMU
- stxa %g0, [%g4] ASI_DMMU_DEMAP
- stxa %g0, [%g4] ASI_IMMU_DEMAP
+ stxa %g0, [%g1] ASI_DMMU_DEMAP
+ stxa %g0, [%g1] ASI_IMMU_DEMAP
stxa %g3, [%g2] ASI_DMMU
retry
+ nop
xcall_flush_tlb_mm:
- mov SECONDARY_CONTEXT, %g2
- mov 0x50, %g4
+ mov PRIMARY_CONTEXT, %g2
+ mov 0x40, %g4
ldxa [%g2] ASI_DMMU, %g3
stxa %g5, [%g2] ASI_DMMU
stxa %g0, [%g4] ASI_DMMU_DEMAP
@@ -337,26 +461,27 @@
retry
xcall_flush_tlb_range:
- sethi %hi(8192 - 1), %g2
- or %g2, %lo(8192 - 1), %g2
+ sethi %hi(PAGE_SIZE - 1), %g2
+ or %g2, %lo(PAGE_SIZE - 1), %g2
andn %g1, %g2, %g1
andn %g7, %g2, %g7
sub %g7, %g1, %g3
add %g2, 1, %g2
- orcc %g1, 0x10, %g1
- srlx %g3, 13, %g4
-
+ srlx %g3, PAGE_SHIFT, %g4
cmp %g4, 96
+
bgu,pn %icc, xcall_flush_tlb_mm
- mov SECONDARY_CONTEXT, %g4
+ mov PRIMARY_CONTEXT, %g4
ldxa [%g4] ASI_DMMU, %g7
sub %g3, %g2, %g3
stxa %g5, [%g4] ASI_DMMU
nop
nop
+ nop
1: stxa %g0, [%g1 + %g3] ASI_DMMU_DEMAP
stxa %g0, [%g1 + %g3] ASI_IMMU_DEMAP
+ membar #Sync
brnz,pt %g3, 1b
sub %g3, %g2, %g3
stxa %g7, [%g4] ASI_DMMU
@@ -378,6 +503,53 @@
b,pt %xcc, rtrap
clr %l6
+ .align 32
+ .globl xcall_flush_dcache_page_cheetah
+xcall_flush_dcache_page_cheetah: /* %g1 == physical page address */
+ sethi %hi(PAGE_SIZE), %g3
+1: subcc %g3, (1 << 5), %g3
+ stxa %g0, [%g1 + %g3] ASI_DCACHE_INVALIDATE
+ bne,pt %icc, 1b
+ nop
+ membar #Sync
+ retry
+ nop
+
+ .globl xcall_flush_dcache_page_spitfire
+xcall_flush_dcache_page_spitfire: /* %g1 == physical page address
+ %g7 == kernel page virtual address
+ %g5 == (page->mapping != NULL) */
+#if (L1DCACHE_SIZE > PAGE_SIZE)
+ srlx %g1, (13 - 2), %g1 ! Form tag comparitor
+ sethi %hi(L1DCACHE_SIZE), %g3 ! D$ size == 16K
+ sub %g3, (1 << 5), %g3 ! D$ linesize == 32
+1: ldxa [%g3] ASI_DCACHE_TAG, %g2
+ andcc %g2, 0x3, %g0
+ be,pn %xcc, 2f
+ andn %g2, 0x3, %g2
+ cmp %g2, %g1
+
+ bne,pt %xcc, 2f
+ nop
+ stxa %g0, [%g3] ASI_DCACHE_TAG
+ membar #Sync
+2: cmp %g3, 0
+ bne,pt %xcc, 1b
+ sub %g3, (1 << 5), %g3
+
+ brz,pn %g5, 2f
+#endif /* L1DCACHE_SIZE > PAGE_SIZE */
+ sethi %hi(PAGE_SIZE), %g3
+
+1: flush %g7
+ subcc %g3, (1 << 5), %g3
+ bne,pt %icc, 1b
+ add %g7, (1 << 5), %g7
+
+2: retry
+ nop
+ nop
+
.globl xcall_capture
xcall_capture:
rdpr %pstate, %g2
@@ -433,7 +605,8 @@
/* These two are not performance critical... */
.globl xcall_flush_tlb_all
xcall_flush_tlb_all:
-
+ BRANCH_IF_CHEETAH(g2, g3, __cheetah_xcall_flush_tlb_all)
+__spitfire_xcall_flush_tlb_all:
/* Spitfire Errata #32 workaround. */
sethi %hi(errata32_hwbug), %g4
stx %g0, [%g4 + %lo(errata32_hwbug)]
@@ -475,17 +648,33 @@
flush %g6
retry
+__cheetah_xcall_flush_tlb_all:
+ mov 0x80, %g2
+ stxa %g0, [%g2] ASI_DMMU_DEMAP
+ stxa %g0, [%g2] ASI_IMMU_DEMAP
+ retry
+
.globl xcall_flush_cache_all
xcall_flush_cache_all:
+ BRANCH_IF_CHEETAH(g2, g3, __cheetah_xcall_flush_cache_all)
+__spitfire_xcall_flush_cache_all:
sethi %hi(16383), %g2
or %g2, %lo(16383), %g2
clr %g3
1: stxa %g0, [%g3] ASI_IC_TAG
+ membar #Sync
add %g3, 32, %g3
cmp %g3, %g2
bleu,pt %xcc, 1b
nop
flush %g6
+ retry
+
+ /* Cheetah's caches are fully coherent in the sense that
+ * caches are flushed here. We need to verify this and
+ * really just not even send out the xcall at the top level.
+ */
+__cheetah_xcall_flush_cache_all:
retry
.globl xcall_call_function
|