summaryrefslogtreecommitdiff
path: root/arch/sparc/mm
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sparc/mm')
-rw-r--r--arch/sparc/mm/Makefile12
-rw-r--r--arch/sparc/mm/btfixup.c328
-rw-r--r--arch/sparc/mm/fault_32.c207
-rw-r--r--arch/sparc/mm/init_32.c51
-rw-r--r--arch/sparc/mm/init_64.c121
-rw-r--r--arch/sparc/mm/io-unit.c35
-rw-r--r--arch/sparc/mm/iommu.c71
-rw-r--r--arch/sparc/mm/leon_mm.c97
-rw-r--r--arch/sparc/mm/loadmmu.c43
-rw-r--r--arch/sparc/mm/nosun4c.c77
-rw-r--r--arch/sparc/mm/srmmu.c1278
-rw-r--r--arch/sparc/mm/srmmu.h4
-rw-r--r--arch/sparc/mm/srmmu_access.S82
-rw-r--r--arch/sparc/mm/sun4c.c2166
-rw-r--r--arch/sparc/mm/ultra.S6
-rw-r--r--arch/sparc/mm/viking.S1
16 files changed, 629 insertions, 3950 deletions
diff --git a/arch/sparc/mm/Makefile b/arch/sparc/mm/Makefile
index 301421c11291..30c3eccfdf5a 100644
--- a/arch/sparc/mm/Makefile
+++ b/arch/sparc/mm/Makefile
@@ -7,19 +7,13 @@ ccflags-y := -Werror
obj-$(CONFIG_SPARC64) += ultra.o tlb.o tsb.o gup.o
obj-y += fault_$(BITS).o
obj-y += init_$(BITS).o
-obj-$(CONFIG_SPARC32) += loadmmu.o
-obj-$(CONFIG_SPARC32) += extable.o btfixup.o srmmu.o iommu.o io-unit.o
+obj-$(CONFIG_SPARC32) += extable.o srmmu.o iommu.o io-unit.o
+obj-$(CONFIG_SPARC32) += srmmu_access.o
obj-$(CONFIG_SPARC32) += hypersparc.o viking.o tsunami.o swift.o
-obj-$(CONFIG_SPARC_LEON)+= leon_mm.o
+obj-$(CONFIG_SPARC32) += leon_mm.o
# Only used by sparc64
obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o
# Only used by sparc32
obj-$(CONFIG_HIGHMEM) += highmem.o
-
-ifdef CONFIG_SMP
-obj-$(CONFIG_SPARC32) += nosun4c.o
-else
-obj-$(CONFIG_SPARC32) += sun4c.o
-endif
diff --git a/arch/sparc/mm/btfixup.c b/arch/sparc/mm/btfixup.c
deleted file mode 100644
index 09d6af22db2d..000000000000
--- a/arch/sparc/mm/btfixup.c
+++ /dev/null
@@ -1,328 +0,0 @@
-/* btfixup.c: Boot time code fixup and relocator, so that
- * we can get rid of most indirect calls to achieve single
- * image sun4c and srmmu kernel.
- *
- * Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <asm/btfixup.h>
-#include <asm/page.h>
-#include <asm/pgalloc.h>
-#include <asm/pgtable.h>
-#include <asm/oplib.h>
-#include <asm/cacheflush.h>
-
-#define BTFIXUP_OPTIMIZE_NOP
-#define BTFIXUP_OPTIMIZE_OTHER
-
-extern char *srmmu_name;
-static char version[] __initdata = "Boot time fixup v1.6. 4/Mar/98 Jakub Jelinek (jj@ultra.linux.cz). Patching kernel for ";
-static char str_sun4c[] __initdata = "sun4c\n";
-static char str_srmmu[] __initdata = "srmmu[%s]/";
-static char str_iommu[] __initdata = "iommu\n";
-static char str_iounit[] __initdata = "io-unit\n";
-
-static int visited __initdata = 0;
-extern unsigned int ___btfixup_start[], ___btfixup_end[], __init_begin[], __init_end[], __init_text_end[];
-extern unsigned int _stext[], _end[], __start___ksymtab[], __stop___ksymtab[];
-static char wrong_f[] __initdata = "Trying to set f fixup %p to invalid function %08x\n";
-static char wrong_b[] __initdata = "Trying to set b fixup %p to invalid function %08x\n";
-static char wrong_s[] __initdata = "Trying to set s fixup %p to invalid value %08x\n";
-static char wrong_h[] __initdata = "Trying to set h fixup %p to invalid value %08x\n";
-static char wrong_a[] __initdata = "Trying to set a fixup %p to invalid value %08x\n";
-static char wrong[] __initdata = "Wrong address for %c fixup %p\n";
-static char insn_f[] __initdata = "Fixup f %p refers to weird instructions at %p[%08x,%08x]\n";
-static char insn_b[] __initdata = "Fixup b %p doesn't refer to a SETHI at %p[%08x]\n";
-static char insn_s[] __initdata = "Fixup s %p doesn't refer to an OR at %p[%08x]\n";
-static char insn_h[] __initdata = "Fixup h %p doesn't refer to a SETHI at %p[%08x]\n";
-static char insn_a[] __initdata = "Fixup a %p doesn't refer to a SETHI nor OR at %p[%08x]\n";
-static char insn_i[] __initdata = "Fixup i %p doesn't refer to a valid instruction at %p[%08x]\n";
-static char fca_und[] __initdata = "flush_cache_all undefined in btfixup()\n";
-static char wrong_setaddr[] __initdata = "Garbled CALL/INT patch at %p[%08x,%08x,%08x]=%08x\n";
-
-#ifdef BTFIXUP_OPTIMIZE_OTHER
-static void __init set_addr(unsigned int *addr, unsigned int q1, int fmangled, unsigned int value)
-{
- if (!fmangled)
- *addr = value;
- else {
- unsigned int *q = (unsigned int *)q1;
- if (*addr == 0x01000000) {
- /* Noped */
- *q = value;
- } else if (addr[-1] == *q) {
- /* Moved */
- addr[-1] = value;
- *q = value;
- } else {
- prom_printf(wrong_setaddr, addr-1, addr[-1], *addr, *q, value);
- prom_halt();
- }
- }
-}
-#else
-static inline void set_addr(unsigned int *addr, unsigned int q1, int fmangled, unsigned int value)
-{
- *addr = value;
-}
-#endif
-
-void __init btfixup(void)
-{
- unsigned int *p, *q;
- int type, count;
- unsigned insn;
- unsigned *addr;
- int fmangled = 0;
- void (*flush_cacheall)(void);
-
- if (!visited) {
- visited++;
- printk(version);
- if (ARCH_SUN4C)
- printk(str_sun4c);
- else {
- printk(str_srmmu, srmmu_name);
- if (sparc_cpu_model == sun4d)
- printk(str_iounit);
- else
- printk(str_iommu);
- }
- }
- for (p = ___btfixup_start; p < ___btfixup_end; ) {
- count = p[2];
- q = p + 3;
- switch (type = *(unsigned char *)p) {
- case 'f':
- count = p[3];
- q = p + 4;
- if (((p[0] & 1) || p[1])
- && ((p[1] & 3) || (unsigned *)(p[1]) < _stext || (unsigned *)(p[1]) >= _end)) {
- prom_printf(wrong_f, p, p[1]);
- prom_halt();
- }
- break;
- case 'b':
- if (p[1] < (unsigned long)__init_begin || p[1] >= (unsigned long)__init_text_end || (p[1] & 3)) {
- prom_printf(wrong_b, p, p[1]);
- prom_halt();
- }
- break;
- case 's':
- if (p[1] + 0x1000 >= 0x2000) {
- prom_printf(wrong_s, p, p[1]);
- prom_halt();
- }
- break;
- case 'h':
- if (p[1] & 0x3ff) {
- prom_printf(wrong_h, p, p[1]);
- prom_halt();
- }
- break;
- case 'a':
- if (p[1] + 0x1000 >= 0x2000 && (p[1] & 0x3ff)) {
- prom_printf(wrong_a, p, p[1]);
- prom_halt();
- }
- break;
- }
- if (p[0] & 1) {
- p[0] &= ~1;
- while (count) {
- fmangled = 0;
- addr = (unsigned *)*q;
- if (addr < _stext || addr >= _end) {
- prom_printf(wrong, type, p);
- prom_halt();
- }
- insn = *addr;
-#ifdef BTFIXUP_OPTIMIZE_OTHER
- if (type != 'f' && q[1]) {
- insn = *(unsigned int *)q[1];
- if (!insn || insn == 1)
- insn = *addr;
- else
- fmangled = 1;
- }
-#endif
- switch (type) {
- case 'f': /* CALL */
- if (addr >= __start___ksymtab && addr < __stop___ksymtab) {
- *addr = p[1];
- break;
- } else if (!q[1]) {
- if ((insn & 0xc1c00000) == 0x01000000) { /* SETHI */
- *addr = (insn & 0xffc00000) | (p[1] >> 10); break;
- } else if ((insn & 0xc1f82000) == 0x80102000) { /* OR X, %LO(i), Y */
- *addr = (insn & 0xffffe000) | (p[1] & 0x3ff); break;
- } else if ((insn & 0xc0000000) != 0x40000000) { /* !CALL */
- bad_f:
- prom_printf(insn_f, p, addr, insn, addr[1]);
- prom_halt();
- }
- } else if (q[1] != 1)
- addr[1] = q[1];
- if (p[2] == BTFIXUPCALL_NORM) {
- norm_f:
- *addr = 0x40000000 | ((p[1] - (unsigned)addr) >> 2);
- q[1] = 0;
- break;
- }
-#ifndef BTFIXUP_OPTIMIZE_NOP
- goto norm_f;
-#else
- if (!(addr[1] & 0x80000000)) {
- if ((addr[1] & 0xc1c00000) != 0x01000000) /* !SETHI */
- goto bad_f; /* CALL, Bicc, FBfcc, CBccc are weird in delay slot, aren't they? */
- } else {
- if ((addr[1] & 0x01800000) == 0x01800000) {
- if ((addr[1] & 0x01f80000) == 0x01e80000) {
- /* RESTORE */
- goto norm_f; /* It is dangerous to patch that */
- }
- goto bad_f;
- }
- if ((addr[1] & 0xffffe003) == 0x9e03e000) {
- /* ADD %O7, XX, %o7 */
- int displac = (addr[1] << 19);
-
- displac = (displac >> 21) + 2;
- *addr = (0x10800000) + (displac & 0x3fffff);
- q[1] = addr[1];
- addr[1] = p[2];
- break;
- }
- if ((addr[1] & 0x201f) == 0x200f || (addr[1] & 0x7c000) == 0x3c000)
- goto norm_f; /* Someone is playing bad tricks with us: rs1 or rs2 is o7 */
- if ((addr[1] & 0x3e000000) == 0x1e000000)
- goto norm_f; /* rd is %o7. We'd better take care. */
- }
- if (p[2] == BTFIXUPCALL_NOP) {
- *addr = 0x01000000;
- q[1] = 1;
- break;
- }
-#ifndef BTFIXUP_OPTIMIZE_OTHER
- goto norm_f;
-#else
- if (addr[1] == 0x01000000) { /* NOP in the delay slot */
- q[1] = addr[1];
- *addr = p[2];
- break;
- }
- if ((addr[1] & 0xc0000000) != 0xc0000000) {
- /* Not a memory operation */
- if ((addr[1] & 0x30000000) == 0x10000000) {
- /* Ok, non-memory op with rd %oX */
- if ((addr[1] & 0x3e000000) == 0x1c000000)
- goto bad_f; /* Aiee. Someone is playing strange %sp tricks */
- if ((addr[1] & 0x3e000000) > 0x12000000 ||
- ((addr[1] & 0x3e000000) == 0x12000000 &&
- p[2] != BTFIXUPCALL_STO1O0 && p[2] != BTFIXUPCALL_SWAPO0O1) ||
- ((p[2] & 0xffffe000) == BTFIXUPCALL_RETINT(0))) {
- /* Nobody uses the result. We can nop it out. */
- *addr = p[2];
- q[1] = addr[1];
- addr[1] = 0x01000000;
- break;
- }
- if ((addr[1] & 0xf1ffffe0) == 0x90100000) {
- /* MOV %reg, %Ox */
- if ((addr[1] & 0x3e000000) == 0x10000000 &&
- (p[2] & 0x7c000) == 0x20000) {
- /* Ok, it is call xx; mov reg, %o0 and call optimizes
- to doing something on %o0. Patch the patch. */
- *addr = (p[2] & ~0x7c000) | ((addr[1] & 0x1f) << 14);
- q[1] = addr[1];
- addr[1] = 0x01000000;
- break;
- }
- if ((addr[1] & 0x3e000000) == 0x12000000 &&
- p[2] == BTFIXUPCALL_STO1O0) {
- *addr = (p[2] & ~0x3e000000) | ((addr[1] & 0x1f) << 25);
- q[1] = addr[1];
- addr[1] = 0x01000000;
- break;
- }
- }
- }
- }
- *addr = addr[1];
- q[1] = addr[1];
- addr[1] = p[2];
- break;
-#endif /* BTFIXUP_OPTIMIZE_OTHER */
-#endif /* BTFIXUP_OPTIMIZE_NOP */
- case 'b': /* BLACKBOX */
- /* Has to be sethi i, xx */
- if ((insn & 0xc1c00000) != 0x01000000) {
- prom_printf(insn_b, p, addr, insn);
- prom_halt();
- } else {
- void (*do_fixup)(unsigned *);
-
- do_fixup = (void (*)(unsigned *))p[1];
- do_fixup(addr);
- }
- break;
- case 's': /* SIMM13 */
- /* Has to be or %g0, i, xx */
- if ((insn & 0xc1ffe000) != 0x80102000) {
- prom_printf(insn_s, p, addr, insn);
- prom_halt();
- }
- set_addr(addr, q[1], fmangled, (insn & 0xffffe000) | (p[1] & 0x1fff));
- break;
- case 'h': /* SETHI */
- /* Has to be sethi i, xx */
- if ((insn & 0xc1c00000) != 0x01000000) {
- prom_printf(insn_h, p, addr, insn);
- prom_halt();
- }
- set_addr(addr, q[1], fmangled, (insn & 0xffc00000) | (p[1] >> 10));
- break;
- case 'a': /* HALF */
- /* Has to be sethi i, xx or or %g0, i, xx */
- if ((insn & 0xc1c00000) != 0x01000000 &&
- (insn & 0xc1ffe000) != 0x80102000) {
- prom_printf(insn_a, p, addr, insn);
- prom_halt();
- }
- if (p[1] & 0x3ff)
- set_addr(addr, q[1], fmangled,
- (insn & 0x3e000000) | 0x80102000 | (p[1] & 0x1fff));
- else
- set_addr(addr, q[1], fmangled,
- (insn & 0x3e000000) | 0x01000000 | (p[1] >> 10));
- break;
- case 'i': /* INT */
- if ((insn & 0xc1c00000) == 0x01000000) /* %HI */
- set_addr(addr, q[1], fmangled, (insn & 0xffc00000) | (p[1] >> 10));
- else if ((insn & 0x80002000) == 0x80002000) /* %LO */
- set_addr(addr, q[1], fmangled, (insn & 0xffffe000) | (p[1] & 0x3ff));
- else {
- prom_printf(insn_i, p, addr, insn);
- prom_halt();
- }
- break;
- }
- count -= 2;
- q += 2;
- }
- } else
- p = q + count;
- }
-#ifdef CONFIG_SMP
- flush_cacheall = (void (*)(void))BTFIXUPVAL_CALL(local_flush_cache_all);
-#else
- flush_cacheall = (void (*)(void))BTFIXUPVAL_CALL(flush_cache_all);
-#endif
- if (!flush_cacheall) {
- prom_printf(fca_und);
- prom_halt();
- }
- (*flush_cacheall)();
-}
diff --git a/arch/sparc/mm/fault_32.c b/arch/sparc/mm/fault_32.c
index df3155a17991..f46cf6be3370 100644
--- a/arch/sparc/mm/fault_32.c
+++ b/arch/sparc/mm/fault_32.c
@@ -24,29 +24,19 @@
#include <asm/page.h>
#include <asm/pgtable.h>
-#include <asm/memreg.h>
#include <asm/openprom.h>
#include <asm/oplib.h>
#include <asm/smp.h>
#include <asm/traps.h>
#include <asm/uaccess.h>
-extern int prom_node_root;
-
int show_unhandled_signals = 1;
/* At boot time we determine these two values necessary for setting
* up the segment maps and page table entries (pte's).
*/
-int num_segmaps, num_contexts;
-int invalid_segment;
-
-/* various Virtual Address Cache parameters we find at boot time... */
-
-int vac_size, vac_linesize, vac_do_hw_vac_flushes;
-int vac_entries_per_context, vac_entries_per_segment;
-int vac_entries_per_page;
+int num_contexts;
/* Return how much physical memory we have. */
unsigned long probe_memory(void)
@@ -60,55 +50,36 @@ unsigned long probe_memory(void)
return total;
}
-extern void sun4c_complete_all_stores(void);
-
-/* Whee, a level 15 NMI interrupt memory error. Let's have fun... */
-asmlinkage void sparc_lvl15_nmi(struct pt_regs *regs, unsigned long serr,
- unsigned long svaddr, unsigned long aerr,
- unsigned long avaddr)
-{
- sun4c_complete_all_stores();
- printk("FAULT: NMI received\n");
- printk("SREGS: Synchronous Error %08lx\n", serr);
- printk(" Synchronous Vaddr %08lx\n", svaddr);
- printk(" Asynchronous Error %08lx\n", aerr);
- printk(" Asynchronous Vaddr %08lx\n", avaddr);
- if (sun4c_memerr_reg)
- printk(" Memory Parity Error %08lx\n", *sun4c_memerr_reg);
- printk("REGISTER DUMP:\n");
- show_regs(regs);
- prom_halt();
-}
-
static void unhandled_fault(unsigned long, struct task_struct *,
struct pt_regs *) __attribute__ ((noreturn));
-static void unhandled_fault(unsigned long address, struct task_struct *tsk,
- struct pt_regs *regs)
+static void __noreturn unhandled_fault(unsigned long address,
+ struct task_struct *tsk,
+ struct pt_regs *regs)
{
- if((unsigned long) address < PAGE_SIZE) {
+ if ((unsigned long) address < PAGE_SIZE) {
printk(KERN_ALERT
"Unable to handle kernel NULL pointer dereference\n");
} else {
- printk(KERN_ALERT "Unable to handle kernel paging request "
- "at virtual address %08lx\n", address);
+ printk(KERN_ALERT "Unable to handle kernel paging request at virtual address %08lx\n",
+ address);
}
printk(KERN_ALERT "tsk->{mm,active_mm}->context = %08lx\n",
(tsk->mm ? tsk->mm->context : tsk->active_mm->context));
printk(KERN_ALERT "tsk->{mm,active_mm}->pgd = %08lx\n",
(tsk->mm ? (unsigned long) tsk->mm->pgd :
- (unsigned long) tsk->active_mm->pgd));
+ (unsigned long) tsk->active_mm->pgd));
die_if_kernel("Oops", regs);
}
-asmlinkage int lookup_fault(unsigned long pc, unsigned long ret_pc,
+asmlinkage int lookup_fault(unsigned long pc, unsigned long ret_pc,
unsigned long address)
{
struct pt_regs regs;
unsigned long g2;
unsigned int insn;
int i;
-
+
i = search_extables_range(ret_pc, &g2);
switch (i) {
case 3:
@@ -128,14 +99,14 @@ asmlinkage int lookup_fault(unsigned long pc, unsigned long ret_pc,
/* for _from_ macros */
insn = *((unsigned int *) pc);
if (!((insn >> 21) & 1) || ((insn>>19)&0x3f) == 15)
- return 2;
- break;
+ return 2;
+ break;
default:
break;
}
- memset(&regs, 0, sizeof (regs));
+ memset(&regs, 0, sizeof(regs));
regs.pc = pc;
regs.npc = pc + 4;
__asm__ __volatile__(
@@ -198,11 +169,10 @@ static unsigned long compute_si_addr(struct pt_regs *regs, int text_fault)
if (text_fault)
return regs->pc;
- if (regs->psr & PSR_PS) {
+ if (regs->psr & PSR_PS)
insn = *(unsigned int *) regs->pc;
- } else {
+ else
__get_user(insn, (unsigned int *) regs->pc);
- }
return safe_compute_effective_address(regs, insn);
}
@@ -228,7 +198,7 @@ asmlinkage void do_sparc_fault(struct pt_regs *regs, int text_fault, int write,
unsigned int flags = (FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE |
(write ? FAULT_FLAG_WRITE : 0));
- if(text_fault)
+ if (text_fault)
address = regs->pc;
/*
@@ -241,36 +211,32 @@ asmlinkage void do_sparc_fault(struct pt_regs *regs, int text_fault, int write,
* nothing more.
*/
code = SEGV_MAPERR;
- if (!ARCH_SUN4C && address >= TASK_SIZE)
+ if (address >= TASK_SIZE)
goto vmalloc_fault;
/*
* If we're in an interrupt or have no user
* context, we must not take the fault..
*/
- if (in_atomic() || !mm)
- goto no_context;
+ if (in_atomic() || !mm)
+ goto no_context;
perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address);
retry:
down_read(&mm->mmap_sem);
- /*
- * The kernel referencing a bad kernel pointer can lock up
- * a sun4c machine completely, so we must attempt recovery.
- */
- if(!from_user && address >= PAGE_OFFSET)
+ if (!from_user && address >= PAGE_OFFSET)
goto bad_area;
vma = find_vma(mm, address);
- if(!vma)
+ if (!vma)
goto bad_area;
- if(vma->vm_start <= address)
+ if (vma->vm_start <= address)
goto good_area;
- if(!(vma->vm_flags & VM_GROWSDOWN))
+ if (!(vma->vm_flags & VM_GROWSDOWN))
goto bad_area;
- if(expand_stack(vma, address))
+ if (expand_stack(vma, address))
goto bad_area;
/*
* Ok, we have a good vm_area for this memory access, so
@@ -278,12 +244,12 @@ retry:
*/
good_area:
code = SEGV_ACCERR;
- if(write) {
- if(!(vma->vm_flags & VM_WRITE))
+ if (write) {
+ if (!(vma->vm_flags & VM_WRITE))
goto bad_area;
} else {
/* Allow reads even for write-only mappings */
- if(!(vma->vm_flags & (VM_READ | VM_EXEC)))
+ if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
goto bad_area;
}
@@ -349,14 +315,16 @@ no_context:
g2 = regs->u_regs[UREG_G2];
if (!from_user) {
fixup = search_extables_range(regs->pc, &g2);
- if (fixup > 10) { /* Values below are reserved for other things */
+ /* Values below 10 are reserved for other things */
+ if (fixup > 10) {
extern const unsigned __memset_start[];
extern const unsigned __memset_end[];
extern const unsigned __csum_partial_copy_start[];
extern const unsigned __csum_partial_copy_end[];
#ifdef DEBUG_EXCEPTIONS
- printk("Exception: PC<%08lx> faddr<%08lx>\n", regs->pc, address);
+ printk("Exception: PC<%08lx> faddr<%08lx>\n",
+ regs->pc, address);
printk("EX_TABLE: insn<%08lx> fixup<%08x> g2<%08lx>\n",
regs->pc, fixup, g2);
#endif
@@ -364,7 +332,7 @@ no_context:
regs->pc < (unsigned long)__memset_end) ||
(regs->pc >= (unsigned long)__csum_partial_copy_start &&
regs->pc < (unsigned long)__csum_partial_copy_end)) {
- regs->u_regs[UREG_I4] = address;
+ regs->u_regs[UREG_I4] = address;
regs->u_regs[UREG_I5] = regs->pc;
}
regs->u_regs[UREG_G2] = g2;
@@ -373,8 +341,8 @@ no_context:
return;
}
}
-
- unhandled_fault (address, tsk, regs);
+
+ unhandled_fault(address, tsk, regs);
do_exit(SIGKILL);
/*
@@ -420,97 +388,12 @@ vmalloc_fault:
if (pmd_present(*pmd) || !pmd_present(*pmd_k))
goto bad_area_nosemaphore;
+
*pmd = *pmd_k;
return;
}
}
-asmlinkage void do_sun4c_fault(struct pt_regs *regs, int text_fault, int write,
- unsigned long address)
-{
- extern void sun4c_update_mmu_cache(struct vm_area_struct *,
- unsigned long,pte_t *);
- extern pte_t *sun4c_pte_offset_kernel(pmd_t *,unsigned long);
- struct task_struct *tsk = current;
- struct mm_struct *mm = tsk->mm;
- pgd_t *pgdp;
- pte_t *ptep;
-
- if (text_fault) {
- address = regs->pc;
- } else if (!write &&
- !(regs->psr & PSR_PS)) {
- unsigned int insn, __user *ip;
-
- ip = (unsigned int __user *)regs->pc;
- if (!get_user(insn, ip)) {
- if ((insn & 0xc1680000) == 0xc0680000)
- write = 1;
- }
- }
-
- if (!mm) {
- /* We are oopsing. */
- do_sparc_fault(regs, text_fault, write, address);
- BUG(); /* P3 Oops already, you bitch */
- }
-
- pgdp = pgd_offset(mm, address);
- ptep = sun4c_pte_offset_kernel((pmd_t *) pgdp, address);
-
- if (pgd_val(*pgdp)) {
- if (write) {
- if ((pte_val(*ptep) & (_SUN4C_PAGE_WRITE|_SUN4C_PAGE_PRESENT))
- == (_SUN4C_PAGE_WRITE|_SUN4C_PAGE_PRESENT)) {
- unsigned long flags;
-
- *ptep = __pte(pte_val(*ptep) | _SUN4C_PAGE_ACCESSED |
- _SUN4C_PAGE_MODIFIED |
- _SUN4C_PAGE_VALID |
- _SUN4C_PAGE_DIRTY);
-
- local_irq_save(flags);
- if (sun4c_get_segmap(address) != invalid_segment) {
- sun4c_put_pte(address, pte_val(*ptep));
- local_irq_restore(flags);
- return;
- }
- local_irq_restore(flags);
- }
- } else {
- if ((pte_val(*ptep) & (_SUN4C_PAGE_READ|_SUN4C_PAGE_PRESENT))
- == (_SUN4C_PAGE_READ|_SUN4C_PAGE_PRESENT)) {
- unsigned long flags;
-
- *ptep = __pte(pte_val(*ptep) | _SUN4C_PAGE_ACCESSED |
- _SUN4C_PAGE_VALID);
-
- local_irq_save(flags);
- if (sun4c_get_segmap(address) != invalid_segment) {
- sun4c_put_pte(address, pte_val(*ptep));
- local_irq_restore(flags);
- return;
- }
- local_irq_restore(flags);
- }
- }
- }
-
- /* This conditional is 'interesting'. */
- if (pgd_val(*pgdp) && !(write && !(pte_val(*ptep) & _SUN4C_PAGE_WRITE))
- && (pte_val(*ptep) & _SUN4C_PAGE_VALID))
- /* Note: It is safe to not grab the MMAP semaphore here because
- * we know that update_mmu_cache() will not sleep for
- * any reason (at least not in the current implementation)
- * and therefore there is no danger of another thread getting
- * on the CPU and doing a shrink_mmap() on this vma.
- */
- sun4c_update_mmu_cache (find_vma(current->mm, address), address,
- ptep);
- else
- do_sparc_fault(regs, text_fault, write, address);
-}
-
/* This always deals with user addresses. */
static void force_user_fault(unsigned long address, int write)
{
@@ -523,21 +406,21 @@ static void force_user_fault(unsigned long address, int write)
down_read(&mm->mmap_sem);
vma = find_vma(mm, address);
- if(!vma)
+ if (!vma)
goto bad_area;
- if(vma->vm_start <= address)
+ if (vma->vm_start <= address)
goto good_area;
- if(!(vma->vm_flags & VM_GROWSDOWN))
+ if (!(vma->vm_flags & VM_GROWSDOWN))
goto bad_area;
- if(expand_stack(vma, address))
+ if (expand_stack(vma, address))
goto bad_area;
good_area:
code = SEGV_ACCERR;
- if(write) {
- if(!(vma->vm_flags & VM_WRITE))
+ if (write) {
+ if (!(vma->vm_flags & VM_WRITE))
goto bad_area;
} else {
- if(!(vma->vm_flags & (VM_READ | VM_EXEC)))
+ if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
goto bad_area;
}
switch (handle_mm_fault(mm, vma, address, write ? FAULT_FLAG_WRITE : 0)) {
@@ -568,7 +451,7 @@ void window_overflow_fault(void)
unsigned long sp;
sp = current_thread_info()->rwbuf_stkptrs[0];
- if(((sp + 0x38) & PAGE_MASK) != (sp & PAGE_MASK))
+ if (((sp + 0x38) & PAGE_MASK) != (sp & PAGE_MASK))
force_user_fault(sp + 0x38, 1);
force_user_fault(sp, 1);
@@ -577,7 +460,7 @@ void window_overflow_fault(void)
void window_underflow_fault(unsigned long sp)
{
- if(((sp + 0x38) & PAGE_MASK) != (sp & PAGE_MASK))
+ if (((sp + 0x38) & PAGE_MASK) != (sp & PAGE_MASK))
force_user_fault(sp + 0x38, 0);
force_user_fault(sp, 0);
@@ -589,7 +472,7 @@ void window_ret_fault(struct pt_regs *regs)
unsigned long sp;
sp = regs->u_regs[UREG_FP];
- if(((sp + 0x38) & PAGE_MASK) != (sp & PAGE_MASK))
+ if (((sp + 0x38) & PAGE_MASK) != (sp & PAGE_MASK))
force_user_fault(sp + 0x38, 0);
force_user_fault(sp, 0);
diff --git a/arch/sparc/mm/init_32.c b/arch/sparc/mm/init_32.c
index c5f9021b1a01..ef5c779ec855 100644
--- a/arch/sparc/mm/init_32.c
+++ b/arch/sparc/mm/init_32.c
@@ -27,7 +27,6 @@
#include <linux/gfp.h>
#include <asm/sections.h>
-#include <asm/vac-ops.h>
#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm/vaddrs.h>
@@ -45,9 +44,6 @@ EXPORT_SYMBOL(phys_base);
unsigned long pfn_base;
EXPORT_SYMBOL(pfn_base);
-unsigned long page_kernel;
-EXPORT_SYMBOL(page_kernel);
-
struct sparc_phys_banks sp_banks[SPARC_PHYS_BANKS+1];
unsigned long sparc_unmapped_base;
@@ -287,44 +283,16 @@ unsigned long __init bootmem_init(unsigned long *pages_avail)
}
/*
- * check_pgt_cache
- *
- * This is called at the end of unmapping of VMA (zap_page_range),
- * to rescan the page cache for architecture specific things,
- * presumably something like sun4/sun4c PMEGs. Most architectures
- * define check_pgt_cache empty.
- *
- * We simply copy the 2.4 implementation for now.
- */
-static int pgt_cache_water[2] = { 25, 50 };
-
-void check_pgt_cache(void)
-{
- do_check_pgt_cache(pgt_cache_water[0], pgt_cache_water[1]);
-}
-
-/*
* paging_init() sets up the page tables: We call the MMU specific
* init routine based upon the Sun model type on the Sparc.
*
*/
-extern void sun4c_paging_init(void);
extern void srmmu_paging_init(void);
extern void device_scan(void);
-pgprot_t PAGE_SHARED __read_mostly;
-EXPORT_SYMBOL(PAGE_SHARED);
-
void __init paging_init(void)
{
switch(sparc_cpu_model) {
- case sun4c:
- case sun4e:
- case sun4:
- sun4c_paging_init();
- sparc_unmapped_base = 0xe0000000;
- BTFIXUPSET_SETHI(sparc_unmapped_base, 0xe0000000);
- break;
case sparc_leon:
leon_init();
/* fall through */
@@ -332,7 +300,6 @@ void __init paging_init(void)
case sun4d:
srmmu_paging_init();
sparc_unmapped_base = 0x50000000;
- BTFIXUPSET_SETHI(sparc_unmapped_base, 0x50000000);
break;
default:
prom_printf("paging_init: Cannot init paging on this Sparc\n");
@@ -341,24 +308,6 @@ void __init paging_init(void)
prom_halt();
}
- /* Initialize the protection map with non-constant, MMU dependent values. */
- protection_map[0] = PAGE_NONE;
- protection_map[1] = PAGE_READONLY;
- protection_map[2] = PAGE_COPY;
- protection_map[3] = PAGE_COPY;
- protection_map[4] = PAGE_READONLY;
- protection_map[5] = PAGE_READONLY;
- protection_map[6] = PAGE_COPY;
- protection_map[7] = PAGE_COPY;
- protection_map[8] = PAGE_NONE;
- protection_map[9] = PAGE_READONLY;
- protection_map[10] = PAGE_SHARED;
- protection_map[11] = PAGE_SHARED;
- protection_map[12] = PAGE_READONLY;
- protection_map[13] = PAGE_READONLY;
- protection_map[14] = PAGE_SHARED;
- protection_map[15] = PAGE_SHARED;
- btfixup();
prom_build_devicetree();
of_fill_in_cpu_data();
device_scan();
diff --git a/arch/sparc/mm/init_64.c b/arch/sparc/mm/init_64.c
index 21faaeea85de..6026fdd1b2ed 100644
--- a/arch/sparc/mm/init_64.c
+++ b/arch/sparc/mm/init_64.c
@@ -741,7 +741,6 @@ static void __init find_ramdisk(unsigned long phys_base)
struct node_mem_mask {
unsigned long mask;
unsigned long val;
- unsigned long bootmem_paddr;
};
static struct node_mem_mask node_masks[MAX_NUMNODES];
static int num_node_masks;
@@ -806,12 +805,6 @@ static u64 memblock_nid_range(u64 start, u64 end, int *nid)
return start;
}
-#else
-static u64 memblock_nid_range(u64 start, u64 end, int *nid)
-{
- *nid = 0;
- return end;
-}
#endif
/* This must be invoked after performing all of the necessary
@@ -820,10 +813,11 @@ static u64 memblock_nid_range(u64 start, u64 end, int *nid)
*/
static void __init allocate_node_data(int nid)
{
- unsigned long paddr, num_pages, start_pfn, end_pfn;
struct pglist_data *p;
-
+ unsigned long start_pfn, end_pfn;
#ifdef CONFIG_NEED_MULTIPLE_NODES
+ unsigned long paddr;
+
paddr = memblock_alloc_try_nid(sizeof(struct pglist_data), SMP_CACHE_BYTES, nid);
if (!paddr) {
prom_printf("Cannot allocate pglist_data for nid[%d]\n", nid);
@@ -832,7 +826,7 @@ static void __init allocate_node_data(int nid)
NODE_DATA(nid) = __va(paddr);
memset(NODE_DATA(nid), 0, sizeof(struct pglist_data));
- NODE_DATA(nid)->bdata = &bootmem_node_data[nid];
+ NODE_DATA(nid)->node_id = nid;
#endif
p = NODE_DATA(nid);
@@ -840,18 +834,6 @@ static void __init allocate_node_data(int nid)
get_pfn_range_for_nid(nid, &start_pfn, &end_pfn);
p->node_start_pfn = start_pfn;
p->node_spanned_pages = end_pfn - start_pfn;
-
- if (p->node_spanned_pages) {
- num_pages = bootmem_bootmap_pages(p->node_spanned_pages);
-
- paddr = memblock_alloc_try_nid(num_pages << PAGE_SHIFT, PAGE_SIZE, nid);
- if (!paddr) {
- prom_printf("Cannot allocate bootmap for nid[%d]\n",
- nid);
- prom_halt();
- }
- node_masks[nid].bootmem_paddr = paddr;
- }
}
static void init_node_masks_nonnuma(void)
@@ -1292,75 +1274,9 @@ static void __init bootmem_init_nonnuma(void)
node_set_online(0);
}
-static void __init reserve_range_in_node(int nid, unsigned long start,
- unsigned long end)
-{
- numadbg(" reserve_range_in_node(nid[%d],start[%lx],end[%lx]\n",
- nid, start, end);
- while (start < end) {
- unsigned long this_end;
- int n;
-
- this_end = memblock_nid_range(start, end, &n);
- if (n == nid) {
- numadbg(" MATCH reserving range [%lx:%lx]\n",
- start, this_end);
- reserve_bootmem_node(NODE_DATA(nid), start,
- (this_end - start), BOOTMEM_DEFAULT);
- } else
- numadbg(" NO MATCH, advancing start to %lx\n",
- this_end);
-
- start = this_end;
- }
-}
-
-static void __init trim_reserved_in_node(int nid)
-{
- struct memblock_region *reg;
-
- numadbg(" trim_reserved_in_node(%d)\n", nid);
-
- for_each_memblock(reserved, reg)
- reserve_range_in_node(nid, reg->base, reg->base + reg->size);
-}
-
-static void __init bootmem_init_one_node(int nid)
-{
- struct pglist_data *p;
-
- numadbg("bootmem_init_one_node(%d)\n", nid);
-
- p = NODE_DATA(nid);
-
- if (p->node_spanned_pages) {
- unsigned long paddr = node_masks[nid].bootmem_paddr;
- unsigned long end_pfn;
-
- end_pfn = p->node_start_pfn + p->node_spanned_pages;
-
- numadbg(" init_bootmem_node(%d, %lx, %lx, %lx)\n",
- nid, paddr >> PAGE_SHIFT, p->node_start_pfn, end_pfn);
-
- init_bootmem_node(p, paddr >> PAGE_SHIFT,
- p->node_start_pfn, end_pfn);
-
- numadbg(" free_bootmem_with_active_regions(%d, %lx)\n",
- nid, end_pfn);
- free_bootmem_with_active_regions(nid, end_pfn);
-
- trim_reserved_in_node(nid);
-
- numadbg(" sparse_memory_present_with_active_regions(%d)\n",
- nid);
- sparse_memory_present_with_active_regions(nid);
- }
-}
-
static unsigned long __init bootmem_init(unsigned long phys_base)
{
unsigned long end_pfn;
- int nid;
end_pfn = memblock_end_of_DRAM() >> PAGE_SHIFT;
max_pfn = max_low_pfn = end_pfn;
@@ -1369,11 +1285,12 @@ static unsigned long __init bootmem_init(unsigned long phys_base)
if (bootmem_init_numa() < 0)
bootmem_init_nonnuma();
- /* XXX cpu notifier XXX */
+ /* Dump memblock with node info. */
+ memblock_dump_all();
- for_each_online_node(nid)
- bootmem_init_one_node(nid);
+ /* XXX cpu notifier XXX */
+ sparse_memory_present_with_active_regions(MAX_NUMNODES);
sparse_init();
return end_pfn;
@@ -1701,6 +1618,7 @@ void __init paging_init(void)
{
unsigned long end_pfn, shift, phys_base;
unsigned long real_end, i;
+ int node;
/* These build time checkes make sure that the dcache_dirty_cpu()
* page->flags usage will work.
@@ -1826,22 +1744,24 @@ void __init paging_init(void)
#endif
}
+ /* Setup bootmem... */
+ last_valid_pfn = end_pfn = bootmem_init(phys_base);
+
/* Once the OF device tree and MDESC have been setup, we know
* the list of possible cpus. Therefore we can allocate the
* IRQ stacks.
*/
for_each_possible_cpu(i) {
- /* XXX Use node local allocations... XXX */
- softirq_stack[i] = __va(memblock_alloc(THREAD_SIZE, THREAD_SIZE));
- hardirq_stack[i] = __va(memblock_alloc(THREAD_SIZE, THREAD_SIZE));
- }
+ node = cpu_to_node(i);
- /* Setup bootmem... */
- last_valid_pfn = end_pfn = bootmem_init(phys_base);
+ softirq_stack[i] = __alloc_bootmem_node(NODE_DATA(node),
+ THREAD_SIZE,
+ THREAD_SIZE, 0);
+ hardirq_stack[i] = __alloc_bootmem_node(NODE_DATA(node),
+ THREAD_SIZE,
+ THREAD_SIZE, 0);
+ }
-#ifndef CONFIG_NEED_MULTIPLE_NODES
- max_mapnr = last_valid_pfn;
-#endif
kernel_physical_mapping_init();
{
@@ -1973,6 +1893,7 @@ void __init mem_init(void)
free_all_bootmem_node(NODE_DATA(i));
}
}
+ totalram_pages += free_low_memory_core_early(MAX_NUMNODES);
}
#else
totalram_pages = free_all_bootmem();
diff --git a/arch/sparc/mm/io-unit.c b/arch/sparc/mm/io-unit.c
index fc58c3e917df..eb99862e9654 100644
--- a/arch/sparc/mm/io-unit.c
+++ b/arch/sparc/mm/io-unit.c
@@ -197,7 +197,7 @@ static void iounit_release_scsi_sgl(struct device *dev, struct scatterlist *sg,
}
#ifdef CONFIG_SBUS
-static int iounit_map_dma_area(struct device *dev, dma_addr_t *pba, unsigned long va, __u32 addr, int len)
+static int iounit_map_dma_area(struct device *dev, dma_addr_t *pba, unsigned long va, unsigned long addr, int len)
{
struct iounit_struct *iounit = dev->archdata.iommu;
unsigned long page, end;
@@ -242,29 +242,18 @@ static void iounit_unmap_dma_area(struct device *dev, unsigned long addr, int le
}
#endif
-static char *iounit_lockarea(char *vaddr, unsigned long len)
-{
-/* FIXME: Write this */
- return vaddr;
-}
-
-static void iounit_unlockarea(char *vaddr, unsigned long len)
-{
-/* FIXME: Write this */
-}
+static const struct sparc32_dma_ops iounit_dma_ops = {
+ .get_scsi_one = iounit_get_scsi_one,
+ .get_scsi_sgl = iounit_get_scsi_sgl,
+ .release_scsi_one = iounit_release_scsi_one,
+ .release_scsi_sgl = iounit_release_scsi_sgl,
+#ifdef CONFIG_SBUS
+ .map_dma_area = iounit_map_dma_area,
+ .unmap_dma_area = iounit_unmap_dma_area,
+#endif
+};
void __init ld_mmu_iounit(void)
{
- BTFIXUPSET_CALL(mmu_lockarea, iounit_lockarea, BTFIXUPCALL_RETO0);
- BTFIXUPSET_CALL(mmu_unlockarea, iounit_unlockarea, BTFIXUPCALL_NOP);
-
- BTFIXUPSET_CALL(mmu_get_scsi_one, iounit_get_scsi_one, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(mmu_get_scsi_sgl, iounit_get_scsi_sgl, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(mmu_release_scsi_one, iounit_release_scsi_one, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(mmu_release_scsi_sgl, iounit_release_scsi_sgl, BTFIXUPCALL_NORM);
-
-#ifdef CONFIG_SBUS
- BTFIXUPSET_CALL(mmu_map_dma_area, iounit_map_dma_area, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(mmu_unmap_dma_area, iounit_unmap_dma_area, BTFIXUPCALL_NORM);
-#endif
+ sparc32_dma_ops = &iounit_dma_ops;
}
diff --git a/arch/sparc/mm/iommu.c b/arch/sparc/mm/iommu.c
index 07fc6a65d9b6..a8a58cad9d2b 100644
--- a/arch/sparc/mm/iommu.c
+++ b/arch/sparc/mm/iommu.c
@@ -39,8 +39,6 @@
/* srmmu.c */
extern int viking_mxcc_present;
-BTFIXUPDEF_CALL(void, flush_page_for_dma, unsigned long)
-#define flush_page_for_dma(page) BTFIXUP_CALL(flush_page_for_dma)(page)
extern int flush_page_for_dma_global;
static int viking_flush;
/* viking.S */
@@ -143,7 +141,6 @@ static int __init iommu_init(void)
subsys_initcall(iommu_init);
-/* This begs to be btfixup-ed by srmmu. */
/* Flush the iotlb entries to ram. */
/* This could be better if we didn't have to flush whole pages. */
static void iommu_flush_iotlb(iopte_t *iopte, unsigned int niopte)
@@ -216,11 +213,6 @@ static u32 iommu_get_scsi_one(struct device *dev, char *vaddr, unsigned int len)
return busa + off;
}
-static __u32 iommu_get_scsi_one_noflush(struct device *dev, char *vaddr, unsigned long len)
-{
- return iommu_get_scsi_one(dev, vaddr, len);
-}
-
static __u32 iommu_get_scsi_one_gflush(struct device *dev, char *vaddr, unsigned long len)
{
flush_page_for_dma(0);
@@ -238,19 +230,6 @@ static __u32 iommu_get_scsi_one_pflush(struct device *dev, char *vaddr, unsigned
return iommu_get_scsi_one(dev, vaddr, len);
}
-static void iommu_get_scsi_sgl_noflush(struct device *dev, struct scatterlist *sg, int sz)
-{
- int n;
-
- while (sz != 0) {
- --sz;
- n = (sg->length + sg->offset + PAGE_SIZE-1) >> PAGE_SHIFT;
- sg->dma_address = iommu_get_one(dev, sg_page(sg), n) + sg->offset;
- sg->dma_length = sg->length;
- sg = sg_next(sg);
- }
-}
-
static void iommu_get_scsi_sgl_gflush(struct device *dev, struct scatterlist *sg, int sz)
{
int n;
@@ -426,40 +405,36 @@ static void iommu_unmap_dma_area(struct device *dev, unsigned long busa, int len
}
#endif
-static char *iommu_lockarea(char *vaddr, unsigned long len)
-{
- return vaddr;
-}
+static const struct sparc32_dma_ops iommu_dma_gflush_ops = {
+ .get_scsi_one = iommu_get_scsi_one_gflush,
+ .get_scsi_sgl = iommu_get_scsi_sgl_gflush,
+ .release_scsi_one = iommu_release_scsi_one,
+ .release_scsi_sgl = iommu_release_scsi_sgl,
+#ifdef CONFIG_SBUS
+ .map_dma_area = iommu_map_dma_area,
+ .unmap_dma_area = iommu_unmap_dma_area,
+#endif
+};
-static void iommu_unlockarea(char *vaddr, unsigned long len)
-{
-}
+static const struct sparc32_dma_ops iommu_dma_pflush_ops = {
+ .get_scsi_one = iommu_get_scsi_one_pflush,
+ .get_scsi_sgl = iommu_get_scsi_sgl_pflush,
+ .release_scsi_one = iommu_release_scsi_one,
+ .release_scsi_sgl = iommu_release_scsi_sgl,
+#ifdef CONFIG_SBUS
+ .map_dma_area = iommu_map_dma_area,
+ .unmap_dma_area = iommu_unmap_dma_area,
+#endif
+};
void __init ld_mmu_iommu(void)
{
- viking_flush = (BTFIXUPVAL_CALL(flush_page_for_dma) == (unsigned long)viking_flush_page);
- BTFIXUPSET_CALL(mmu_lockarea, iommu_lockarea, BTFIXUPCALL_RETO0);
- BTFIXUPSET_CALL(mmu_unlockarea, iommu_unlockarea, BTFIXUPCALL_NOP);
-
- if (!BTFIXUPVAL_CALL(flush_page_for_dma)) {
- /* IO coherent chip */
- BTFIXUPSET_CALL(mmu_get_scsi_one, iommu_get_scsi_one_noflush, BTFIXUPCALL_RETO0);
- BTFIXUPSET_CALL(mmu_get_scsi_sgl, iommu_get_scsi_sgl_noflush, BTFIXUPCALL_NORM);
- } else if (flush_page_for_dma_global) {
+ if (flush_page_for_dma_global) {
/* flush_page_for_dma flushes everything, no matter of what page is it */
- BTFIXUPSET_CALL(mmu_get_scsi_one, iommu_get_scsi_one_gflush, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(mmu_get_scsi_sgl, iommu_get_scsi_sgl_gflush, BTFIXUPCALL_NORM);
+ sparc32_dma_ops = &iommu_dma_gflush_ops;
} else {
- BTFIXUPSET_CALL(mmu_get_scsi_one, iommu_get_scsi_one_pflush, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(mmu_get_scsi_sgl, iommu_get_scsi_sgl_pflush, BTFIXUPCALL_NORM);
+ sparc32_dma_ops = &iommu_dma_pflush_ops;
}
- BTFIXUPSET_CALL(mmu_release_scsi_one, iommu_release_scsi_one, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(mmu_release_scsi_sgl, iommu_release_scsi_sgl, BTFIXUPCALL_NORM);
-
-#ifdef CONFIG_SBUS
- BTFIXUPSET_CALL(mmu_map_dma_area, iommu_map_dma_area, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(mmu_unmap_dma_area, iommu_unmap_dma_area, BTFIXUPCALL_NORM);
-#endif
if (viking_mxcc_present || srmmu_modtype == HyperSparc) {
dvma_prot = __pgprot(SRMMU_CACHE | SRMMU_ET_PTE | SRMMU_PRIV);
diff --git a/arch/sparc/mm/leon_mm.c b/arch/sparc/mm/leon_mm.c
index 13c2169822a8..5bed085a2c17 100644
--- a/arch/sparc/mm/leon_mm.c
+++ b/arch/sparc/mm/leon_mm.c
@@ -15,10 +15,24 @@
#include <asm/leon.h>
#include <asm/tlbflush.h>
+#include "srmmu.h"
+
int leon_flush_during_switch = 1;
int srmmu_swprobe_trace;
-unsigned long srmmu_swprobe(unsigned long vaddr, unsigned long *paddr)
+static inline unsigned long leon_get_ctable_ptr(void)
+{
+ unsigned int retval;
+
+ __asm__ __volatile__("lda [%1] %2, %0\n\t" :
+ "=r" (retval) :
+ "r" (SRMMU_CTXTBL_PTR),
+ "i" (ASI_LEON_MMUREGS));
+ return (retval & SRMMU_CTX_PMASK) << 4;
+}
+
+
+unsigned long leon_swprobe(unsigned long vaddr, unsigned long *paddr)
{
unsigned int ctxtbl;
@@ -33,10 +47,10 @@ unsigned long srmmu_swprobe(unsigned long vaddr, unsigned long *paddr)
if (srmmu_swprobe_trace)
printk(KERN_INFO "swprobe: trace on\n");
- ctxtbl = srmmu_get_ctable_ptr();
+ ctxtbl = leon_get_ctable_ptr();
if (!(ctxtbl)) {
if (srmmu_swprobe_trace)
- printk(KERN_INFO "swprobe: srmmu_get_ctable_ptr returned 0=>0\n");
+ printk(KERN_INFO "swprobe: leon_get_ctable_ptr returned 0=>0\n");
return 0;
}
if (!_pfn_valid(PFN(ctxtbl))) {
@@ -258,3 +272,80 @@ void leon_switch_mm(void)
if (leon_flush_during_switch)
leon_flush_cache_all();
}
+
+static void leon_flush_cache_mm(struct mm_struct *mm)
+{
+ leon_flush_cache_all();
+}
+
+static void leon_flush_cache_page(struct vm_area_struct *vma, unsigned long page)
+{
+ leon_flush_pcache_all(vma, page);
+}
+
+static void leon_flush_cache_range(struct vm_area_struct *vma,
+ unsigned long start,
+ unsigned long end)
+{
+ leon_flush_cache_all();
+}
+
+static void leon_flush_tlb_mm(struct mm_struct *mm)
+{
+ leon_flush_tlb_all();
+}
+
+static void leon_flush_tlb_page(struct vm_area_struct *vma,
+ unsigned long page)
+{
+ leon_flush_tlb_all();
+}
+
+static void leon_flush_tlb_range(struct vm_area_struct *vma,
+ unsigned long start,
+ unsigned long end)
+{
+ leon_flush_tlb_all();
+}
+
+static void leon_flush_page_to_ram(unsigned long page)
+{
+ leon_flush_cache_all();
+}
+
+static void leon_flush_sig_insns(struct mm_struct *mm, unsigned long page)
+{
+ leon_flush_cache_all();
+}
+
+static void leon_flush_page_for_dma(unsigned long page)
+{
+ leon_flush_dcache_all();
+}
+
+void __init poke_leonsparc(void)
+{
+}
+
+static const struct sparc32_cachetlb_ops leon_ops = {
+ .cache_all = leon_flush_cache_all,
+ .cache_mm = leon_flush_cache_mm,
+ .cache_page = leon_flush_cache_page,
+ .cache_range = leon_flush_cache_range,
+ .tlb_all = leon_flush_tlb_all,
+ .tlb_mm = leon_flush_tlb_mm,
+ .tlb_page = leon_flush_tlb_page,
+ .tlb_range = leon_flush_tlb_range,
+ .page_to_ram = leon_flush_page_to_ram,
+ .sig_insns = leon_flush_sig_insns,
+ .page_for_dma = leon_flush_page_for_dma,
+};
+
+void __init init_leon(void)
+{
+ srmmu_name = "LEON";
+ sparc32_cachetlb_ops = &leon_ops;
+ poke_srmmu = poke_leonsparc;
+
+ leon_flush_during_switch = leon_flush_needed();
+}
diff --git a/arch/sparc/mm/loadmmu.c b/arch/sparc/mm/loadmmu.c
deleted file mode 100644
index c5bf2a6c3858..000000000000
--- a/arch/sparc/mm/loadmmu.c
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * loadmmu.c: This code loads up all the mm function pointers once the
- * machine type has been determined. It also sets the static
- * mmu values such as PAGE_NONE, etc.
- *
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- * Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
- */
-
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/init.h>
-
-#include <asm/page.h>
-#include <asm/pgtable.h>
-#include <asm/mmu_context.h>
-#include <asm/oplib.h>
-
-struct ctx_list *ctx_list_pool;
-struct ctx_list ctx_free;
-struct ctx_list ctx_used;
-
-extern void ld_mmu_sun4c(void);
-extern void ld_mmu_srmmu(void);
-
-void __init load_mmu(void)
-{
- switch(sparc_cpu_model) {
- case sun4c:
- case sun4:
- ld_mmu_sun4c();
- break;
- case sun4m:
- case sun4d:
- case sparc_leon:
- ld_mmu_srmmu();
- break;
- default:
- prom_printf("load_mmu: %d unsupported\n", (int)sparc_cpu_model);
- prom_halt();
- }
- btfixup();
-}
diff --git a/arch/sparc/mm/nosun4c.c b/arch/sparc/mm/nosun4c.c
deleted file mode 100644
index 4e62c27147c4..000000000000
--- a/arch/sparc/mm/nosun4c.c
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * nosun4c.c: This file is a bunch of dummies for SMP compiles,
- * so that it does not need sun4c and avoid ifdefs.
- *
- * Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
- */
-
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/init.h>
-#include <asm/pgtable.h>
-
-static char shouldnothappen[] __initdata = "32bit SMP kernel only supports sun4m and sun4d\n";
-
-/* Dummies */
-struct sun4c_mmu_ring {
- unsigned long xxx1[3];
- unsigned char xxx2[2];
- int xxx3;
-};
-struct sun4c_mmu_ring sun4c_kernel_ring;
-struct sun4c_mmu_ring sun4c_kfree_ring;
-unsigned long sun4c_kernel_faults;
-unsigned long *sun4c_memerr_reg;
-
-static void __init should_not_happen(void)
-{
- prom_printf(shouldnothappen);
- prom_halt();
-}
-
-unsigned long __init sun4c_paging_init(unsigned long start_mem, unsigned long end_mem)
-{
- should_not_happen();
- return 0;
-}
-
-void __init ld_mmu_sun4c(void)
-{
- should_not_happen();
-}
-
-void sun4c_mapioaddr(unsigned long physaddr, unsigned long virt_addr, int bus_type, int rdonly)
-{
-}
-
-void sun4c_unmapioaddr(unsigned long virt_addr)
-{
-}
-
-void sun4c_complete_all_stores(void)
-{
-}
-
-pte_t *sun4c_pte_offset(pmd_t * dir, unsigned long address)
-{
- return NULL;
-}
-
-pte_t *sun4c_pte_offset_kernel(pmd_t *dir, unsigned long address)
-{
- return NULL;
-}
-
-void sun4c_update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t *ptep)
-{
-}
-
-void __init sun4c_probe_vac(void)
-{
- should_not_happen();
-}
-
-void __init sun4c_probe_memerr_reg(void)
-{
- should_not_happen();
-}
diff --git a/arch/sparc/mm/srmmu.c b/arch/sparc/mm/srmmu.c
index cbef74e793b8..62e3f5773303 100644
--- a/arch/sparc/mm/srmmu.c
+++ b/arch/sparc/mm/srmmu.c
@@ -48,39 +48,37 @@
#include <asm/turbosparc.h>
#include <asm/leon.h>
-#include <asm/btfixup.h>
+#include "srmmu.h"
enum mbus_module srmmu_modtype;
static unsigned int hwbug_bitmask;
int vac_cache_size;
int vac_line_size;
+struct ctx_list *ctx_list_pool;
+struct ctx_list ctx_free;
+struct ctx_list ctx_used;
+
extern struct resource sparc_iomap;
extern unsigned long last_valid_pfn;
-extern unsigned long page_kernel;
-
static pgd_t *srmmu_swapper_pg_dir;
+const struct sparc32_cachetlb_ops *sparc32_cachetlb_ops;
+
#ifdef CONFIG_SMP
+const struct sparc32_cachetlb_ops *local_ops;
+
#define FLUSH_BEGIN(mm)
#define FLUSH_END
#else
-#define FLUSH_BEGIN(mm) if((mm)->context != NO_CONTEXT) {
+#define FLUSH_BEGIN(mm) if ((mm)->context != NO_CONTEXT) {
#define FLUSH_END }
#endif
-BTFIXUPDEF_CALL(void, flush_page_for_dma, unsigned long)
-#define flush_page_for_dma(page) BTFIXUP_CALL(flush_page_for_dma)(page)
-
int flush_page_for_dma_global = 1;
-#ifdef CONFIG_SMP
-BTFIXUPDEF_CALL(void, local_flush_page_for_dma, unsigned long)
-#define local_flush_page_for_dma(page) BTFIXUP_CALL(local_flush_page_for_dma)(page)
-#endif
-
char *srmmu_name;
ctxd_t *srmmu_ctx_table_phys;
@@ -91,28 +89,6 @@ static DEFINE_SPINLOCK(srmmu_context_spinlock);
static int is_hypersparc;
-/*
- * In general all page table modifications should use the V8 atomic
- * swap instruction. This insures the mmu and the cpu are in sync
- * with respect to ref/mod bits in the page tables.
- */
-static inline unsigned long srmmu_swap(unsigned long *addr, unsigned long value)
-{
- __asm__ __volatile__("swap [%2], %0" : "=&r" (value) : "0" (value), "r" (addr));
- return value;
-}
-
-static inline void srmmu_set_pte(pte_t *ptep, pte_t pteval)
-{
- srmmu_swap((unsigned long *)ptep, pte_val(pteval));
-}
-
-/* The very generic SRMMU page table operations. */
-static inline int srmmu_device_memory(unsigned long x)
-{
- return ((x & 0xF0000000) != 0);
-}
-
static int srmmu_cache_pagetables;
/* these will be initialized in srmmu_nocache_calcsize() */
@@ -129,145 +105,39 @@ void *srmmu_nocache_pool;
void *srmmu_nocache_bitmap;
static struct bit_map srmmu_nocache_map;
-static unsigned long srmmu_pte_pfn(pte_t pte)
-{
- if (srmmu_device_memory(pte_val(pte))) {
- /* Just return something that will cause
- * pfn_valid() to return false. This makes
- * copy_one_pte() to just directly copy to
- * PTE over.
- */
- return ~0UL;
- }
- return (pte_val(pte) & SRMMU_PTE_PMASK) >> (PAGE_SHIFT-4);
-}
-
-static struct page *srmmu_pmd_page(pmd_t pmd)
-{
-
- if (srmmu_device_memory(pmd_val(pmd)))
- BUG();
- return pfn_to_page((pmd_val(pmd) & SRMMU_PTD_PMASK) >> (PAGE_SHIFT-4));
-}
-
-static inline unsigned long srmmu_pgd_page(pgd_t pgd)
-{ return srmmu_device_memory(pgd_val(pgd))?~0:(unsigned long)__nocache_va((pgd_val(pgd) & SRMMU_PTD_PMASK) << 4); }
-
-
-static inline int srmmu_pte_none(pte_t pte)
-{ return !(pte_val(pte) & 0xFFFFFFF); }
-
-static inline int srmmu_pte_present(pte_t pte)
-{ return ((pte_val(pte) & SRMMU_ET_MASK) == SRMMU_ET_PTE); }
-
-static inline void srmmu_pte_clear(pte_t *ptep)
-{ srmmu_set_pte(ptep, __pte(0)); }
-
static inline int srmmu_pmd_none(pmd_t pmd)
{ return !(pmd_val(pmd) & 0xFFFFFFF); }
-static inline int srmmu_pmd_bad(pmd_t pmd)
-{ return (pmd_val(pmd) & SRMMU_ET_MASK) != SRMMU_ET_PTD; }
-
-static inline int srmmu_pmd_present(pmd_t pmd)
-{ return ((pmd_val(pmd) & SRMMU_ET_MASK) == SRMMU_ET_PTD); }
-
-static inline void srmmu_pmd_clear(pmd_t *pmdp) {
- int i;
- for (i = 0; i < PTRS_PER_PTE/SRMMU_REAL_PTRS_PER_PTE; i++)
- srmmu_set_pte((pte_t *)&pmdp->pmdv[i], __pte(0));
-}
-
-static inline int srmmu_pgd_none(pgd_t pgd)
-{ return !(pgd_val(pgd) & 0xFFFFFFF); }
-
-static inline int srmmu_pgd_bad(pgd_t pgd)
-{ return (pgd_val(pgd) & SRMMU_ET_MASK) != SRMMU_ET_PTD; }
-
-static inline int srmmu_pgd_present(pgd_t pgd)
-{ return ((pgd_val(pgd) & SRMMU_ET_MASK) == SRMMU_ET_PTD); }
-
-static inline void srmmu_pgd_clear(pgd_t * pgdp)
-{ srmmu_set_pte((pte_t *)pgdp, __pte(0)); }
-
-static inline pte_t srmmu_pte_wrprotect(pte_t pte)
-{ return __pte(pte_val(pte) & ~SRMMU_WRITE);}
-
-static inline pte_t srmmu_pte_mkclean(pte_t pte)
-{ return __pte(pte_val(pte) & ~SRMMU_DIRTY);}
-
-static inline pte_t srmmu_pte_mkold(pte_t pte)
-{ return __pte(pte_val(pte) & ~SRMMU_REF);}
-
-static inline pte_t srmmu_pte_mkwrite(pte_t pte)
-{ return __pte(pte_val(pte) | SRMMU_WRITE);}
-
-static inline pte_t srmmu_pte_mkdirty(pte_t pte)
-{ return __pte(pte_val(pte) | SRMMU_DIRTY);}
-
-static inline pte_t srmmu_pte_mkyoung(pte_t pte)
-{ return __pte(pte_val(pte) | SRMMU_REF);}
-
-/*
- * Conversion functions: convert a page and protection to a page entry,
- * and a page entry and page directory to the page they refer to.
- */
-static pte_t srmmu_mk_pte(struct page *page, pgprot_t pgprot)
-{ return __pte((page_to_pfn(page) << (PAGE_SHIFT-4)) | pgprot_val(pgprot)); }
-
-static pte_t srmmu_mk_pte_phys(unsigned long page, pgprot_t pgprot)
-{ return __pte(((page) >> 4) | pgprot_val(pgprot)); }
-
-static pte_t srmmu_mk_pte_io(unsigned long page, pgprot_t pgprot, int space)
-{ return __pte(((page) >> 4) | (space << 28) | pgprot_val(pgprot)); }
-
/* XXX should we hyper_flush_whole_icache here - Anton */
static inline void srmmu_ctxd_set(ctxd_t *ctxp, pgd_t *pgdp)
-{ srmmu_set_pte((pte_t *)ctxp, (SRMMU_ET_PTD | (__nocache_pa((unsigned long) pgdp) >> 4))); }
-
-static inline void srmmu_pgd_set(pgd_t * pgdp, pmd_t * pmdp)
-{ srmmu_set_pte((pte_t *)pgdp, (SRMMU_ET_PTD | (__nocache_pa((unsigned long) pmdp) >> 4))); }
+{ set_pte((pte_t *)ctxp, (SRMMU_ET_PTD | (__nocache_pa((unsigned long) pgdp) >> 4))); }
-static void srmmu_pmd_set(pmd_t *pmdp, pte_t *ptep)
+void pmd_set(pmd_t *pmdp, pte_t *ptep)
{
unsigned long ptp; /* Physical address, shifted right by 4 */
int i;
ptp = __nocache_pa((unsigned long) ptep) >> 4;
for (i = 0; i < PTRS_PER_PTE/SRMMU_REAL_PTRS_PER_PTE; i++) {
- srmmu_set_pte((pte_t *)&pmdp->pmdv[i], SRMMU_ET_PTD | ptp);
+ set_pte((pte_t *)&pmdp->pmdv[i], SRMMU_ET_PTD | ptp);
ptp += (SRMMU_REAL_PTRS_PER_PTE*sizeof(pte_t) >> 4);
}
}
-static void srmmu_pmd_populate(pmd_t *pmdp, struct page *ptep)
+void pmd_populate(struct mm_struct *mm, pmd_t *pmdp, struct page *ptep)
{
unsigned long ptp; /* Physical address, shifted right by 4 */
int i;
ptp = page_to_pfn(ptep) << (PAGE_SHIFT-4); /* watch for overflow */
for (i = 0; i < PTRS_PER_PTE/SRMMU_REAL_PTRS_PER_PTE; i++) {
- srmmu_set_pte((pte_t *)&pmdp->pmdv[i], SRMMU_ET_PTD | ptp);
+ set_pte((pte_t *)&pmdp->pmdv[i], SRMMU_ET_PTD | ptp);
ptp += (SRMMU_REAL_PTRS_PER_PTE*sizeof(pte_t) >> 4);
}
}
-static inline pte_t srmmu_pte_modify(pte_t pte, pgprot_t newprot)
-{ return __pte((pte_val(pte) & SRMMU_CHG_MASK) | pgprot_val(newprot)); }
-
-/* to find an entry in a top-level page table... */
-static inline pgd_t *srmmu_pgd_offset(struct mm_struct * mm, unsigned long address)
-{ return mm->pgd + (address >> SRMMU_PGDIR_SHIFT); }
-
-/* Find an entry in the second-level page table.. */
-static inline pmd_t *srmmu_pmd_offset(pgd_t * dir, unsigned long address)
-{
- return (pmd_t *) srmmu_pgd_page(*dir) +
- ((address >> PMD_SHIFT) & (PTRS_PER_PMD - 1));
-}
-
/* Find an entry in the third-level page table.. */
-static inline pte_t *srmmu_pte_offset(pmd_t * dir, unsigned long address)
+pte_t *pte_offset_kernel(pmd_t * dir, unsigned long address)
{
void *pte;
@@ -276,23 +146,6 @@ static inline pte_t *srmmu_pte_offset(pmd_t * dir, unsigned long address)
((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1));
}
-static unsigned long srmmu_swp_type(swp_entry_t entry)
-{
- return (entry.val >> SRMMU_SWP_TYPE_SHIFT) & SRMMU_SWP_TYPE_MASK;
-}
-
-static unsigned long srmmu_swp_offset(swp_entry_t entry)
-{
- return (entry.val >> SRMMU_SWP_OFF_SHIFT) & SRMMU_SWP_OFF_MASK;
-}
-
-static swp_entry_t srmmu_swp_entry(unsigned long type, unsigned long offset)
-{
- return (swp_entry_t) {
- (type & SRMMU_SWP_TYPE_MASK) << SRMMU_SWP_TYPE_SHIFT
- | (offset & SRMMU_SWP_OFF_MASK) << SRMMU_SWP_OFF_SHIFT };
-}
-
/*
* size: bytes to allocate in the nocache area.
* align: bytes, number to align at.
@@ -325,7 +178,7 @@ static unsigned long __srmmu_get_nocache(int size, int align)
return (SRMMU_NOCACHE_VADDR + (offset << SRMMU_NOCACHE_BITMAP_SHIFT));
}
-static unsigned long srmmu_get_nocache(int size, int align)
+unsigned long srmmu_get_nocache(int size, int align)
{
unsigned long tmp;
@@ -337,7 +190,7 @@ static unsigned long srmmu_get_nocache(int size, int align)
return tmp;
}
-static void srmmu_free_nocache(unsigned long vaddr, int size)
+void srmmu_free_nocache(unsigned long vaddr, int size)
{
int offset;
@@ -429,15 +282,15 @@ static void __init srmmu_nocache_init(void)
while (vaddr < srmmu_nocache_end) {
pgd = pgd_offset_k(vaddr);
- pmd = srmmu_pmd_offset(__nocache_fix(pgd), vaddr);
- pte = srmmu_pte_offset(__nocache_fix(pmd), vaddr);
+ pmd = pmd_offset(__nocache_fix(pgd), vaddr);
+ pte = pte_offset_kernel(__nocache_fix(pmd), vaddr);
pteval = ((paddr >> 4) | SRMMU_ET_PTE | SRMMU_PRIV);
if (srmmu_cache_pagetables)
pteval |= SRMMU_CACHE;
- srmmu_set_pte(__nocache_fix(pte), __pte(pteval));
+ set_pte(__nocache_fix(pte), __pte(pteval));
vaddr += PAGE_SIZE;
paddr += PAGE_SIZE;
@@ -447,7 +300,7 @@ static void __init srmmu_nocache_init(void)
flush_tlb_all();
}
-static inline pgd_t *srmmu_get_pgd_fast(void)
+pgd_t *get_pgd_fast(void)
{
pgd_t *pgd = NULL;
@@ -462,21 +315,6 @@ static inline pgd_t *srmmu_get_pgd_fast(void)
return pgd;
}
-static void srmmu_free_pgd_fast(pgd_t *pgd)
-{
- srmmu_free_nocache((unsigned long)pgd, SRMMU_PGD_TABLE_SIZE);
-}
-
-static pmd_t *srmmu_pmd_alloc_one(struct mm_struct *mm, unsigned long address)
-{
- return (pmd_t *)srmmu_get_nocache(SRMMU_PMD_TABLE_SIZE, SRMMU_PMD_TABLE_SIZE);
-}
-
-static void srmmu_pmd_free(pmd_t * pmd)
-{
- srmmu_free_nocache((unsigned long)pmd, SRMMU_PMD_TABLE_SIZE);
-}
-
/*
* Hardware needs alignment to 256 only, but we align to whole page size
* to reduce fragmentation problems due to the buddy principle.
@@ -485,31 +323,19 @@ static void srmmu_pmd_free(pmd_t * pmd)
* Alignments up to the page size are the same for physical and virtual
* addresses of the nocache area.
*/
-static pte_t *
-srmmu_pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address)
-{
- return (pte_t *)srmmu_get_nocache(PTE_SIZE, PTE_SIZE);
-}
-
-static pgtable_t
-srmmu_pte_alloc_one(struct mm_struct *mm, unsigned long address)
+pgtable_t pte_alloc_one(struct mm_struct *mm, unsigned long address)
{
unsigned long pte;
struct page *page;
- if ((pte = (unsigned long)srmmu_pte_alloc_one_kernel(mm, address)) == 0)
+ if ((pte = (unsigned long)pte_alloc_one_kernel(mm, address)) == 0)
return NULL;
page = pfn_to_page( __nocache_pa(pte) >> PAGE_SHIFT );
pgtable_page_ctor(page);
return page;
}
-static void srmmu_free_pte_fast(pte_t *pte)
-{
- srmmu_free_nocache((unsigned long)pte, PTE_SIZE);
-}
-
-static void srmmu_pte_free(pgtable_t pte)
+void pte_free(struct mm_struct *mm, pgtable_t pte)
{
unsigned long p;
@@ -560,8 +386,8 @@ static inline void free_context(int context)
}
-static void srmmu_switch_mm(struct mm_struct *old_mm, struct mm_struct *mm,
- struct task_struct *tsk, int cpu)
+void switch_mm(struct mm_struct *old_mm, struct mm_struct *mm,
+ struct task_struct *tsk)
{
if(mm->context == NO_CONTEXT) {
spin_lock(&srmmu_context_spinlock);
@@ -590,8 +416,8 @@ static inline void srmmu_mapioaddr(unsigned long physaddr,
physaddr &= PAGE_MASK;
pgdp = pgd_offset_k(virt_addr);
- pmdp = srmmu_pmd_offset(pgdp, virt_addr);
- ptep = srmmu_pte_offset(pmdp, virt_addr);
+ pmdp = pmd_offset(pgdp, virt_addr);
+ ptep = pte_offset_kernel(pmdp, virt_addr);
tmp = (physaddr >> 4) | SRMMU_ET_PTE;
/*
@@ -602,11 +428,11 @@ static inline void srmmu_mapioaddr(unsigned long physaddr,
tmp |= (bus_type << 28);
tmp |= SRMMU_PRIV;
__flush_page_to_ram(virt_addr);
- srmmu_set_pte(ptep, __pte(tmp));
+ set_pte(ptep, __pte(tmp));
}
-static void srmmu_mapiorange(unsigned int bus, unsigned long xpa,
- unsigned long xva, unsigned int len)
+void srmmu_mapiorange(unsigned int bus, unsigned long xpa,
+ unsigned long xva, unsigned int len)
{
while (len != 0) {
len -= PAGE_SIZE;
@@ -624,14 +450,14 @@ static inline void srmmu_unmapioaddr(unsigned long virt_addr)
pte_t *ptep;
pgdp = pgd_offset_k(virt_addr);
- pmdp = srmmu_pmd_offset(pgdp, virt_addr);
- ptep = srmmu_pte_offset(pmdp, virt_addr);
+ pmdp = pmd_offset(pgdp, virt_addr);
+ ptep = pte_offset_kernel(pmdp, virt_addr);
/* No need to flush uncacheable page. */
- srmmu_pte_clear(ptep);
+ __pte_clear(ptep);
}
-static void srmmu_unmapiorange(unsigned long virt_addr, unsigned int len)
+void srmmu_unmapiorange(unsigned long virt_addr, unsigned int len)
{
while (len != 0) {
len -= PAGE_SIZE;
@@ -641,34 +467,6 @@ static void srmmu_unmapiorange(unsigned long virt_addr, unsigned int len)
flush_tlb_all();
}
-/*
- * On the SRMMU we do not have the problems with limited tlb entries
- * for mapping kernel pages, so we just take things from the free page
- * pool. As a side effect we are putting a little too much pressure
- * on the gfp() subsystem. This setup also makes the logic of the
- * iommu mapping code a lot easier as we can transparently handle
- * mappings on the kernel stack without any special code as we did
- * need on the sun4c.
- */
-static struct thread_info *srmmu_alloc_thread_info_node(int node)
-{
- struct thread_info *ret;
-
- ret = (struct thread_info *)__get_free_pages(GFP_KERNEL,
- THREAD_INFO_ORDER);
-#ifdef CONFIG_DEBUG_STACK_USAGE
- if (ret)
- memset(ret, 0, PAGE_SIZE << THREAD_INFO_ORDER);
-#endif /* DEBUG_STACK_USAGE */
-
- return ret;
-}
-
-static void srmmu_free_thread_info(struct thread_info *ti)
-{
- free_pages((unsigned long)ti, THREAD_INFO_ORDER);
-}
-
/* tsunami.S */
extern void tsunami_flush_cache_all(void);
extern void tsunami_flush_cache_mm(struct mm_struct *mm);
@@ -683,38 +481,6 @@ extern void tsunami_flush_tlb_range(struct vm_area_struct *vma, unsigned long st
extern void tsunami_flush_tlb_page(struct vm_area_struct *vma, unsigned long page);
extern void tsunami_setup_blockops(void);
-/*
- * Workaround, until we find what's going on with Swift. When low on memory,
- * it sometimes loops in fault/handle_mm_fault incl. flush_tlb_page to find
- * out it is already in page tables/ fault again on the same instruction.
- * I really don't understand it, have checked it and contexts
- * are right, flush_tlb_all is done as well, and it faults again...
- * Strange. -jj
- *
- * The following code is a deadwood that may be necessary when
- * we start to make precise page flushes again. --zaitcev
- */
-static void swift_update_mmu_cache(struct vm_area_struct * vma, unsigned long address, pte_t *ptep)
-{
-#if 0
- static unsigned long last;
- unsigned int val;
- /* unsigned int n; */
-
- if (address == last) {
- val = srmmu_hwprobe(address);
- if (val != 0 && pte_val(*ptep) != val) {
- printk("swift_update_mmu_cache: "
- "addr %lx put %08x probed %08x from %p\n",
- address, pte_val(*ptep), val,
- __builtin_return_address(0));
- srmmu_flush_whole_tlb();
- }
- }
- last = address;
-#endif
-}
-
/* swift.S */
extern void swift_flush_cache_all(void);
extern void swift_flush_cache_mm(struct mm_struct *mm);
@@ -767,244 +533,6 @@ void swift_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
* with respect to cache coherency.
*/
-/* Cypress flushes. */
-static void cypress_flush_cache_all(void)
-{
- volatile unsigned long cypress_sucks;
- unsigned long faddr, tagval;
-
- flush_user_windows();
- for(faddr = 0; faddr < 0x10000; faddr += 0x20) {
- __asm__ __volatile__("lda [%1 + %2] %3, %0\n\t" :
- "=r" (tagval) :
- "r" (faddr), "r" (0x40000),
- "i" (ASI_M_DATAC_TAG));
-
- /* If modified and valid, kick it. */
- if((tagval & 0x60) == 0x60)
- cypress_sucks = *(unsigned long *)(0xf0020000 + faddr);
- }
-}
-
-static void cypress_flush_cache_mm(struct mm_struct *mm)
-{
- register unsigned long a, b, c, d, e, f, g;
- unsigned long flags, faddr;
- int octx;
-
- FLUSH_BEGIN(mm)
- flush_user_windows();
- local_irq_save(flags);
- octx = srmmu_get_context();
- srmmu_set_context(mm->context);
- a = 0x20; b = 0x40; c = 0x60;
- d = 0x80; e = 0xa0; f = 0xc0; g = 0xe0;
-
- faddr = (0x10000 - 0x100);
- goto inside;
- do {
- faddr -= 0x100;
- inside:
- __asm__ __volatile__("sta %%g0, [%0] %1\n\t"
- "sta %%g0, [%0 + %2] %1\n\t"
- "sta %%g0, [%0 + %3] %1\n\t"
- "sta %%g0, [%0 + %4] %1\n\t"
- "sta %%g0, [%0 + %5] %1\n\t"
- "sta %%g0, [%0 + %6] %1\n\t"
- "sta %%g0, [%0 + %7] %1\n\t"
- "sta %%g0, [%0 + %8] %1\n\t" : :
- "r" (faddr), "i" (ASI_M_FLUSH_CTX),
- "r" (a), "r" (b), "r" (c), "r" (d),
- "r" (e), "r" (f), "r" (g));
- } while(faddr);
- srmmu_set_context(octx);
- local_irq_restore(flags);
- FLUSH_END
-}
-
-static void cypress_flush_cache_range(struct vm_area_struct *vma, unsigned long start, unsigned long end)
-{
- struct mm_struct *mm = vma->vm_mm;
- register unsigned long a, b, c, d, e, f, g;
- unsigned long flags, faddr;
- int octx;
-
- FLUSH_BEGIN(mm)
- flush_user_windows();
- local_irq_save(flags);
- octx = srmmu_get_context();
- srmmu_set_context(mm->context);
- a = 0x20; b = 0x40; c = 0x60;
- d = 0x80; e = 0xa0; f = 0xc0; g = 0xe0;
-
- start &= SRMMU_REAL_PMD_MASK;
- while(start < end) {
- faddr = (start + (0x10000 - 0x100));
- goto inside;
- do {
- faddr -= 0x100;
- inside:
- __asm__ __volatile__("sta %%g0, [%0] %1\n\t"
- "sta %%g0, [%0 + %2] %1\n\t"
- "sta %%g0, [%0 + %3] %1\n\t"
- "sta %%g0, [%0 + %4] %1\n\t"
- "sta %%g0, [%0 + %5] %1\n\t"
- "sta %%g0, [%0 + %6] %1\n\t"
- "sta %%g0, [%0 + %7] %1\n\t"
- "sta %%g0, [%0 + %8] %1\n\t" : :
- "r" (faddr),
- "i" (ASI_M_FLUSH_SEG),
- "r" (a), "r" (b), "r" (c), "r" (d),
- "r" (e), "r" (f), "r" (g));
- } while (faddr != start);
- start += SRMMU_REAL_PMD_SIZE;
- }
- srmmu_set_context(octx);
- local_irq_restore(flags);
- FLUSH_END
-}
-
-static void cypress_flush_cache_page(struct vm_area_struct *vma, unsigned long page)
-{
- register unsigned long a, b, c, d, e, f, g;
- struct mm_struct *mm = vma->vm_mm;
- unsigned long flags, line;
- int octx;
-
- FLUSH_BEGIN(mm)
- flush_user_windows();
- local_irq_save(flags);
- octx = srmmu_get_context();
- srmmu_set_context(mm->context);
- a = 0x20; b = 0x40; c = 0x60;
- d = 0x80; e = 0xa0; f = 0xc0; g = 0xe0;
-
- page &= PAGE_MASK;
- line = (page + PAGE_SIZE) - 0x100;
- goto inside;
- do {
- line -= 0x100;
- inside:
- __asm__ __volatile__("sta %%g0, [%0] %1\n\t"
- "sta %%g0, [%0 + %2] %1\n\t"
- "sta %%g0, [%0 + %3] %1\n\t"
- "sta %%g0, [%0 + %4] %1\n\t"
- "sta %%g0, [%0 + %5] %1\n\t"
- "sta %%g0, [%0 + %6] %1\n\t"
- "sta %%g0, [%0 + %7] %1\n\t"
- "sta %%g0, [%0 + %8] %1\n\t" : :
- "r" (line),
- "i" (ASI_M_FLUSH_PAGE),
- "r" (a), "r" (b), "r" (c), "r" (d),
- "r" (e), "r" (f), "r" (g));
- } while(line != page);
- srmmu_set_context(octx);
- local_irq_restore(flags);
- FLUSH_END
-}
-
-/* Cypress is copy-back, at least that is how we configure it. */
-static void cypress_flush_page_to_ram(unsigned long page)
-{
- register unsigned long a, b, c, d, e, f, g;
- unsigned long line;
-
- a = 0x20; b = 0x40; c = 0x60; d = 0x80; e = 0xa0; f = 0xc0; g = 0xe0;
- page &= PAGE_MASK;
- line = (page + PAGE_SIZE) - 0x100;
- goto inside;
- do {
- line -= 0x100;
- inside:
- __asm__ __volatile__("sta %%g0, [%0] %1\n\t"
- "sta %%g0, [%0 + %2] %1\n\t"
- "sta %%g0, [%0 + %3] %1\n\t"
- "sta %%g0, [%0 + %4] %1\n\t"
- "sta %%g0, [%0 + %5] %1\n\t"
- "sta %%g0, [%0 + %6] %1\n\t"
- "sta %%g0, [%0 + %7] %1\n\t"
- "sta %%g0, [%0 + %8] %1\n\t" : :
- "r" (line),
- "i" (ASI_M_FLUSH_PAGE),
- "r" (a), "r" (b), "r" (c), "r" (d),
- "r" (e), "r" (f), "r" (g));
- } while(line != page);
-}
-
-/* Cypress is also IO cache coherent. */
-static void cypress_flush_page_for_dma(unsigned long page)
-{
-}
-
-/* Cypress has unified L2 VIPT, from which both instructions and data
- * are stored. It does not have an onboard icache of any sort, therefore
- * no flush is necessary.
- */
-static void cypress_flush_sig_insns(struct mm_struct *mm, unsigned long insn_addr)
-{
-}
-
-static void cypress_flush_tlb_all(void)
-{
- srmmu_flush_whole_tlb();
-}
-
-static void cypress_flush_tlb_mm(struct mm_struct *mm)
-{
- FLUSH_BEGIN(mm)
- __asm__ __volatile__(
- "lda [%0] %3, %%g5\n\t"
- "sta %2, [%0] %3\n\t"
- "sta %%g0, [%1] %4\n\t"
- "sta %%g5, [%0] %3\n"
- : /* no outputs */
- : "r" (SRMMU_CTX_REG), "r" (0x300), "r" (mm->context),
- "i" (ASI_M_MMUREGS), "i" (ASI_M_FLUSH_PROBE)
- : "g5");
- FLUSH_END
-}
-
-static void cypress_flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end)
-{
- struct mm_struct *mm = vma->vm_mm;
- unsigned long size;
-
- FLUSH_BEGIN(mm)
- start &= SRMMU_PGDIR_MASK;
- size = SRMMU_PGDIR_ALIGN(end) - start;
- __asm__ __volatile__(
- "lda [%0] %5, %%g5\n\t"
- "sta %1, [%0] %5\n"
- "1:\n\t"
- "subcc %3, %4, %3\n\t"
- "bne 1b\n\t"
- " sta %%g0, [%2 + %3] %6\n\t"
- "sta %%g5, [%0] %5\n"
- : /* no outputs */
- : "r" (SRMMU_CTX_REG), "r" (mm->context), "r" (start | 0x200),
- "r" (size), "r" (SRMMU_PGDIR_SIZE), "i" (ASI_M_MMUREGS),
- "i" (ASI_M_FLUSH_PROBE)
- : "g5", "cc");
- FLUSH_END
-}
-
-static void cypress_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
-{
- struct mm_struct *mm = vma->vm_mm;
-
- FLUSH_BEGIN(mm)
- __asm__ __volatile__(
- "lda [%0] %3, %%g5\n\t"
- "sta %1, [%0] %3\n\t"
- "sta %%g0, [%2] %4\n\t"
- "sta %%g5, [%0] %3\n"
- : /* no outputs */
- : "r" (SRMMU_CTX_REG), "r" (mm->context), "r" (page & PAGE_MASK),
- "i" (ASI_M_MMUREGS), "i" (ASI_M_FLUSH_PROBE)
- : "g5");
- FLUSH_END
-}
-
/* viking.S */
extern void viking_flush_cache_all(void);
extern void viking_flush_cache_mm(struct mm_struct *mm);
@@ -1065,21 +593,21 @@ static void __init srmmu_early_allocate_ptable_skeleton(unsigned long start,
while(start < end) {
pgdp = pgd_offset_k(start);
- if(srmmu_pgd_none(*(pgd_t *)__nocache_fix(pgdp))) {
+ if (pgd_none(*(pgd_t *)__nocache_fix(pgdp))) {
pmdp = (pmd_t *) __srmmu_get_nocache(
SRMMU_PMD_TABLE_SIZE, SRMMU_PMD_TABLE_SIZE);
if (pmdp == NULL)
early_pgtable_allocfail("pmd");
memset(__nocache_fix(pmdp), 0, SRMMU_PMD_TABLE_SIZE);
- srmmu_pgd_set(__nocache_fix(pgdp), pmdp);
+ pgd_set(__nocache_fix(pgdp), pmdp);
}
- pmdp = srmmu_pmd_offset(__nocache_fix(pgdp), start);
+ pmdp = pmd_offset(__nocache_fix(pgdp), start);
if(srmmu_pmd_none(*(pmd_t *)__nocache_fix(pmdp))) {
ptep = (pte_t *)__srmmu_get_nocache(PTE_SIZE, PTE_SIZE);
if (ptep == NULL)
early_pgtable_allocfail("pte");
memset(__nocache_fix(ptep), 0, PTE_SIZE);
- srmmu_pmd_set(__nocache_fix(pmdp), ptep);
+ pmd_set(__nocache_fix(pmdp), ptep);
}
if (start > (0xffffffffUL - PMD_SIZE))
break;
@@ -1096,21 +624,21 @@ static void __init srmmu_allocate_ptable_skeleton(unsigned long start,
while(start < end) {
pgdp = pgd_offset_k(start);
- if(srmmu_pgd_none(*pgdp)) {
+ if (pgd_none(*pgdp)) {
pmdp = (pmd_t *)__srmmu_get_nocache(SRMMU_PMD_TABLE_SIZE, SRMMU_PMD_TABLE_SIZE);
if (pmdp == NULL)
early_pgtable_allocfail("pmd");
memset(pmdp, 0, SRMMU_PMD_TABLE_SIZE);
- srmmu_pgd_set(pgdp, pmdp);
+ pgd_set(pgdp, pmdp);
}
- pmdp = srmmu_pmd_offset(pgdp, start);
+ pmdp = pmd_offset(pgdp, start);
if(srmmu_pmd_none(*pmdp)) {
ptep = (pte_t *) __srmmu_get_nocache(PTE_SIZE,
PTE_SIZE);
if (ptep == NULL)
early_pgtable_allocfail("pte");
memset(ptep, 0, PTE_SIZE);
- srmmu_pmd_set(pmdp, ptep);
+ pmd_set(pmdp, ptep);
}
if (start > (0xffffffffUL - PMD_SIZE))
break;
@@ -1118,6 +646,23 @@ static void __init srmmu_allocate_ptable_skeleton(unsigned long start,
}
}
+/* These flush types are not available on all chips... */
+static inline unsigned long srmmu_probe(unsigned long vaddr)
+{
+ unsigned long retval;
+
+ if (sparc_cpu_model != sparc_leon) {
+
+ vaddr &= PAGE_MASK;
+ __asm__ __volatile__("lda [%1] %2, %0\n\t" :
+ "=r" (retval) :
+ "r" (vaddr | 0x400), "i" (ASI_M_FLUSH_PROBE));
+ } else {
+ retval = leon_swprobe(vaddr, 0);
+ }
+ return retval;
+}
+
/*
* This is much cleaner than poking around physical address space
* looking at the prom's page table directly which is what most
@@ -1137,7 +682,7 @@ static void __init srmmu_inherit_prom_mappings(unsigned long start,
break; /* probably wrap around */
if(start == 0xfef00000)
start = KADB_DEBUGGER_BEGVM;
- if(!(prompte = srmmu_hwprobe(start))) {
+ if(!(prompte = srmmu_probe(start))) {
start += PAGE_SIZE;
continue;
}
@@ -1146,12 +691,12 @@ static void __init srmmu_inherit_prom_mappings(unsigned long start,
what = 0;
if(!(start & ~(SRMMU_REAL_PMD_MASK))) {
- if(srmmu_hwprobe((start-PAGE_SIZE) + SRMMU_REAL_PMD_SIZE) == prompte)
+ if(srmmu_probe((start-PAGE_SIZE) + SRMMU_REAL_PMD_SIZE) == prompte)
what = 1;
}
if(!(start & ~(SRMMU_PGDIR_MASK))) {
- if(srmmu_hwprobe((start-PAGE_SIZE) + SRMMU_PGDIR_SIZE) ==
+ if(srmmu_probe((start-PAGE_SIZE) + SRMMU_PGDIR_SIZE) ==
prompte)
what = 2;
}
@@ -1162,21 +707,21 @@ static void __init srmmu_inherit_prom_mappings(unsigned long start,
start += SRMMU_PGDIR_SIZE;
continue;
}
- if(srmmu_pgd_none(*(pgd_t *)__nocache_fix(pgdp))) {
+ if (pgd_none(*(pgd_t *)__nocache_fix(pgdp))) {
pmdp = (pmd_t *)__srmmu_get_nocache(SRMMU_PMD_TABLE_SIZE, SRMMU_PMD_TABLE_SIZE);
if (pmdp == NULL)
early_pgtable_allocfail("pmd");
memset(__nocache_fix(pmdp), 0, SRMMU_PMD_TABLE_SIZE);
- srmmu_pgd_set(__nocache_fix(pgdp), pmdp);
+ pgd_set(__nocache_fix(pgdp), pmdp);
}
- pmdp = srmmu_pmd_offset(__nocache_fix(pgdp), start);
+ pmdp = pmd_offset(__nocache_fix(pgdp), start);
if(srmmu_pmd_none(*(pmd_t *)__nocache_fix(pmdp))) {
ptep = (pte_t *) __srmmu_get_nocache(PTE_SIZE,
PTE_SIZE);
if (ptep == NULL)
early_pgtable_allocfail("pte");
memset(__nocache_fix(ptep), 0, PTE_SIZE);
- srmmu_pmd_set(__nocache_fix(pmdp), ptep);
+ pmd_set(__nocache_fix(pmdp), ptep);
}
if(what == 1) {
/*
@@ -1190,7 +735,7 @@ static void __init srmmu_inherit_prom_mappings(unsigned long start,
start += SRMMU_REAL_PMD_SIZE;
continue;
}
- ptep = srmmu_pte_offset(__nocache_fix(pmdp), start);
+ ptep = pte_offset_kernel(__nocache_fix(pmdp), start);
*(pte_t *)__nocache_fix(ptep) = __pte(prompte);
start += PAGE_SIZE;
}
@@ -1231,13 +776,6 @@ static unsigned long __init map_spbank(unsigned long vbase, int sp_entry)
return vstart;
}
-static inline void memprobe_error(char *msg)
-{
- prom_printf(msg);
- prom_printf("Halting now...\n");
- prom_halt();
-}
-
static inline void map_kernel(void)
{
int i;
@@ -1249,8 +787,6 @@ static inline void map_kernel(void)
for (i = 0; sp_banks[i].num_bytes != 0; i++) {
map_spbank((unsigned long)__va(sp_banks[i].base_addr), i);
}
-
- BTFIXUPSET_SIMM13(user_ptrs_per_pgd, PAGE_OFFSET / SRMMU_PGDIR_SIZE);
}
/* Paging initialization on the Sparc Reference MMU. */
@@ -1312,7 +848,7 @@ void __init srmmu_paging_init(void)
srmmu_set_ctable_ptr((unsigned long)srmmu_ctx_table_phys);
#ifdef CONFIG_SMP
/* Stop from hanging here... */
- local_flush_tlb_all();
+ local_ops->tlb_all();
#else
flush_tlb_all();
#endif
@@ -1326,8 +862,8 @@ void __init srmmu_paging_init(void)
srmmu_allocate_ptable_skeleton(PKMAP_BASE, PKMAP_END);
pgd = pgd_offset_k(PKMAP_BASE);
- pmd = srmmu_pmd_offset(pgd, PKMAP_BASE);
- pte = srmmu_pte_offset(pmd, PKMAP_BASE);
+ pmd = pmd_offset(pgd, PKMAP_BASE);
+ pte = pte_offset_kernel(pmd, PKMAP_BASE);
pkmap_page_table = pte;
flush_cache_all();
@@ -1359,7 +895,7 @@ void __init srmmu_paging_init(void)
}
}
-static void srmmu_mmu_info(struct seq_file *m)
+void mmu_info(struct seq_file *m)
{
seq_printf(m,
"MMU type\t: %s\n"
@@ -1372,11 +908,7 @@ static void srmmu_mmu_info(struct seq_file *m)
srmmu_nocache_map.used << SRMMU_NOCACHE_BITMAP_SHIFT);
}
-static void srmmu_update_mmu_cache(struct vm_area_struct * vma, unsigned long address, pte_t pte)
-{
-}
-
-static void srmmu_destroy_context(struct mm_struct *mm)
+void destroy_context(struct mm_struct *mm)
{
if(mm->context != NO_CONTEXT) {
@@ -1474,6 +1006,20 @@ static void __cpuinit poke_hypersparc(void)
clear = srmmu_get_fstatus();
}
+static const struct sparc32_cachetlb_ops hypersparc_ops = {
+ .cache_all = hypersparc_flush_cache_all,
+ .cache_mm = hypersparc_flush_cache_mm,
+ .cache_page = hypersparc_flush_cache_page,
+ .cache_range = hypersparc_flush_cache_range,
+ .tlb_all = hypersparc_flush_tlb_all,
+ .tlb_mm = hypersparc_flush_tlb_mm,
+ .tlb_page = hypersparc_flush_tlb_page,
+ .tlb_range = hypersparc_flush_tlb_range,
+ .page_to_ram = hypersparc_flush_page_to_ram,
+ .sig_insns = hypersparc_flush_sig_insns,
+ .page_for_dma = hypersparc_flush_page_for_dma,
+};
+
static void __init init_hypersparc(void)
{
srmmu_name = "ROSS HyperSparc";
@@ -1482,118 +1028,13 @@ static void __init init_hypersparc(void)
init_vac_layout();
is_hypersparc = 1;
-
- BTFIXUPSET_CALL(pte_clear, srmmu_pte_clear, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(pmd_clear, srmmu_pmd_clear, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(pgd_clear, srmmu_pgd_clear, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_cache_all, hypersparc_flush_cache_all, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_cache_mm, hypersparc_flush_cache_mm, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_cache_range, hypersparc_flush_cache_range, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_cache_page, hypersparc_flush_cache_page, BTFIXUPCALL_NORM);
-
- BTFIXUPSET_CALL(flush_tlb_all, hypersparc_flush_tlb_all, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_tlb_mm, hypersparc_flush_tlb_mm, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_tlb_range, hypersparc_flush_tlb_range, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_tlb_page, hypersparc_flush_tlb_page, BTFIXUPCALL_NORM);
-
- BTFIXUPSET_CALL(__flush_page_to_ram, hypersparc_flush_page_to_ram, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_sig_insns, hypersparc_flush_sig_insns, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_page_for_dma, hypersparc_flush_page_for_dma, BTFIXUPCALL_NOP);
-
+ sparc32_cachetlb_ops = &hypersparc_ops;
poke_srmmu = poke_hypersparc;
hypersparc_setup_blockops();
}
-static void __cpuinit poke_cypress(void)
-{
- unsigned long mreg = srmmu_get_mmureg();
- unsigned long faddr, tagval;
- volatile unsigned long cypress_sucks;
- volatile unsigned long clear;
-
- clear = srmmu_get_faddr();
- clear = srmmu_get_fstatus();
-
- if (!(mreg & CYPRESS_CENABLE)) {
- for(faddr = 0x0; faddr < 0x10000; faddr += 20) {
- __asm__ __volatile__("sta %%g0, [%0 + %1] %2\n\t"
- "sta %%g0, [%0] %2\n\t" : :
- "r" (faddr), "r" (0x40000),
- "i" (ASI_M_DATAC_TAG));
- }
- } else {
- for(faddr = 0; faddr < 0x10000; faddr += 0x20) {
- __asm__ __volatile__("lda [%1 + %2] %3, %0\n\t" :
- "=r" (tagval) :
- "r" (faddr), "r" (0x40000),
- "i" (ASI_M_DATAC_TAG));
-
- /* If modified and valid, kick it. */
- if((tagval & 0x60) == 0x60)
- cypress_sucks = *(unsigned long *)
- (0xf0020000 + faddr);
- }
- }
-
- /* And one more, for our good neighbor, Mr. Broken Cypress. */
- clear = srmmu_get_faddr();
- clear = srmmu_get_fstatus();
-
- mreg |= (CYPRESS_CENABLE | CYPRESS_CMODE);
- srmmu_set_mmureg(mreg);
-}
-
-static void __init init_cypress_common(void)
-{
- init_vac_layout();
-
- BTFIXUPSET_CALL(pte_clear, srmmu_pte_clear, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(pmd_clear, srmmu_pmd_clear, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(pgd_clear, srmmu_pgd_clear, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_cache_all, cypress_flush_cache_all, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_cache_mm, cypress_flush_cache_mm, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_cache_range, cypress_flush_cache_range, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_cache_page, cypress_flush_cache_page, BTFIXUPCALL_NORM);
-
- BTFIXUPSET_CALL(flush_tlb_all, cypress_flush_tlb_all, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_tlb_mm, cypress_flush_tlb_mm, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_tlb_page, cypress_flush_tlb_page, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_tlb_range, cypress_flush_tlb_range, BTFIXUPCALL_NORM);
-
-
- BTFIXUPSET_CALL(__flush_page_to_ram, cypress_flush_page_to_ram, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_sig_insns, cypress_flush_sig_insns, BTFIXUPCALL_NOP);
- BTFIXUPSET_CALL(flush_page_for_dma, cypress_flush_page_for_dma, BTFIXUPCALL_NOP);
-
- poke_srmmu = poke_cypress;
-}
-
-static void __init init_cypress_604(void)
-{
- srmmu_name = "ROSS Cypress-604(UP)";
- srmmu_modtype = Cypress;
- init_cypress_common();
-}
-
-static void __init init_cypress_605(unsigned long mrev)
-{
- srmmu_name = "ROSS Cypress-605(MP)";
- if(mrev == 0xe) {
- srmmu_modtype = Cypress_vE;
- hwbug_bitmask |= HWBUG_COPYBACK_BROKEN;
- } else {
- if(mrev == 0xd) {
- srmmu_modtype = Cypress_vD;
- hwbug_bitmask |= HWBUG_ASIFLUSH_BROKEN;
- } else {
- srmmu_modtype = Cypress;
- }
- }
- init_cypress_common();
-}
-
static void __cpuinit poke_swift(void)
{
unsigned long mreg;
@@ -1617,6 +1058,20 @@ static void __cpuinit poke_swift(void)
srmmu_set_mmureg(mreg);
}
+static const struct sparc32_cachetlb_ops swift_ops = {
+ .cache_all = swift_flush_cache_all,
+ .cache_mm = swift_flush_cache_mm,
+ .cache_page = swift_flush_cache_page,
+ .cache_range = swift_flush_cache_range,
+ .tlb_all = swift_flush_tlb_all,
+ .tlb_mm = swift_flush_tlb_mm,
+ .tlb_page = swift_flush_tlb_page,
+ .tlb_range = swift_flush_tlb_range,
+ .page_to_ram = swift_flush_page_to_ram,
+ .sig_insns = swift_flush_sig_insns,
+ .page_for_dma = swift_flush_page_for_dma,
+};
+
#define SWIFT_MASKID_ADDR 0x10003018
static void __init init_swift(void)
{
@@ -1667,23 +1122,7 @@ static void __init init_swift(void)
break;
}
- BTFIXUPSET_CALL(flush_cache_all, swift_flush_cache_all, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_cache_mm, swift_flush_cache_mm, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_cache_page, swift_flush_cache_page, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_cache_range, swift_flush_cache_range, BTFIXUPCALL_NORM);
-
-
- BTFIXUPSET_CALL(flush_tlb_all, swift_flush_tlb_all, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_tlb_mm, swift_flush_tlb_mm, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_tlb_page, swift_flush_tlb_page, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_tlb_range, swift_flush_tlb_range, BTFIXUPCALL_NORM);
-
- BTFIXUPSET_CALL(__flush_page_to_ram, swift_flush_page_to_ram, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_sig_insns, swift_flush_sig_insns, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_page_for_dma, swift_flush_page_for_dma, BTFIXUPCALL_NORM);
-
- BTFIXUPSET_CALL(update_mmu_cache, swift_update_mmu_cache, BTFIXUPCALL_NORM);
-
+ sparc32_cachetlb_ops = &swift_ops;
flush_page_for_dma_global = 0;
/*
@@ -1734,7 +1173,7 @@ static void turbosparc_flush_page_to_ram(unsigned long page)
#ifdef TURBOSPARC_WRITEBACK
volatile unsigned long clear;
- if (srmmu_hwprobe(page))
+ if (srmmu_probe(page))
turbosparc_flush_page_cache(page);
clear = srmmu_get_fstatus();
#endif
@@ -1816,26 +1255,25 @@ static void __cpuinit poke_turbosparc(void)
srmmu_set_mmureg(mreg);
}
+static const struct sparc32_cachetlb_ops turbosparc_ops = {
+ .cache_all = turbosparc_flush_cache_all,
+ .cache_mm = turbosparc_flush_cache_mm,
+ .cache_page = turbosparc_flush_cache_page,
+ .cache_range = turbosparc_flush_cache_range,
+ .tlb_all = turbosparc_flush_tlb_all,
+ .tlb_mm = turbosparc_flush_tlb_mm,
+ .tlb_page = turbosparc_flush_tlb_page,
+ .tlb_range = turbosparc_flush_tlb_range,
+ .page_to_ram = turbosparc_flush_page_to_ram,
+ .sig_insns = turbosparc_flush_sig_insns,
+ .page_for_dma = turbosparc_flush_page_for_dma,
+};
+
static void __init init_turbosparc(void)
{
srmmu_name = "Fujitsu TurboSparc";
srmmu_modtype = TurboSparc;
-
- BTFIXUPSET_CALL(flush_cache_all, turbosparc_flush_cache_all, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_cache_mm, turbosparc_flush_cache_mm, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_cache_page, turbosparc_flush_cache_page, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_cache_range, turbosparc_flush_cache_range, BTFIXUPCALL_NORM);
-
- BTFIXUPSET_CALL(flush_tlb_all, turbosparc_flush_tlb_all, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_tlb_mm, turbosparc_flush_tlb_mm, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_tlb_page, turbosparc_flush_tlb_page, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_tlb_range, turbosparc_flush_tlb_range, BTFIXUPCALL_NORM);
-
- BTFIXUPSET_CALL(__flush_page_to_ram, turbosparc_flush_page_to_ram, BTFIXUPCALL_NORM);
-
- BTFIXUPSET_CALL(flush_sig_insns, turbosparc_flush_sig_insns, BTFIXUPCALL_NOP);
- BTFIXUPSET_CALL(flush_page_for_dma, turbosparc_flush_page_for_dma, BTFIXUPCALL_NORM);
-
+ sparc32_cachetlb_ops = &turbosparc_ops;
poke_srmmu = poke_turbosparc;
}
@@ -1850,6 +1288,20 @@ static void __cpuinit poke_tsunami(void)
srmmu_set_mmureg(mreg);
}
+static const struct sparc32_cachetlb_ops tsunami_ops = {
+ .cache_all = tsunami_flush_cache_all,
+ .cache_mm = tsunami_flush_cache_mm,
+ .cache_page = tsunami_flush_cache_page,
+ .cache_range = tsunami_flush_cache_range,
+ .tlb_all = tsunami_flush_tlb_all,
+ .tlb_mm = tsunami_flush_tlb_mm,
+ .tlb_page = tsunami_flush_tlb_page,
+ .tlb_range = tsunami_flush_tlb_range,
+ .page_to_ram = tsunami_flush_page_to_ram,
+ .sig_insns = tsunami_flush_sig_insns,
+ .page_for_dma = tsunami_flush_page_for_dma,
+};
+
static void __init init_tsunami(void)
{
/*
@@ -1860,22 +1312,7 @@ static void __init init_tsunami(void)
srmmu_name = "TI Tsunami";
srmmu_modtype = Tsunami;
-
- BTFIXUPSET_CALL(flush_cache_all, tsunami_flush_cache_all, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_cache_mm, tsunami_flush_cache_mm, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_cache_page, tsunami_flush_cache_page, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_cache_range, tsunami_flush_cache_range, BTFIXUPCALL_NORM);
-
-
- BTFIXUPSET_CALL(flush_tlb_all, tsunami_flush_tlb_all, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_tlb_mm, tsunami_flush_tlb_mm, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_tlb_page, tsunami_flush_tlb_page, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_tlb_range, tsunami_flush_tlb_range, BTFIXUPCALL_NORM);
-
- BTFIXUPSET_CALL(__flush_page_to_ram, tsunami_flush_page_to_ram, BTFIXUPCALL_NOP);
- BTFIXUPSET_CALL(flush_sig_insns, tsunami_flush_sig_insns, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_page_for_dma, tsunami_flush_page_for_dma, BTFIXUPCALL_NORM);
-
+ sparc32_cachetlb_ops = &tsunami_ops;
poke_srmmu = poke_tsunami;
tsunami_setup_blockops();
@@ -1886,7 +1323,7 @@ static void __cpuinit poke_viking(void)
unsigned long mreg = srmmu_get_mmureg();
static int smp_catch;
- if(viking_mxcc_present) {
+ if (viking_mxcc_present) {
unsigned long mxcc_control = mxcc_get_creg();
mxcc_control |= (MXCC_CTL_ECE | MXCC_CTL_PRE | MXCC_CTL_MCE);
@@ -1923,6 +1360,52 @@ static void __cpuinit poke_viking(void)
srmmu_set_mmureg(mreg);
}
+static struct sparc32_cachetlb_ops viking_ops = {
+ .cache_all = viking_flush_cache_all,
+ .cache_mm = viking_flush_cache_mm,
+ .cache_page = viking_flush_cache_page,
+ .cache_range = viking_flush_cache_range,
+ .tlb_all = viking_flush_tlb_all,
+ .tlb_mm = viking_flush_tlb_mm,
+ .tlb_page = viking_flush_tlb_page,
+ .tlb_range = viking_flush_tlb_range,
+ .page_to_ram = viking_flush_page_to_ram,
+ .sig_insns = viking_flush_sig_insns,
+ .page_for_dma = viking_flush_page_for_dma,
+};
+
+#ifdef CONFIG_SMP
+/* On sun4d the cpu broadcasts local TLB flushes, so we can just
+ * perform the local TLB flush and all the other cpus will see it.
+ * But, unfortunately, there is a bug in the sun4d XBUS backplane
+ * that requires that we add some synchronization to these flushes.
+ *
+ * The bug is that the fifo which keeps track of all the pending TLB
+ * broadcasts in the system is an entry or two too small, so if we
+ * have too many going at once we'll overflow that fifo and lose a TLB
+ * flush resulting in corruption.
+ *
+ * Our workaround is to take a global spinlock around the TLB flushes,
+ * which guarentees we won't ever have too many pending. It's a big
+ * hammer, but a semaphore like system to make sure we only have N TLB
+ * flushes going at once will require SMP locking anyways so there's
+ * no real value in trying any harder than this.
+ */
+static struct sparc32_cachetlb_ops viking_sun4d_smp_ops = {
+ .cache_all = viking_flush_cache_all,
+ .cache_mm = viking_flush_cache_mm,
+ .cache_page = viking_flush_cache_page,
+ .cache_range = viking_flush_cache_range,
+ .tlb_all = sun4dsmp_flush_tlb_all,
+ .tlb_mm = sun4dsmp_flush_tlb_mm,
+ .tlb_page = sun4dsmp_flush_tlb_page,
+ .tlb_range = sun4dsmp_flush_tlb_range,
+ .page_to_ram = viking_flush_page_to_ram,
+ .sig_insns = viking_flush_sig_insns,
+ .page_for_dma = viking_flush_page_for_dma,
+};
+#endif
+
static void __init init_viking(void)
{
unsigned long mreg = srmmu_get_mmureg();
@@ -1933,10 +1416,6 @@ static void __init init_viking(void)
viking_mxcc_present = 0;
msi_set_sync();
- BTFIXUPSET_CALL(pte_clear, srmmu_pte_clear, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(pmd_clear, srmmu_pmd_clear, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(pgd_clear, srmmu_pgd_clear, BTFIXUPCALL_NORM);
-
/*
* We need this to make sure old viking takes no hits
* on it's cache for dma snoops to workaround the
@@ -1944,84 +1423,28 @@ static void __init init_viking(void)
* This is only necessary because of the new way in
* which we use the IOMMU.
*/
- BTFIXUPSET_CALL(flush_page_for_dma, viking_flush_page, BTFIXUPCALL_NORM);
-
+ viking_ops.page_for_dma = viking_flush_page;
+#ifdef CONFIG_SMP
+ viking_sun4d_smp_ops.page_for_dma = viking_flush_page;
+#endif
flush_page_for_dma_global = 0;
} else {
srmmu_name = "TI Viking/MXCC";
viking_mxcc_present = 1;
-
srmmu_cache_pagetables = 1;
-
- /* MXCC vikings lack the DMA snooping bug. */
- BTFIXUPSET_CALL(flush_page_for_dma, viking_flush_page_for_dma, BTFIXUPCALL_NOP);
}
- BTFIXUPSET_CALL(flush_cache_all, viking_flush_cache_all, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_cache_mm, viking_flush_cache_mm, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_cache_page, viking_flush_cache_page, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_cache_range, viking_flush_cache_range, BTFIXUPCALL_NORM);
-
+ sparc32_cachetlb_ops = (const struct sparc32_cachetlb_ops *)
+ &viking_ops;
#ifdef CONFIG_SMP
- if (sparc_cpu_model == sun4d) {
- BTFIXUPSET_CALL(flush_tlb_all, sun4dsmp_flush_tlb_all, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_tlb_mm, sun4dsmp_flush_tlb_mm, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_tlb_page, sun4dsmp_flush_tlb_page, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_tlb_range, sun4dsmp_flush_tlb_range, BTFIXUPCALL_NORM);
- } else
+ if (sparc_cpu_model == sun4d)
+ sparc32_cachetlb_ops = (const struct sparc32_cachetlb_ops *)
+ &viking_sun4d_smp_ops;
#endif
- {
- BTFIXUPSET_CALL(flush_tlb_all, viking_flush_tlb_all, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_tlb_mm, viking_flush_tlb_mm, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_tlb_page, viking_flush_tlb_page, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_tlb_range, viking_flush_tlb_range, BTFIXUPCALL_NORM);
- }
-
- BTFIXUPSET_CALL(__flush_page_to_ram, viking_flush_page_to_ram, BTFIXUPCALL_NOP);
- BTFIXUPSET_CALL(flush_sig_insns, viking_flush_sig_insns, BTFIXUPCALL_NOP);
poke_srmmu = poke_viking;
}
-#ifdef CONFIG_SPARC_LEON
-
-void __init poke_leonsparc(void)
-{
-}
-
-void __init init_leon(void)
-{
-
- srmmu_name = "LEON";
-
- BTFIXUPSET_CALL(flush_cache_all, leon_flush_cache_all,
- BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_cache_mm, leon_flush_cache_all,
- BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_cache_page, leon_flush_pcache_all,
- BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_cache_range, leon_flush_cache_all,
- BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_page_for_dma, leon_flush_dcache_all,
- BTFIXUPCALL_NORM);
-
- BTFIXUPSET_CALL(flush_tlb_all, leon_flush_tlb_all, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_tlb_mm, leon_flush_tlb_all, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_tlb_page, leon_flush_tlb_all, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_tlb_range, leon_flush_tlb_all, BTFIXUPCALL_NORM);
-
- BTFIXUPSET_CALL(__flush_page_to_ram, leon_flush_cache_all,
- BTFIXUPCALL_NOP);
- BTFIXUPSET_CALL(flush_sig_insns, leon_flush_cache_all, BTFIXUPCALL_NOP);
-
- poke_srmmu = poke_leonsparc;
-
- srmmu_cache_pagetables = 0;
-
- leon_flush_during_switch = leon_flush_needed();
-}
-#endif
-
/* Probe for the srmmu chip version. */
static void __init get_srmmu_type(void)
{
@@ -2052,22 +1475,15 @@ static void __init get_srmmu_type(void)
break;
case 0:
case 2:
- /* Uniprocessor Cypress */
- init_cypress_604();
- break;
case 10:
case 11:
case 12:
- /* _REALLY OLD_ Cypress MP chips... */
case 13:
case 14:
case 15:
- /* MP Cypress mmu/cache-controller */
- init_cypress_605(mod_rev);
- break;
default:
- /* Some other Cypress revision, assume a 605. */
- init_cypress_605(mod_rev);
+ prom_printf("Sparc-Linux Cypress support does not longer exit.\n");
+ prom_halt();
break;
}
return;
@@ -2123,203 +1539,193 @@ static void __init get_srmmu_type(void)
srmmu_is_bad();
}
-/* don't laugh, static pagetables */
-static void srmmu_check_pgt_cache(int low, int high)
+#ifdef CONFIG_SMP
+/* Local cross-calls. */
+static void smp_flush_page_for_dma(unsigned long page)
{
+ xc1((smpfunc_t) local_ops->page_for_dma, page);
+ local_ops->page_for_dma(page);
}
-extern unsigned long spwin_mmu_patchme, fwin_mmu_patchme,
- tsetup_mmu_patchme, rtrap_mmu_patchme;
-
-extern unsigned long spwin_srmmu_stackchk, srmmu_fwin_stackchk,
- tsetup_srmmu_stackchk, srmmu_rett_stackchk;
-
-extern unsigned long srmmu_fault;
-
-#define PATCH_BRANCH(insn, dest) do { \
- iaddr = &(insn); \
- daddr = &(dest); \
- *iaddr = SPARC_BRANCH((unsigned long) daddr, (unsigned long) iaddr); \
- } while(0)
-
-static void __init patch_window_trap_handlers(void)
+static void smp_flush_cache_all(void)
{
- unsigned long *iaddr, *daddr;
-
- PATCH_BRANCH(spwin_mmu_patchme, spwin_srmmu_stackchk);
- PATCH_BRANCH(fwin_mmu_patchme, srmmu_fwin_stackchk);
- PATCH_BRANCH(tsetup_mmu_patchme, tsetup_srmmu_stackchk);
- PATCH_BRANCH(rtrap_mmu_patchme, srmmu_rett_stackchk);
- PATCH_BRANCH(sparc_ttable[SP_TRAP_TFLT].inst_three, srmmu_fault);
- PATCH_BRANCH(sparc_ttable[SP_TRAP_DFLT].inst_three, srmmu_fault);
- PATCH_BRANCH(sparc_ttable[SP_TRAP_DACC].inst_three, srmmu_fault);
+ xc0((smpfunc_t) local_ops->cache_all);
+ local_ops->cache_all();
}
-#ifdef CONFIG_SMP
-/* Local cross-calls. */
-static void smp_flush_page_for_dma(unsigned long page)
+static void smp_flush_tlb_all(void)
{
- xc1((smpfunc_t) BTFIXUP_CALL(local_flush_page_for_dma), page);
- local_flush_page_for_dma(page);
+ xc0((smpfunc_t) local_ops->tlb_all);
+ local_ops->tlb_all();
}
-#endif
-
-static pte_t srmmu_pgoff_to_pte(unsigned long pgoff)
+static void smp_flush_cache_mm(struct mm_struct *mm)
{
- return __pte((pgoff << SRMMU_PTE_FILE_SHIFT) | SRMMU_FILE);
+ if (mm->context != NO_CONTEXT) {
+ cpumask_t cpu_mask;
+ cpumask_copy(&cpu_mask, mm_cpumask(mm));
+ cpumask_clear_cpu(smp_processor_id(), &cpu_mask);
+ if (!cpumask_empty(&cpu_mask))
+ xc1((smpfunc_t) local_ops->cache_mm, (unsigned long) mm);
+ local_ops->cache_mm(mm);
+ }
}
-static unsigned long srmmu_pte_to_pgoff(pte_t pte)
+static void smp_flush_tlb_mm(struct mm_struct *mm)
{
- return pte_val(pte) >> SRMMU_PTE_FILE_SHIFT;
+ if (mm->context != NO_CONTEXT) {
+ cpumask_t cpu_mask;
+ cpumask_copy(&cpu_mask, mm_cpumask(mm));
+ cpumask_clear_cpu(smp_processor_id(), &cpu_mask);
+ if (!cpumask_empty(&cpu_mask)) {
+ xc1((smpfunc_t) local_ops->tlb_mm, (unsigned long) mm);
+ if (atomic_read(&mm->mm_users) == 1 && current->active_mm == mm)
+ cpumask_copy(mm_cpumask(mm),
+ cpumask_of(smp_processor_id()));
+ }
+ local_ops->tlb_mm(mm);
+ }
}
-static pgprot_t srmmu_pgprot_noncached(pgprot_t prot)
+static void smp_flush_cache_range(struct vm_area_struct *vma,
+ unsigned long start,
+ unsigned long end)
{
- prot &= ~__pgprot(SRMMU_CACHE);
+ struct mm_struct *mm = vma->vm_mm;
- return prot;
+ if (mm->context != NO_CONTEXT) {
+ cpumask_t cpu_mask;
+ cpumask_copy(&cpu_mask, mm_cpumask(mm));
+ cpumask_clear_cpu(smp_processor_id(), &cpu_mask);
+ if (!cpumask_empty(&cpu_mask))
+ xc3((smpfunc_t) local_ops->cache_range,
+ (unsigned long) vma, start, end);
+ local_ops->cache_range(vma, start, end);
+ }
}
-/* Load up routines and constants for sun4m and sun4d mmu */
-void __init ld_mmu_srmmu(void)
+static void smp_flush_tlb_range(struct vm_area_struct *vma,
+ unsigned long start,
+ unsigned long end)
{
- extern void ld_mmu_iommu(void);
- extern void ld_mmu_iounit(void);
- extern void ___xchg32_sun4md(void);
-
- BTFIXUPSET_SIMM13(pgdir_shift, SRMMU_PGDIR_SHIFT);
- BTFIXUPSET_SETHI(pgdir_size, SRMMU_PGDIR_SIZE);
- BTFIXUPSET_SETHI(pgdir_mask, SRMMU_PGDIR_MASK);
-
- BTFIXUPSET_SIMM13(ptrs_per_pmd, SRMMU_PTRS_PER_PMD);
- BTFIXUPSET_SIMM13(ptrs_per_pgd, SRMMU_PTRS_PER_PGD);
-
- BTFIXUPSET_INT(page_none, pgprot_val(SRMMU_PAGE_NONE));
- PAGE_SHARED = pgprot_val(SRMMU_PAGE_SHARED);
- BTFIXUPSET_INT(page_copy, pgprot_val(SRMMU_PAGE_COPY));
- BTFIXUPSET_INT(page_readonly, pgprot_val(SRMMU_PAGE_RDONLY));
- BTFIXUPSET_INT(page_kernel, pgprot_val(SRMMU_PAGE_KERNEL));
- page_kernel = pgprot_val(SRMMU_PAGE_KERNEL);
+ struct mm_struct *mm = vma->vm_mm;
- /* Functions */
- BTFIXUPSET_CALL(pgprot_noncached, srmmu_pgprot_noncached, BTFIXUPCALL_NORM);
-#ifndef CONFIG_SMP
- BTFIXUPSET_CALL(___xchg32, ___xchg32_sun4md, BTFIXUPCALL_SWAPG1G2);
-#endif
- BTFIXUPSET_CALL(do_check_pgt_cache, srmmu_check_pgt_cache, BTFIXUPCALL_NOP);
+ if (mm->context != NO_CONTEXT) {
+ cpumask_t cpu_mask;
+ cpumask_copy(&cpu_mask, mm_cpumask(mm));
+ cpumask_clear_cpu(smp_processor_id(), &cpu_mask);
+ if (!cpumask_empty(&cpu_mask))
+ xc3((smpfunc_t) local_ops->tlb_range,
+ (unsigned long) vma, start, end);
+ local_ops->tlb_range(vma, start, end);
+ }
+}
- BTFIXUPSET_CALL(set_pte, srmmu_set_pte, BTFIXUPCALL_SWAPO0O1);
- BTFIXUPSET_CALL(switch_mm, srmmu_switch_mm, BTFIXUPCALL_NORM);
+static void smp_flush_cache_page(struct vm_area_struct *vma, unsigned long page)
+{
+ struct mm_struct *mm = vma->vm_mm;
- BTFIXUPSET_CALL(pte_pfn, srmmu_pte_pfn, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(pmd_page, srmmu_pmd_page, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(pgd_page_vaddr, srmmu_pgd_page, BTFIXUPCALL_NORM);
+ if (mm->context != NO_CONTEXT) {
+ cpumask_t cpu_mask;
+ cpumask_copy(&cpu_mask, mm_cpumask(mm));
+ cpumask_clear_cpu(smp_processor_id(), &cpu_mask);
+ if (!cpumask_empty(&cpu_mask))
+ xc2((smpfunc_t) local_ops->cache_page,
+ (unsigned long) vma, page);
+ local_ops->cache_page(vma, page);
+ }
+}
- BTFIXUPSET_CALL(pte_present, srmmu_pte_present, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(pte_clear, srmmu_pte_clear, BTFIXUPCALL_SWAPO0G0);
+static void smp_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
+{
+ struct mm_struct *mm = vma->vm_mm;
- BTFIXUPSET_CALL(pmd_bad, srmmu_pmd_bad, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(pmd_present, srmmu_pmd_present, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(pmd_clear, srmmu_pmd_clear, BTFIXUPCALL_SWAPO0G0);
+ if (mm->context != NO_CONTEXT) {
+ cpumask_t cpu_mask;
+ cpumask_copy(&cpu_mask, mm_cpumask(mm));
+ cpumask_clear_cpu(smp_processor_id(), &cpu_mask);
+ if (!cpumask_empty(&cpu_mask))
+ xc2((smpfunc_t) local_ops->tlb_page,
+ (unsigned long) vma, page);
+ local_ops->tlb_page(vma, page);
+ }
+}
- BTFIXUPSET_CALL(pgd_none, srmmu_pgd_none, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(pgd_bad, srmmu_pgd_bad, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(pgd_present, srmmu_pgd_present, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(pgd_clear, srmmu_pgd_clear, BTFIXUPCALL_SWAPO0G0);
+static void smp_flush_page_to_ram(unsigned long page)
+{
+ /* Current theory is that those who call this are the one's
+ * who have just dirtied their cache with the pages contents
+ * in kernel space, therefore we only run this on local cpu.
+ *
+ * XXX This experiment failed, research further... -DaveM
+ */
+#if 1
+ xc1((smpfunc_t) local_ops->page_to_ram, page);
+#endif
+ local_ops->page_to_ram(page);
+}
+
+static void smp_flush_sig_insns(struct mm_struct *mm, unsigned long insn_addr)
+{
+ cpumask_t cpu_mask;
+ cpumask_copy(&cpu_mask, mm_cpumask(mm));
+ cpumask_clear_cpu(smp_processor_id(), &cpu_mask);
+ if (!cpumask_empty(&cpu_mask))
+ xc2((smpfunc_t) local_ops->sig_insns,
+ (unsigned long) mm, insn_addr);
+ local_ops->sig_insns(mm, insn_addr);
+}
+
+static struct sparc32_cachetlb_ops smp_cachetlb_ops = {
+ .cache_all = smp_flush_cache_all,
+ .cache_mm = smp_flush_cache_mm,
+ .cache_page = smp_flush_cache_page,
+ .cache_range = smp_flush_cache_range,
+ .tlb_all = smp_flush_tlb_all,
+ .tlb_mm = smp_flush_tlb_mm,
+ .tlb_page = smp_flush_tlb_page,
+ .tlb_range = smp_flush_tlb_range,
+ .page_to_ram = smp_flush_page_to_ram,
+ .sig_insns = smp_flush_sig_insns,
+ .page_for_dma = smp_flush_page_for_dma,
+};
+#endif
- BTFIXUPSET_CALL(mk_pte, srmmu_mk_pte, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(mk_pte_phys, srmmu_mk_pte_phys, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(mk_pte_io, srmmu_mk_pte_io, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(pgd_set, srmmu_pgd_set, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(pmd_set, srmmu_pmd_set, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(pmd_populate, srmmu_pmd_populate, BTFIXUPCALL_NORM);
-
- BTFIXUPSET_INT(pte_modify_mask, SRMMU_CHG_MASK);
- BTFIXUPSET_CALL(pmd_offset, srmmu_pmd_offset, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(pte_offset_kernel, srmmu_pte_offset, BTFIXUPCALL_NORM);
-
- BTFIXUPSET_CALL(free_pte_fast, srmmu_free_pte_fast, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(pte_free, srmmu_pte_free, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(pte_alloc_one_kernel, srmmu_pte_alloc_one_kernel, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(pte_alloc_one, srmmu_pte_alloc_one, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(free_pmd_fast, srmmu_pmd_free, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(pmd_alloc_one, srmmu_pmd_alloc_one, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(free_pgd_fast, srmmu_free_pgd_fast, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(get_pgd_fast, srmmu_get_pgd_fast, BTFIXUPCALL_NORM);
-
- BTFIXUPSET_HALF(pte_writei, SRMMU_WRITE);
- BTFIXUPSET_HALF(pte_dirtyi, SRMMU_DIRTY);
- BTFIXUPSET_HALF(pte_youngi, SRMMU_REF);
- BTFIXUPSET_HALF(pte_filei, SRMMU_FILE);
- BTFIXUPSET_HALF(pte_wrprotecti, SRMMU_WRITE);
- BTFIXUPSET_HALF(pte_mkcleani, SRMMU_DIRTY);
- BTFIXUPSET_HALF(pte_mkoldi, SRMMU_REF);
- BTFIXUPSET_CALL(pte_mkwrite, srmmu_pte_mkwrite, BTFIXUPCALL_ORINT(SRMMU_WRITE));
- BTFIXUPSET_CALL(pte_mkdirty, srmmu_pte_mkdirty, BTFIXUPCALL_ORINT(SRMMU_DIRTY));
- BTFIXUPSET_CALL(pte_mkyoung, srmmu_pte_mkyoung, BTFIXUPCALL_ORINT(SRMMU_REF));
- BTFIXUPSET_CALL(update_mmu_cache, srmmu_update_mmu_cache, BTFIXUPCALL_NOP);
- BTFIXUPSET_CALL(destroy_context, srmmu_destroy_context, BTFIXUPCALL_NORM);
-
- BTFIXUPSET_CALL(sparc_mapiorange, srmmu_mapiorange, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(sparc_unmapiorange, srmmu_unmapiorange, BTFIXUPCALL_NORM);
-
- BTFIXUPSET_CALL(__swp_type, srmmu_swp_type, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(__swp_offset, srmmu_swp_offset, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(__swp_entry, srmmu_swp_entry, BTFIXUPCALL_NORM);
-
- BTFIXUPSET_CALL(mmu_info, srmmu_mmu_info, BTFIXUPCALL_NORM);
-
- BTFIXUPSET_CALL(alloc_thread_info_node, srmmu_alloc_thread_info_node, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(free_thread_info, srmmu_free_thread_info, BTFIXUPCALL_NORM);
-
- BTFIXUPSET_CALL(pte_to_pgoff, srmmu_pte_to_pgoff, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(pgoff_to_pte, srmmu_pgoff_to_pte, BTFIXUPCALL_NORM);
+/* Load up routines and constants for sun4m and sun4d mmu */
+void __init load_mmu(void)
+{
+ extern void ld_mmu_iommu(void);
+ extern void ld_mmu_iounit(void);
+ /* Functions */
get_srmmu_type();
- patch_window_trap_handlers();
#ifdef CONFIG_SMP
/* El switcheroo... */
+ local_ops = sparc32_cachetlb_ops;
- BTFIXUPCOPY_CALL(local_flush_cache_all, flush_cache_all);
- BTFIXUPCOPY_CALL(local_flush_cache_mm, flush_cache_mm);
- BTFIXUPCOPY_CALL(local_flush_cache_range, flush_cache_range);
- BTFIXUPCOPY_CALL(local_flush_cache_page, flush_cache_page);
- BTFIXUPCOPY_CALL(local_flush_tlb_all, flush_tlb_all);
- BTFIXUPCOPY_CALL(local_flush_tlb_mm, flush_tlb_mm);
- BTFIXUPCOPY_CALL(local_flush_tlb_range, flush_tlb_range);
- BTFIXUPCOPY_CALL(local_flush_tlb_page, flush_tlb_page);
- BTFIXUPCOPY_CALL(local_flush_page_to_ram, __flush_page_to_ram);
- BTFIXUPCOPY_CALL(local_flush_sig_insns, flush_sig_insns);
- BTFIXUPCOPY_CALL(local_flush_page_for_dma, flush_page_for_dma);
-
- BTFIXUPSET_CALL(flush_cache_all, smp_flush_cache_all, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_cache_mm, smp_flush_cache_mm, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_cache_range, smp_flush_cache_range, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_cache_page, smp_flush_cache_page, BTFIXUPCALL_NORM);
- if (sparc_cpu_model != sun4d &&
- sparc_cpu_model != sparc_leon) {
- BTFIXUPSET_CALL(flush_tlb_all, smp_flush_tlb_all, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_tlb_mm, smp_flush_tlb_mm, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_tlb_range, smp_flush_tlb_range, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_tlb_page, smp_flush_tlb_page, BTFIXUPCALL_NORM);
+ if (sparc_cpu_model == sun4d || sparc_cpu_model == sparc_leon) {
+ smp_cachetlb_ops.tlb_all = local_ops->tlb_all;
+ smp_cachetlb_ops.tlb_mm = local_ops->tlb_mm;
+ smp_cachetlb_ops.tlb_range = local_ops->tlb_range;
+ smp_cachetlb_ops.tlb_page = local_ops->tlb_page;
}
- BTFIXUPSET_CALL(__flush_page_to_ram, smp_flush_page_to_ram, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_sig_insns, smp_flush_sig_insns, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_page_for_dma, smp_flush_page_for_dma, BTFIXUPCALL_NORM);
if (poke_srmmu == poke_viking) {
/* Avoid unnecessary cross calls. */
- BTFIXUPCOPY_CALL(flush_cache_all, local_flush_cache_all);
- BTFIXUPCOPY_CALL(flush_cache_mm, local_flush_cache_mm);
- BTFIXUPCOPY_CALL(flush_cache_range, local_flush_cache_range);
- BTFIXUPCOPY_CALL(flush_cache_page, local_flush_cache_page);
- BTFIXUPCOPY_CALL(__flush_page_to_ram, local_flush_page_to_ram);
- BTFIXUPCOPY_CALL(flush_sig_insns, local_flush_sig_insns);
- BTFIXUPCOPY_CALL(flush_page_for_dma, local_flush_page_for_dma);
+ smp_cachetlb_ops.cache_all = local_ops->cache_all;
+ smp_cachetlb_ops.cache_mm = local_ops->cache_mm;
+ smp_cachetlb_ops.cache_range = local_ops->cache_range;
+ smp_cachetlb_ops.cache_page = local_ops->cache_page;
+
+ smp_cachetlb_ops.page_to_ram = local_ops->page_to_ram;
+ smp_cachetlb_ops.sig_insns = local_ops->sig_insns;
+ smp_cachetlb_ops.page_for_dma = local_ops->page_for_dma;
}
+
+ /* It really is const after this point. */
+ sparc32_cachetlb_ops = (const struct sparc32_cachetlb_ops *)
+ &smp_cachetlb_ops;
#endif
if (sparc_cpu_model == sun4d)
diff --git a/arch/sparc/mm/srmmu.h b/arch/sparc/mm/srmmu.h
new file mode 100644
index 000000000000..5703274ccf89
--- /dev/null
+++ b/arch/sparc/mm/srmmu.h
@@ -0,0 +1,4 @@
+/* srmmu.c */
+extern char *srmmu_name;
+
+extern void (*poke_srmmu)(void);
diff --git a/arch/sparc/mm/srmmu_access.S b/arch/sparc/mm/srmmu_access.S
new file mode 100644
index 000000000000..d0a67b2c2383
--- /dev/null
+++ b/arch/sparc/mm/srmmu_access.S
@@ -0,0 +1,82 @@
+/* Assembler variants of srmmu access functions.
+ * Implemented in assembler to allow run-time patching.
+ * LEON uses a different ASI for MMUREGS than SUN.
+ *
+ * The leon_1insn_patch infrastructure is used
+ * for the run-time patching.
+ */
+
+#include <linux/linkage.h>
+
+#include <asm/asmmacro.h>
+#include <asm/pgtsrmmu.h>
+#include <asm/asi.h>
+
+/* unsigned int srmmu_get_mmureg(void) */
+ENTRY(srmmu_get_mmureg)
+LEON_PI(lda [%g0] ASI_LEON_MMUREGS, %o0)
+SUN_PI_(lda [%g0] ASI_M_MMUREGS, %o0)
+ retl
+ nop
+ENDPROC(srmmu_get_mmureg)
+
+/* void srmmu_set_mmureg(unsigned long regval) */
+ENTRY(srmmu_set_mmureg)
+LEON_PI(sta %o0, [%g0] ASI_LEON_MMUREGS)
+SUN_PI_(sta %o0, [%g0] ASI_M_MMUREGS)
+ retl
+ nop
+ENDPROC(srmmu_set_mmureg)
+
+/* void srmmu_set_ctable_ptr(unsigned long paddr) */
+ENTRY(srmmu_set_ctable_ptr)
+ /* paddr = ((paddr >> 4) & SRMMU_CTX_PMASK); */
+ srl %o0, 4, %g1
+ and %g1, SRMMU_CTX_PMASK, %g1
+
+ mov SRMMU_CTXTBL_PTR, %g2
+LEON_PI(sta %g1, [%g2] ASI_LEON_MMUREGS)
+SUN_PI_(sta %g1, [%g2] ASI_M_MMUREGS)
+ retl
+ nop
+ENDPROC(srmmu_set_ctable_ptr)
+
+
+/* void srmmu_set_context(int context) */
+ENTRY(srmmu_set_context)
+ mov SRMMU_CTX_REG, %g1
+LEON_PI(sta %o0, [%g1] ASI_LEON_MMUREGS)
+SUN_PI_(sta %o0, [%g1] ASI_M_MMUREGS)
+ retl
+ nop
+ENDPROC(srmmu_set_context)
+
+
+/* int srmmu_get_context(void) */
+ENTRY(srmmu_get_context)
+ mov SRMMU_CTX_REG, %o0
+LEON_PI(lda [%o0] ASI_LEON_MMUREGS, %o0)
+SUN_PI_(lda [%o0] ASI_M_MMUREGS, %o0)
+ retl
+ nop
+ENDPROC(srmmu_get_context)
+
+
+/* unsigned int srmmu_get_fstatus(void) */
+ENTRY(srmmu_get_fstatus)
+ mov SRMMU_FAULT_STATUS, %o0
+LEON_PI(lda [%o0] ASI_LEON_MMUREGS, %o0)
+SUN_PI_(lda [%o0] ASI_M_MMUREGS, %o0)
+ retl
+ nop
+ENDPROC(srmmu_get_fstatus)
+
+
+/* unsigned int srmmu_get_faddr(void) */
+ENTRY(srmmu_get_faddr)
+ mov SRMMU_FAULT_ADDR, %o0
+LEON_PI(lda [%o0] ASI_LEON_MMUREGS, %o0)
+SUN_PI_(lda [%o0] ASI_M_MMUREGS, %o0)
+ retl
+ nop
+ENDPROC(srmmu_get_faddr)
diff --git a/arch/sparc/mm/sun4c.c b/arch/sparc/mm/sun4c.c
deleted file mode 100644
index 1cf4f198709a..000000000000
--- a/arch/sparc/mm/sun4c.c
+++ /dev/null
@@ -1,2166 +0,0 @@
-/* sun4c.c: Doing in software what should be done in hardware.
- *
- * Copyright (C) 1996 David S. Miller (davem@davemloft.net)
- * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
- * Copyright (C) 1996 Andrew Tridgell (Andrew.Tridgell@anu.edu.au)
- * Copyright (C) 1997-2000 Anton Blanchard (anton@samba.org)
- * Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
- */
-
-#define NR_TASK_BUCKETS 512
-
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/bootmem.h>
-#include <linux/highmem.h>
-#include <linux/fs.h>
-#include <linux/seq_file.h>
-#include <linux/scatterlist.h>
-#include <linux/bitmap.h>
-
-#include <asm/sections.h>
-#include <asm/page.h>
-#include <asm/pgalloc.h>
-#include <asm/pgtable.h>
-#include <asm/vaddrs.h>
-#include <asm/idprom.h>
-#include <asm/machines.h>
-#include <asm/memreg.h>
-#include <asm/processor.h>
-#include <asm/auxio.h>
-#include <asm/io.h>
-#include <asm/oplib.h>
-#include <asm/openprom.h>
-#include <asm/mmu_context.h>
-#include <asm/highmem.h>
-#include <asm/btfixup.h>
-#include <asm/cacheflush.h>
-#include <asm/tlbflush.h>
-
-/* Because of our dynamic kernel TLB miss strategy, and how
- * our DVMA mapping allocation works, you _MUST_:
- *
- * 1) Disable interrupts _and_ not touch any dynamic kernel
- * memory while messing with kernel MMU state. By
- * dynamic memory I mean any object which is not in
- * the kernel image itself or a thread_union (both of
- * which are locked into the MMU).
- * 2) Disable interrupts while messing with user MMU state.
- */
-
-extern int num_segmaps, num_contexts;
-
-extern unsigned long page_kernel;
-
-/* That's it, we prom_halt() on sun4c if the cache size is something other than 65536.
- * So let's save some cycles and just use that everywhere except for that bootup
- * sanity check.
- */
-#define SUN4C_VAC_SIZE 65536
-
-#define SUN4C_KERNEL_BUCKETS 32
-
-/* Flushing the cache. */
-struct sun4c_vac_props sun4c_vacinfo;
-unsigned long sun4c_kernel_faults;
-
-/* Invalidate every sun4c cache line tag. */
-static void __init sun4c_flush_all(void)
-{
- unsigned long begin, end;
-
- if (sun4c_vacinfo.on)
- panic("SUN4C: AIEEE, trying to invalidate vac while it is on.");
-
- /* Clear 'valid' bit in all cache line tags */
- begin = AC_CACHETAGS;
- end = (AC_CACHETAGS + SUN4C_VAC_SIZE);
- while (begin < end) {
- __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
- "r" (begin), "i" (ASI_CONTROL));
- begin += sun4c_vacinfo.linesize;
- }
-}
-
-static void sun4c_flush_context_hw(void)
-{
- unsigned long end = SUN4C_VAC_SIZE;
-
- __asm__ __volatile__(
- "1: addcc %0, -4096, %0\n\t"
- " bne 1b\n\t"
- " sta %%g0, [%0] %2"
- : "=&r" (end)
- : "0" (end), "i" (ASI_HWFLUSHCONTEXT)
- : "cc");
-}
-
-/* Must be called minimally with IRQs disabled. */
-static void sun4c_flush_segment_hw(unsigned long addr)
-{
- if (sun4c_get_segmap(addr) != invalid_segment) {
- unsigned long vac_size = SUN4C_VAC_SIZE;
-
- __asm__ __volatile__(
- "1: addcc %0, -4096, %0\n\t"
- " bne 1b\n\t"
- " sta %%g0, [%2 + %0] %3"
- : "=&r" (vac_size)
- : "0" (vac_size), "r" (addr), "i" (ASI_HWFLUSHSEG)
- : "cc");
- }
-}
-
-/* File local boot time fixups. */
-BTFIXUPDEF_CALL(void, sun4c_flush_page, unsigned long)
-BTFIXUPDEF_CALL(void, sun4c_flush_segment, unsigned long)
-BTFIXUPDEF_CALL(void, sun4c_flush_context, void)
-
-#define sun4c_flush_page(addr) BTFIXUP_CALL(sun4c_flush_page)(addr)
-#define sun4c_flush_segment(addr) BTFIXUP_CALL(sun4c_flush_segment)(addr)
-#define sun4c_flush_context() BTFIXUP_CALL(sun4c_flush_context)()
-
-/* Must be called minimally with interrupts disabled. */
-static void sun4c_flush_page_hw(unsigned long addr)
-{
- addr &= PAGE_MASK;
- if ((int)sun4c_get_pte(addr) < 0)
- __asm__ __volatile__("sta %%g0, [%0] %1"
- : : "r" (addr), "i" (ASI_HWFLUSHPAGE));
-}
-
-/* Don't inline the software version as it eats too many cache lines if expanded. */
-static void sun4c_flush_context_sw(void)
-{
- unsigned long nbytes = SUN4C_VAC_SIZE;
- unsigned long lsize = sun4c_vacinfo.linesize;
-
- __asm__ __volatile__(
- "add %2, %2, %%g1\n\t"
- "add %2, %%g1, %%g2\n\t"
- "add %2, %%g2, %%g3\n\t"
- "add %2, %%g3, %%g4\n\t"
- "add %2, %%g4, %%g5\n\t"
- "add %2, %%g5, %%o4\n\t"
- "add %2, %%o4, %%o5\n"
- "1:\n\t"
- "subcc %0, %%o5, %0\n\t"
- "sta %%g0, [%0] %3\n\t"
- "sta %%g0, [%0 + %2] %3\n\t"
- "sta %%g0, [%0 + %%g1] %3\n\t"
- "sta %%g0, [%0 + %%g2] %3\n\t"
- "sta %%g0, [%0 + %%g3] %3\n\t"
- "sta %%g0, [%0 + %%g4] %3\n\t"
- "sta %%g0, [%0 + %%g5] %3\n\t"
- "bg 1b\n\t"
- " sta %%g0, [%1 + %%o4] %3\n"
- : "=&r" (nbytes)
- : "0" (nbytes), "r" (lsize), "i" (ASI_FLUSHCTX)
- : "g1", "g2", "g3", "g4", "g5", "o4", "o5", "cc");
-}
-
-/* Don't inline the software version as it eats too many cache lines if expanded. */
-static void sun4c_flush_segment_sw(unsigned long addr)
-{
- if (sun4c_get_segmap(addr) != invalid_segment) {
- unsigned long nbytes = SUN4C_VAC_SIZE;
- unsigned long lsize = sun4c_vacinfo.linesize;
-
- __asm__ __volatile__(
- "add %2, %2, %%g1\n\t"
- "add %2, %%g1, %%g2\n\t"
- "add %2, %%g2, %%g3\n\t"
- "add %2, %%g3, %%g4\n\t"
- "add %2, %%g4, %%g5\n\t"
- "add %2, %%g5, %%o4\n\t"
- "add %2, %%o4, %%o5\n"
- "1:\n\t"
- "subcc %1, %%o5, %1\n\t"
- "sta %%g0, [%0] %6\n\t"
- "sta %%g0, [%0 + %2] %6\n\t"
- "sta %%g0, [%0 + %%g1] %6\n\t"
- "sta %%g0, [%0 + %%g2] %6\n\t"
- "sta %%g0, [%0 + %%g3] %6\n\t"
- "sta %%g0, [%0 + %%g4] %6\n\t"
- "sta %%g0, [%0 + %%g5] %6\n\t"
- "sta %%g0, [%0 + %%o4] %6\n\t"
- "bg 1b\n\t"
- " add %0, %%o5, %0\n"
- : "=&r" (addr), "=&r" (nbytes), "=&r" (lsize)
- : "0" (addr), "1" (nbytes), "2" (lsize),
- "i" (ASI_FLUSHSEG)
- : "g1", "g2", "g3", "g4", "g5", "o4", "o5", "cc");
- }
-}
-
-/* Don't inline the software version as it eats too many cache lines if expanded. */
-static void sun4c_flush_page_sw(unsigned long addr)
-{
- addr &= PAGE_MASK;
- if ((sun4c_get_pte(addr) & (_SUN4C_PAGE_NOCACHE | _SUN4C_PAGE_VALID)) ==
- _SUN4C_PAGE_VALID) {
- unsigned long left = PAGE_SIZE;
- unsigned long lsize = sun4c_vacinfo.linesize;
-
- __asm__ __volatile__(
- "add %2, %2, %%g1\n\t"
- "add %2, %%g1, %%g2\n\t"
- "add %2, %%g2, %%g3\n\t"
- "add %2, %%g3, %%g4\n\t"
- "add %2, %%g4, %%g5\n\t"
- "add %2, %%g5, %%o4\n\t"
- "add %2, %%o4, %%o5\n"
- "1:\n\t"
- "subcc %1, %%o5, %1\n\t"
- "sta %%g0, [%0] %6\n\t"
- "sta %%g0, [%0 + %2] %6\n\t"
- "sta %%g0, [%0 + %%g1] %6\n\t"
- "sta %%g0, [%0 + %%g2] %6\n\t"
- "sta %%g0, [%0 + %%g3] %6\n\t"
- "sta %%g0, [%0 + %%g4] %6\n\t"
- "sta %%g0, [%0 + %%g5] %6\n\t"
- "sta %%g0, [%0 + %%o4] %6\n\t"
- "bg 1b\n\t"
- " add %0, %%o5, %0\n"
- : "=&r" (addr), "=&r" (left), "=&r" (lsize)
- : "0" (addr), "1" (left), "2" (lsize),
- "i" (ASI_FLUSHPG)
- : "g1", "g2", "g3", "g4", "g5", "o4", "o5", "cc");
- }
-}
-
-/* The sun4c's do have an on chip store buffer. And the way you
- * clear them out isn't so obvious. The only way I can think of
- * to accomplish this is to read the current context register,
- * store the same value there, then read an external hardware
- * register.
- */
-void sun4c_complete_all_stores(void)
-{
- volatile int _unused;
-
- _unused = sun4c_get_context();
- sun4c_set_context(_unused);
- _unused = get_auxio();
-}
-
-/* Bootup utility functions. */
-static inline void sun4c_init_clean_segmap(unsigned char pseg)
-{
- unsigned long vaddr;
-
- sun4c_put_segmap(0, pseg);
- for (vaddr = 0; vaddr < SUN4C_REAL_PGDIR_SIZE; vaddr += PAGE_SIZE)
- sun4c_put_pte(vaddr, 0);
- sun4c_put_segmap(0, invalid_segment);
-}
-
-static inline void sun4c_init_clean_mmu(unsigned long kernel_end)
-{
- unsigned long vaddr;
- unsigned char savectx, ctx;
-
- savectx = sun4c_get_context();
- for (ctx = 0; ctx < num_contexts; ctx++) {
- sun4c_set_context(ctx);
- for (vaddr = 0; vaddr < 0x20000000; vaddr += SUN4C_REAL_PGDIR_SIZE)
- sun4c_put_segmap(vaddr, invalid_segment);
- for (vaddr = 0xe0000000; vaddr < KERNBASE; vaddr += SUN4C_REAL_PGDIR_SIZE)
- sun4c_put_segmap(vaddr, invalid_segment);
- for (vaddr = kernel_end; vaddr < KADB_DEBUGGER_BEGVM; vaddr += SUN4C_REAL_PGDIR_SIZE)
- sun4c_put_segmap(vaddr, invalid_segment);
- for (vaddr = LINUX_OPPROM_ENDVM; vaddr; vaddr += SUN4C_REAL_PGDIR_SIZE)
- sun4c_put_segmap(vaddr, invalid_segment);
- }
- sun4c_set_context(savectx);
-}
-
-void __init sun4c_probe_vac(void)
-{
- sun4c_disable_vac();
-
- if ((idprom->id_machtype == (SM_SUN4C | SM_4C_SS1)) ||
- (idprom->id_machtype == (SM_SUN4C | SM_4C_SS1PLUS))) {
- /* PROM on SS1 lacks this info, to be super safe we
- * hard code it here since this arch is cast in stone.
- */
- sun4c_vacinfo.num_bytes = 65536;
- sun4c_vacinfo.linesize = 16;
- } else {
- sun4c_vacinfo.num_bytes =
- prom_getintdefault(prom_root_node, "vac-size", 65536);
- sun4c_vacinfo.linesize =
- prom_getintdefault(prom_root_node, "vac-linesize", 16);
- }
- sun4c_vacinfo.do_hwflushes =
- prom_getintdefault(prom_root_node, "vac-hwflush", 0);
-
- if (sun4c_vacinfo.do_hwflushes == 0)
- sun4c_vacinfo.do_hwflushes =
- prom_getintdefault(prom_root_node, "vac_hwflush", 0);
-
- if (sun4c_vacinfo.num_bytes != 65536) {
- prom_printf("WEIRD Sun4C VAC cache size, "
- "tell sparclinux@vger.kernel.org");
- prom_halt();
- }
-
- switch (sun4c_vacinfo.linesize) {
- case 16:
- sun4c_vacinfo.log2lsize = 4;
- break;
- case 32:
- sun4c_vacinfo.log2lsize = 5;
- break;
- default:
- prom_printf("probe_vac: Didn't expect vac-linesize of %d, halting\n",
- sun4c_vacinfo.linesize);
- prom_halt();
- }
-
- sun4c_flush_all();
- sun4c_enable_vac();
-}
-
-/* Patch instructions for the low level kernel fault handler. */
-extern unsigned long invalid_segment_patch1, invalid_segment_patch1_ff;
-extern unsigned long invalid_segment_patch2, invalid_segment_patch2_ff;
-extern unsigned long invalid_segment_patch1_1ff, invalid_segment_patch2_1ff;
-extern unsigned long num_context_patch1, num_context_patch1_16;
-extern unsigned long num_context_patch2_16;
-extern unsigned long vac_linesize_patch, vac_linesize_patch_32;
-extern unsigned long vac_hwflush_patch1, vac_hwflush_patch1_on;
-extern unsigned long vac_hwflush_patch2, vac_hwflush_patch2_on;
-
-#define PATCH_INSN(src, dst) do { \
- daddr = &(dst); \
- iaddr = &(src); \
- *daddr = *iaddr; \
- } while (0)
-
-static void __init patch_kernel_fault_handler(void)
-{
- unsigned long *iaddr, *daddr;
-
- switch (num_segmaps) {
- case 128:
- /* Default, nothing to do. */
- break;
- case 256:
- PATCH_INSN(invalid_segment_patch1_ff,
- invalid_segment_patch1);
- PATCH_INSN(invalid_segment_patch2_ff,
- invalid_segment_patch2);
- break;
- case 512:
- PATCH_INSN(invalid_segment_patch1_1ff,
- invalid_segment_patch1);
- PATCH_INSN(invalid_segment_patch2_1ff,
- invalid_segment_patch2);
- break;
- default:
- prom_printf("Unhandled number of segmaps: %d\n",
- num_segmaps);
- prom_halt();
- }
- switch (num_contexts) {
- case 8:
- /* Default, nothing to do. */
- break;
- case 16:
- PATCH_INSN(num_context_patch1_16,
- num_context_patch1);
- break;
- default:
- prom_printf("Unhandled number of contexts: %d\n",
- num_contexts);
- prom_halt();
- }
-
- if (sun4c_vacinfo.do_hwflushes != 0) {
- PATCH_INSN(vac_hwflush_patch1_on, vac_hwflush_patch1);
- PATCH_INSN(vac_hwflush_patch2_on, vac_hwflush_patch2);
- } else {
- switch (sun4c_vacinfo.linesize) {
- case 16:
- /* Default, nothing to do. */
- break;
- case 32:
- PATCH_INSN(vac_linesize_patch_32, vac_linesize_patch);
- break;
- default:
- prom_printf("Impossible VAC linesize %d, halting...\n",
- sun4c_vacinfo.linesize);
- prom_halt();
- }
- }
-}
-
-static void __init sun4c_probe_mmu(void)
-{
- if ((idprom->id_machtype == (SM_SUN4C | SM_4C_SS1)) ||
- (idprom->id_machtype == (SM_SUN4C | SM_4C_SS1PLUS))) {
- /* Hardcode these just to be safe, PROM on SS1 does
- * not have this info available in the root node.
- */
- num_segmaps = 128;
- num_contexts = 8;
- } else {
- num_segmaps =
- prom_getintdefault(prom_root_node, "mmu-npmg", 128);
- num_contexts =
- prom_getintdefault(prom_root_node, "mmu-nctx", 0x8);
- }
- patch_kernel_fault_handler();
-}
-
-volatile unsigned long __iomem *sun4c_memerr_reg = NULL;
-
-void __init sun4c_probe_memerr_reg(void)
-{
- phandle node;
- struct linux_prom_registers regs[1];
-
- node = prom_getchild(prom_root_node);
- node = prom_searchsiblings(prom_root_node, "memory-error");
- if (!node)
- return;
- if (prom_getproperty(node, "reg", (char *)regs, sizeof(regs)) <= 0)
- return;
- /* hmm I think regs[0].which_io is zero here anyways */
- sun4c_memerr_reg = ioremap(regs[0].phys_addr, regs[0].reg_size);
-}
-
-static inline void sun4c_init_ss2_cache_bug(void)
-{
- if ((idprom->id_machtype == (SM_SUN4C | SM_4C_SS2)) ||
- (idprom->id_machtype == (SM_SUN4C | SM_4C_IPX)) ||
- (idprom->id_machtype == (SM_SUN4C | SM_4C_ELC))) {
- /* Whee.. */
- printk("SS2 cache bug detected, uncaching trap table page\n");
- sun4c_flush_page((unsigned int) &_start);
- sun4c_put_pte(((unsigned long) &_start),
- (sun4c_get_pte((unsigned long) &_start) | _SUN4C_PAGE_NOCACHE));
- }
-}
-
-/* Addr is always aligned on a page boundary for us already. */
-static int sun4c_map_dma_area(struct device *dev, dma_addr_t *pba, unsigned long va,
- unsigned long addr, int len)
-{
- unsigned long page, end;
-
- *pba = addr;
-
- end = PAGE_ALIGN((addr + len));
- while (addr < end) {
- page = va;
- sun4c_flush_page(page);
- page -= PAGE_OFFSET;
- page >>= PAGE_SHIFT;
- page |= (_SUN4C_PAGE_VALID | _SUN4C_PAGE_DIRTY |
- _SUN4C_PAGE_NOCACHE | _SUN4C_PAGE_PRIV);
- sun4c_put_pte(addr, page);
- addr += PAGE_SIZE;
- va += PAGE_SIZE;
- }
-
- return 0;
-}
-
-static void sun4c_unmap_dma_area(struct device *dev, unsigned long busa, int len)
-{
- /* Fortunately for us, bus_addr == uncached_virt in sun4c. */
- /* XXX Implement this */
-}
-
-/* TLB management. */
-
-/* Don't change this struct without changing entry.S. This is used
- * in the in-window kernel fault handler, and you don't want to mess
- * with that. (See sun4c_fault in entry.S).
- */
-struct sun4c_mmu_entry {
- struct sun4c_mmu_entry *next;
- struct sun4c_mmu_entry *prev;
- unsigned long vaddr;
- unsigned char pseg;
- unsigned char locked;
-
- /* For user mappings only, and completely hidden from kernel
- * TLB miss code.
- */
- unsigned char ctx;
- struct sun4c_mmu_entry *lru_next;
- struct sun4c_mmu_entry *lru_prev;
-};
-
-static struct sun4c_mmu_entry mmu_entry_pool[SUN4C_MAX_SEGMAPS];
-
-static void __init sun4c_init_mmu_entry_pool(void)
-{
- int i;
-
- for (i=0; i < SUN4C_MAX_SEGMAPS; i++) {
- mmu_entry_pool[i].pseg = i;
- mmu_entry_pool[i].next = NULL;
- mmu_entry_pool[i].prev = NULL;
- mmu_entry_pool[i].vaddr = 0;
- mmu_entry_pool[i].locked = 0;
- mmu_entry_pool[i].ctx = 0;
- mmu_entry_pool[i].lru_next = NULL;
- mmu_entry_pool[i].lru_prev = NULL;
- }
- mmu_entry_pool[invalid_segment].locked = 1;
-}
-
-static inline void fix_permissions(unsigned long vaddr, unsigned long bits_on,
- unsigned long bits_off)
-{
- unsigned long start, end;
-
- end = vaddr + SUN4C_REAL_PGDIR_SIZE;
- for (start = vaddr; start < end; start += PAGE_SIZE)
- if (sun4c_get_pte(start) & _SUN4C_PAGE_VALID)
- sun4c_put_pte(start, (sun4c_get_pte(start) | bits_on) &
- ~bits_off);
-}
-
-static inline void sun4c_init_map_kernelprom(unsigned long kernel_end)
-{
- unsigned long vaddr;
- unsigned char pseg, ctx;
-
- for (vaddr = KADB_DEBUGGER_BEGVM;
- vaddr < LINUX_OPPROM_ENDVM;
- vaddr += SUN4C_REAL_PGDIR_SIZE) {
- pseg = sun4c_get_segmap(vaddr);
- if (pseg != invalid_segment) {
- mmu_entry_pool[pseg].locked = 1;
- for (ctx = 0; ctx < num_contexts; ctx++)
- prom_putsegment(ctx, vaddr, pseg);
- fix_permissions(vaddr, _SUN4C_PAGE_PRIV, 0);
- }
- }
-
- for (vaddr = KERNBASE; vaddr < kernel_end; vaddr += SUN4C_REAL_PGDIR_SIZE) {
- pseg = sun4c_get_segmap(vaddr);
- mmu_entry_pool[pseg].locked = 1;
- for (ctx = 0; ctx < num_contexts; ctx++)
- prom_putsegment(ctx, vaddr, pseg);
- fix_permissions(vaddr, _SUN4C_PAGE_PRIV, _SUN4C_PAGE_NOCACHE);
- }
-}
-
-static void __init sun4c_init_lock_area(unsigned long start, unsigned long end)
-{
- int i, ctx;
-
- while (start < end) {
- for (i = 0; i < invalid_segment; i++)
- if (!mmu_entry_pool[i].locked)
- break;
- mmu_entry_pool[i].locked = 1;
- sun4c_init_clean_segmap(i);
- for (ctx = 0; ctx < num_contexts; ctx++)
- prom_putsegment(ctx, start, mmu_entry_pool[i].pseg);
- start += SUN4C_REAL_PGDIR_SIZE;
- }
-}
-
-/* Don't change this struct without changing entry.S. This is used
- * in the in-window kernel fault handler, and you don't want to mess
- * with that. (See sun4c_fault in entry.S).
- */
-struct sun4c_mmu_ring {
- struct sun4c_mmu_entry ringhd;
- int num_entries;
-};
-
-static struct sun4c_mmu_ring sun4c_context_ring[SUN4C_MAX_CONTEXTS]; /* used user entries */
-static struct sun4c_mmu_ring sun4c_ufree_ring; /* free user entries */
-static struct sun4c_mmu_ring sun4c_ulru_ring; /* LRU user entries */
-struct sun4c_mmu_ring sun4c_kernel_ring; /* used kernel entries */
-struct sun4c_mmu_ring sun4c_kfree_ring; /* free kernel entries */
-
-static inline void sun4c_init_rings(void)
-{
- int i;
-
- for (i = 0; i < SUN4C_MAX_CONTEXTS; i++) {
- sun4c_context_ring[i].ringhd.next =
- sun4c_context_ring[i].ringhd.prev =
- &sun4c_context_ring[i].ringhd;
- sun4c_context_ring[i].num_entries = 0;
- }
- sun4c_ufree_ring.ringhd.next = sun4c_ufree_ring.ringhd.prev =
- &sun4c_ufree_ring.ringhd;
- sun4c_ufree_ring.num_entries = 0;
- sun4c_ulru_ring.ringhd.lru_next = sun4c_ulru_ring.ringhd.lru_prev =
- &sun4c_ulru_ring.ringhd;
- sun4c_ulru_ring.num_entries = 0;
- sun4c_kernel_ring.ringhd.next = sun4c_kernel_ring.ringhd.prev =
- &sun4c_kernel_ring.ringhd;
- sun4c_kernel_ring.num_entries = 0;
- sun4c_kfree_ring.ringhd.next = sun4c_kfree_ring.ringhd.prev =
- &sun4c_kfree_ring.ringhd;
- sun4c_kfree_ring.num_entries = 0;
-}
-
-static void add_ring(struct sun4c_mmu_ring *ring,
- struct sun4c_mmu_entry *entry)
-{
- struct sun4c_mmu_entry *head = &ring->ringhd;
-
- entry->prev = head;
- (entry->next = head->next)->prev = entry;
- head->next = entry;
- ring->num_entries++;
-}
-
-static inline void add_lru(struct sun4c_mmu_entry *entry)
-{
- struct sun4c_mmu_ring *ring = &sun4c_ulru_ring;
- struct sun4c_mmu_entry *head = &ring->ringhd;
-
- entry->lru_next = head;
- (entry->lru_prev = head->lru_prev)->lru_next = entry;
- head->lru_prev = entry;
-}
-
-static void add_ring_ordered(struct sun4c_mmu_ring *ring,
- struct sun4c_mmu_entry *entry)
-{
- struct sun4c_mmu_entry *head = &ring->ringhd;
- unsigned long addr = entry->vaddr;
-
- while ((head->next != &ring->ringhd) && (head->next->vaddr < addr))
- head = head->next;
-
- entry->prev = head;
- (entry->next = head->next)->prev = entry;
- head->next = entry;
- ring->num_entries++;
-
- add_lru(entry);
-}
-
-static inline void remove_ring(struct sun4c_mmu_ring *ring,
- struct sun4c_mmu_entry *entry)
-{
- struct sun4c_mmu_entry *next = entry->next;
-
- (next->prev = entry->prev)->next = next;
- ring->num_entries--;
-}
-
-static void remove_lru(struct sun4c_mmu_entry *entry)
-{
- struct sun4c_mmu_entry *next = entry->lru_next;
-
- (next->lru_prev = entry->lru_prev)->lru_next = next;
-}
-
-static void free_user_entry(int ctx, struct sun4c_mmu_entry *entry)
-{
- remove_ring(sun4c_context_ring+ctx, entry);
- remove_lru(entry);
- add_ring(&sun4c_ufree_ring, entry);
-}
-
-static void free_kernel_entry(struct sun4c_mmu_entry *entry,
- struct sun4c_mmu_ring *ring)
-{
- remove_ring(ring, entry);
- add_ring(&sun4c_kfree_ring, entry);
-}
-
-static void __init sun4c_init_fill_kernel_ring(int howmany)
-{
- int i;
-
- while (howmany) {
- for (i = 0; i < invalid_segment; i++)
- if (!mmu_entry_pool[i].locked)
- break;
- mmu_entry_pool[i].locked = 1;
- sun4c_init_clean_segmap(i);
- add_ring(&sun4c_kfree_ring, &mmu_entry_pool[i]);
- howmany--;
- }
-}
-
-static void __init sun4c_init_fill_user_ring(void)
-{
- int i;
-
- for (i = 0; i < invalid_segment; i++) {
- if (mmu_entry_pool[i].locked)
- continue;
- sun4c_init_clean_segmap(i);
- add_ring(&sun4c_ufree_ring, &mmu_entry_pool[i]);
- }
-}
-
-static void sun4c_kernel_unmap(struct sun4c_mmu_entry *kentry)
-{
- int savectx, ctx;
-
- savectx = sun4c_get_context();
- for (ctx = 0; ctx < num_contexts; ctx++) {
- sun4c_set_context(ctx);
- sun4c_put_segmap(kentry->vaddr, invalid_segment);
- }
- sun4c_set_context(savectx);
-}
-
-static void sun4c_kernel_map(struct sun4c_mmu_entry *kentry)
-{
- int savectx, ctx;
-
- savectx = sun4c_get_context();
- for (ctx = 0; ctx < num_contexts; ctx++) {
- sun4c_set_context(ctx);
- sun4c_put_segmap(kentry->vaddr, kentry->pseg);
- }
- sun4c_set_context(savectx);
-}
-
-#define sun4c_user_unmap(__entry) \
- sun4c_put_segmap((__entry)->vaddr, invalid_segment)
-
-static void sun4c_demap_context(struct sun4c_mmu_ring *crp, unsigned char ctx)
-{
- struct sun4c_mmu_entry *head = &crp->ringhd;
- unsigned long flags;
-
- local_irq_save(flags);
- if (head->next != head) {
- struct sun4c_mmu_entry *entry = head->next;
- int savectx = sun4c_get_context();
-
- flush_user_windows();
- sun4c_set_context(ctx);
- sun4c_flush_context();
- do {
- struct sun4c_mmu_entry *next = entry->next;
-
- sun4c_user_unmap(entry);
- free_user_entry(ctx, entry);
-
- entry = next;
- } while (entry != head);
- sun4c_set_context(savectx);
- }
- local_irq_restore(flags);
-}
-
-static int sun4c_user_taken_entries; /* This is how much we have. */
-static int max_user_taken_entries; /* This limits us and prevents deadlock. */
-
-static struct sun4c_mmu_entry *sun4c_kernel_strategy(void)
-{
- struct sun4c_mmu_entry *this_entry;
-
- /* If some are free, return first one. */
- if (sun4c_kfree_ring.num_entries) {
- this_entry = sun4c_kfree_ring.ringhd.next;
- return this_entry;
- }
-
- /* Else free one up. */
- this_entry = sun4c_kernel_ring.ringhd.prev;
- sun4c_flush_segment(this_entry->vaddr);
- sun4c_kernel_unmap(this_entry);
- free_kernel_entry(this_entry, &sun4c_kernel_ring);
- this_entry = sun4c_kfree_ring.ringhd.next;
-
- return this_entry;
-}
-
-/* Using this method to free up mmu entries eliminates a lot of
- * potential races since we have a kernel that incurs tlb
- * replacement faults. There may be performance penalties.
- *
- * NOTE: Must be called with interrupts disabled.
- */
-static struct sun4c_mmu_entry *sun4c_user_strategy(void)
-{
- struct sun4c_mmu_entry *entry;
- unsigned char ctx;
- int savectx;
-
- /* If some are free, return first one. */
- if (sun4c_ufree_ring.num_entries) {
- entry = sun4c_ufree_ring.ringhd.next;
- goto unlink_out;
- }
-
- if (sun4c_user_taken_entries) {
- entry = sun4c_kernel_strategy();
- sun4c_user_taken_entries--;
- goto kunlink_out;
- }
-
- /* Grab from the beginning of the LRU list. */
- entry = sun4c_ulru_ring.ringhd.lru_next;
- ctx = entry->ctx;
-
- savectx = sun4c_get_context();
- flush_user_windows();
- sun4c_set_context(ctx);
- sun4c_flush_segment(entry->vaddr);
- sun4c_user_unmap(entry);
- remove_ring(sun4c_context_ring + ctx, entry);
- remove_lru(entry);
- sun4c_set_context(savectx);
-
- return entry;
-
-unlink_out:
- remove_ring(&sun4c_ufree_ring, entry);
- return entry;
-kunlink_out:
- remove_ring(&sun4c_kfree_ring, entry);
- return entry;
-}
-
-/* NOTE: Must be called with interrupts disabled. */
-void sun4c_grow_kernel_ring(void)
-{
- struct sun4c_mmu_entry *entry;
-
- /* Prevent deadlock condition. */
- if (sun4c_user_taken_entries >= max_user_taken_entries)
- return;
-
- if (sun4c_ufree_ring.num_entries) {
- entry = sun4c_ufree_ring.ringhd.next;
- remove_ring(&sun4c_ufree_ring, entry);
- add_ring(&sun4c_kfree_ring, entry);
- sun4c_user_taken_entries++;
- }
-}
-
-/* 2 page buckets for task struct and kernel stack allocation.
- *
- * TASK_STACK_BEGIN
- * bucket[0]
- * bucket[1]
- * [ ... ]
- * bucket[NR_TASK_BUCKETS-1]
- * TASK_STACK_BEGIN + (sizeof(struct task_bucket) * NR_TASK_BUCKETS)
- *
- * Each slot looks like:
- *
- * page 1 -- task struct + beginning of kernel stack
- * page 2 -- rest of kernel stack
- */
-
-union task_union *sun4c_bucket[NR_TASK_BUCKETS];
-
-static int sun4c_lowbucket_avail;
-
-#define BUCKET_EMPTY ((union task_union *) 0)
-#define BUCKET_SHIFT (PAGE_SHIFT + 1) /* log2(sizeof(struct task_bucket)) */
-#define BUCKET_SIZE (1 << BUCKET_SHIFT)
-#define BUCKET_NUM(addr) ((((addr) - SUN4C_LOCK_VADDR) >> BUCKET_SHIFT))
-#define BUCKET_ADDR(num) (((num) << BUCKET_SHIFT) + SUN4C_LOCK_VADDR)
-#define BUCKET_PTE(page) \
- ((((page) - PAGE_OFFSET) >> PAGE_SHIFT) | pgprot_val(SUN4C_PAGE_KERNEL))
-#define BUCKET_PTE_PAGE(pte) \
- (PAGE_OFFSET + (((pte) & SUN4C_PFN_MASK) << PAGE_SHIFT))
-
-static void get_locked_segment(unsigned long addr)
-{
- struct sun4c_mmu_entry *stolen;
- unsigned long flags;
-
- local_irq_save(flags);
- addr &= SUN4C_REAL_PGDIR_MASK;
- stolen = sun4c_user_strategy();
- max_user_taken_entries--;
- stolen->vaddr = addr;
- flush_user_windows();
- sun4c_kernel_map(stolen);
- local_irq_restore(flags);
-}
-
-static void free_locked_segment(unsigned long addr)
-{
- struct sun4c_mmu_entry *entry;
- unsigned long flags;
- unsigned char pseg;
-
- local_irq_save(flags);
- addr &= SUN4C_REAL_PGDIR_MASK;
- pseg = sun4c_get_segmap(addr);
- entry = &mmu_entry_pool[pseg];
-
- flush_user_windows();
- sun4c_flush_segment(addr);
- sun4c_kernel_unmap(entry);
- add_ring(&sun4c_ufree_ring, entry);
- max_user_taken_entries++;
- local_irq_restore(flags);
-}
-
-static inline void garbage_collect(int entry)
-{
- int start, end;
-
- /* 32 buckets per segment... */
- entry &= ~31;
- start = entry;
- for (end = (start + 32); start < end; start++)
- if (sun4c_bucket[start] != BUCKET_EMPTY)
- return;
-
- /* Entire segment empty, release it. */
- free_locked_segment(BUCKET_ADDR(entry));
-}
-
-static struct thread_info *sun4c_alloc_thread_info_node(int node)
-{
- unsigned long addr, pages;
- int entry;
-
- pages = __get_free_pages(GFP_KERNEL, THREAD_INFO_ORDER);
- if (!pages)
- return NULL;
-
- for (entry = sun4c_lowbucket_avail; entry < NR_TASK_BUCKETS; entry++)
- if (sun4c_bucket[entry] == BUCKET_EMPTY)
- break;
- if (entry == NR_TASK_BUCKETS) {
- free_pages(pages, THREAD_INFO_ORDER);
- return NULL;
- }
- if (entry >= sun4c_lowbucket_avail)
- sun4c_lowbucket_avail = entry + 1;
-
- addr = BUCKET_ADDR(entry);
- sun4c_bucket[entry] = (union task_union *) addr;
- if(sun4c_get_segmap(addr) == invalid_segment)
- get_locked_segment(addr);
-
- /* We are changing the virtual color of the page(s)
- * so we must flush the cache to guarantee consistency.
- */
- sun4c_flush_page(pages);
- sun4c_flush_page(pages + PAGE_SIZE);
-
- sun4c_put_pte(addr, BUCKET_PTE(pages));
- sun4c_put_pte(addr + PAGE_SIZE, BUCKET_PTE(pages + PAGE_SIZE));
-
-#ifdef CONFIG_DEBUG_STACK_USAGE
- memset((void *)addr, 0, PAGE_SIZE << THREAD_INFO_ORDER);
-#endif /* DEBUG_STACK_USAGE */
-
- return (struct thread_info *) addr;
-}
-
-static void sun4c_free_thread_info(struct thread_info *ti)
-{
- unsigned long tiaddr = (unsigned long) ti;
- unsigned long pages = BUCKET_PTE_PAGE(sun4c_get_pte(tiaddr));
- int entry = BUCKET_NUM(tiaddr);
-
- /* We are deleting a mapping, so the flush here is mandatory. */
- sun4c_flush_page(tiaddr);
- sun4c_flush_page(tiaddr + PAGE_SIZE);
-
- sun4c_put_pte(tiaddr, 0);
- sun4c_put_pte(tiaddr + PAGE_SIZE, 0);
-
- sun4c_bucket[entry] = BUCKET_EMPTY;
- if (entry < sun4c_lowbucket_avail)
- sun4c_lowbucket_avail = entry;
-
- free_pages(pages, THREAD_INFO_ORDER);
- garbage_collect(entry);
-}
-
-static void __init sun4c_init_buckets(void)
-{
- int entry;
-
- if (sizeof(union thread_union) != (PAGE_SIZE << THREAD_INFO_ORDER)) {
- extern void thread_info_size_is_bolixed_pete(void);
- thread_info_size_is_bolixed_pete();
- }
-
- for (entry = 0; entry < NR_TASK_BUCKETS; entry++)
- sun4c_bucket[entry] = BUCKET_EMPTY;
- sun4c_lowbucket_avail = 0;
-}
-
-static unsigned long sun4c_iobuffer_start;
-static unsigned long sun4c_iobuffer_end;
-static unsigned long sun4c_iobuffer_high;
-static unsigned long *sun4c_iobuffer_map;
-static int iobuffer_map_size;
-
-/*
- * Alias our pages so they do not cause a trap.
- * Also one page may be aliased into several I/O areas and we may
- * finish these I/O separately.
- */
-static char *sun4c_lockarea(char *vaddr, unsigned long size)
-{
- unsigned long base, scan;
- unsigned long npages;
- unsigned long vpage;
- unsigned long pte;
- unsigned long apage;
- unsigned long high;
- unsigned long flags;
-
- npages = (((unsigned long)vaddr & ~PAGE_MASK) +
- size + (PAGE_SIZE-1)) >> PAGE_SHIFT;
-
- local_irq_save(flags);
- base = bitmap_find_next_zero_area(sun4c_iobuffer_map, iobuffer_map_size,
- 0, npages, 0);
- if (base >= iobuffer_map_size)
- goto abend;
-
- high = ((base + npages) << PAGE_SHIFT) + sun4c_iobuffer_start;
- high = SUN4C_REAL_PGDIR_ALIGN(high);
- while (high > sun4c_iobuffer_high) {
- get_locked_segment(sun4c_iobuffer_high);
- sun4c_iobuffer_high += SUN4C_REAL_PGDIR_SIZE;
- }
-
- vpage = ((unsigned long) vaddr) & PAGE_MASK;
- for (scan = base; scan < base+npages; scan++) {
- pte = ((vpage-PAGE_OFFSET) >> PAGE_SHIFT);
- pte |= pgprot_val(SUN4C_PAGE_KERNEL);
- pte |= _SUN4C_PAGE_NOCACHE;
- set_bit(scan, sun4c_iobuffer_map);
- apage = (scan << PAGE_SHIFT) + sun4c_iobuffer_start;
-
- /* Flush original mapping so we see the right things later. */
- sun4c_flush_page(vpage);
-
- sun4c_put_pte(apage, pte);
- vpage += PAGE_SIZE;
- }
- local_irq_restore(flags);
- return (char *) ((base << PAGE_SHIFT) + sun4c_iobuffer_start +
- (((unsigned long) vaddr) & ~PAGE_MASK));
-
-abend:
- local_irq_restore(flags);
- printk("DMA vaddr=0x%p size=%08lx\n", vaddr, size);
- panic("Out of iobuffer table");
- return NULL;
-}
-
-static void sun4c_unlockarea(char *vaddr, unsigned long size)
-{
- unsigned long vpage, npages;
- unsigned long flags;
- int scan, high;
-
- vpage = (unsigned long)vaddr & PAGE_MASK;
- npages = (((unsigned long)vaddr & ~PAGE_MASK) +
- size + (PAGE_SIZE-1)) >> PAGE_SHIFT;
-
- local_irq_save(flags);
- while (npages != 0) {
- --npages;
-
- /* This mapping is marked non-cachable, no flush necessary. */
- sun4c_put_pte(vpage, 0);
- clear_bit((vpage - sun4c_iobuffer_start) >> PAGE_SHIFT,
- sun4c_iobuffer_map);
- vpage += PAGE_SIZE;
- }
-
- /* garbage collect */
- scan = (sun4c_iobuffer_high - sun4c_iobuffer_start) >> PAGE_SHIFT;
- while (scan >= 0 && !sun4c_iobuffer_map[scan >> 5])
- scan -= 32;
- scan += 32;
- high = sun4c_iobuffer_start + (scan << PAGE_SHIFT);
- high = SUN4C_REAL_PGDIR_ALIGN(high) + SUN4C_REAL_PGDIR_SIZE;
- while (high < sun4c_iobuffer_high) {
- sun4c_iobuffer_high -= SUN4C_REAL_PGDIR_SIZE;
- free_locked_segment(sun4c_iobuffer_high);
- }
- local_irq_restore(flags);
-}
-
-/* Note the scsi code at init time passes to here buffers
- * which sit on the kernel stack, those are already locked
- * by implication and fool the page locking code above
- * if passed to by mistake.
- */
-static __u32 sun4c_get_scsi_one(struct device *dev, char *bufptr, unsigned long len)
-{
- unsigned long page;
-
- page = ((unsigned long)bufptr) & PAGE_MASK;
- if (!virt_addr_valid(page)) {
- sun4c_flush_page(page);
- return (__u32)bufptr; /* already locked */
- }
- return (__u32)sun4c_lockarea(bufptr, len);
-}
-
-static void sun4c_get_scsi_sgl(struct device *dev, struct scatterlist *sg, int sz)
-{
- while (sz != 0) {
- --sz;
- sg->dma_address = (__u32)sun4c_lockarea(sg_virt(sg), sg->length);
- sg->dma_length = sg->length;
- sg = sg_next(sg);
- }
-}
-
-static void sun4c_release_scsi_one(struct device *dev, __u32 bufptr, unsigned long len)
-{
- if (bufptr < sun4c_iobuffer_start)
- return; /* On kernel stack or similar, see above */
- sun4c_unlockarea((char *)bufptr, len);
-}
-
-static void sun4c_release_scsi_sgl(struct device *dev, struct scatterlist *sg, int sz)
-{
- while (sz != 0) {
- --sz;
- sun4c_unlockarea((char *)sg->dma_address, sg->length);
- sg = sg_next(sg);
- }
-}
-
-#define TASK_ENTRY_SIZE BUCKET_SIZE /* see above */
-#define LONG_ALIGN(x) (((x)+(sizeof(long))-1)&~((sizeof(long))-1))
-
-struct vm_area_struct sun4c_kstack_vma;
-
-static void __init sun4c_init_lock_areas(void)
-{
- unsigned long sun4c_taskstack_start;
- unsigned long sun4c_taskstack_end;
- int bitmap_size;
-
- sun4c_init_buckets();
- sun4c_taskstack_start = SUN4C_LOCK_VADDR;
- sun4c_taskstack_end = (sun4c_taskstack_start +
- (TASK_ENTRY_SIZE * NR_TASK_BUCKETS));
- if (sun4c_taskstack_end >= SUN4C_LOCK_END) {
- prom_printf("Too many tasks, decrease NR_TASK_BUCKETS please.\n");
- prom_halt();
- }
-
- sun4c_iobuffer_start = sun4c_iobuffer_high =
- SUN4C_REAL_PGDIR_ALIGN(sun4c_taskstack_end);
- sun4c_iobuffer_end = SUN4C_LOCK_END;
- bitmap_size = (sun4c_iobuffer_end - sun4c_iobuffer_start) >> PAGE_SHIFT;
- bitmap_size = (bitmap_size + 7) >> 3;
- bitmap_size = LONG_ALIGN(bitmap_size);
- iobuffer_map_size = bitmap_size << 3;
- sun4c_iobuffer_map = __alloc_bootmem(bitmap_size, SMP_CACHE_BYTES, 0UL);
- memset((void *) sun4c_iobuffer_map, 0, bitmap_size);
-
- sun4c_kstack_vma.vm_mm = &init_mm;
- sun4c_kstack_vma.vm_start = sun4c_taskstack_start;
- sun4c_kstack_vma.vm_end = sun4c_taskstack_end;
- sun4c_kstack_vma.vm_page_prot = PAGE_SHARED;
- sun4c_kstack_vma.vm_flags = VM_READ | VM_WRITE | VM_EXEC;
- insert_vm_struct(&init_mm, &sun4c_kstack_vma);
-}
-
-/* Cache flushing on the sun4c. */
-static void sun4c_flush_cache_all(void)
-{
- unsigned long begin, end;
-
- flush_user_windows();
- begin = (KERNBASE + SUN4C_REAL_PGDIR_SIZE);
- end = (begin + SUN4C_VAC_SIZE);
-
- if (sun4c_vacinfo.linesize == 32) {
- while (begin < end) {
- __asm__ __volatile__(
- "ld [%0 + 0x00], %%g0\n\t"
- "ld [%0 + 0x20], %%g0\n\t"
- "ld [%0 + 0x40], %%g0\n\t"
- "ld [%0 + 0x60], %%g0\n\t"
- "ld [%0 + 0x80], %%g0\n\t"
- "ld [%0 + 0xa0], %%g0\n\t"
- "ld [%0 + 0xc0], %%g0\n\t"
- "ld [%0 + 0xe0], %%g0\n\t"
- "ld [%0 + 0x100], %%g0\n\t"
- "ld [%0 + 0x120], %%g0\n\t"
- "ld [%0 + 0x140], %%g0\n\t"
- "ld [%0 + 0x160], %%g0\n\t"
- "ld [%0 + 0x180], %%g0\n\t"
- "ld [%0 + 0x1a0], %%g0\n\t"
- "ld [%0 + 0x1c0], %%g0\n\t"
- "ld [%0 + 0x1e0], %%g0\n"
- : : "r" (begin));
- begin += 512;
- }
- } else {
- while (begin < end) {
- __asm__ __volatile__(
- "ld [%0 + 0x00], %%g0\n\t"
- "ld [%0 + 0x10], %%g0\n\t"
- "ld [%0 + 0x20], %%g0\n\t"
- "ld [%0 + 0x30], %%g0\n\t"
- "ld [%0 + 0x40], %%g0\n\t"
- "ld [%0 + 0x50], %%g0\n\t"
- "ld [%0 + 0x60], %%g0\n\t"
- "ld [%0 + 0x70], %%g0\n\t"
- "ld [%0 + 0x80], %%g0\n\t"
- "ld [%0 + 0x90], %%g0\n\t"
- "ld [%0 + 0xa0], %%g0\n\t"
- "ld [%0 + 0xb0], %%g0\n\t"
- "ld [%0 + 0xc0], %%g0\n\t"
- "ld [%0 + 0xd0], %%g0\n\t"
- "ld [%0 + 0xe0], %%g0\n\t"
- "ld [%0 + 0xf0], %%g0\n"
- : : "r" (begin));
- begin += 256;
- }
- }
-}
-
-static void sun4c_flush_cache_mm(struct mm_struct *mm)
-{
- int new_ctx = mm->context;
-
- if (new_ctx != NO_CONTEXT) {
- flush_user_windows();
-
- if (sun4c_context_ring[new_ctx].num_entries) {
- struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd;
- unsigned long flags;
-
- local_irq_save(flags);
- if (head->next != head) {
- struct sun4c_mmu_entry *entry = head->next;
- int savectx = sun4c_get_context();
-
- sun4c_set_context(new_ctx);
- sun4c_flush_context();
- do {
- struct sun4c_mmu_entry *next = entry->next;
-
- sun4c_user_unmap(entry);
- free_user_entry(new_ctx, entry);
-
- entry = next;
- } while (entry != head);
- sun4c_set_context(savectx);
- }
- local_irq_restore(flags);
- }
- }
-}
-
-static void sun4c_flush_cache_range(struct vm_area_struct *vma, unsigned long start, unsigned long end)
-{
- struct mm_struct *mm = vma->vm_mm;
- int new_ctx = mm->context;
-
- if (new_ctx != NO_CONTEXT) {
- struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd;
- struct sun4c_mmu_entry *entry;
- unsigned long flags;
-
- flush_user_windows();
-
- local_irq_save(flags);
- /* All user segmap chains are ordered on entry->vaddr. */
- for (entry = head->next;
- (entry != head) && ((entry->vaddr+SUN4C_REAL_PGDIR_SIZE) < start);
- entry = entry->next)
- ;
-
- /* Tracing various job mixtures showed that this conditional
- * only passes ~35% of the time for most worse case situations,
- * therefore we avoid all of this gross overhead ~65% of the time.
- */
- if ((entry != head) && (entry->vaddr < end)) {
- int octx = sun4c_get_context();
- sun4c_set_context(new_ctx);
-
- /* At this point, always, (start >= entry->vaddr) and
- * (entry->vaddr < end), once the latter condition
- * ceases to hold, or we hit the end of the list, we
- * exit the loop. The ordering of all user allocated
- * segmaps makes this all work out so beautifully.
- */
- do {
- struct sun4c_mmu_entry *next = entry->next;
- unsigned long realend;
-
- /* "realstart" is always >= entry->vaddr */
- realend = entry->vaddr + SUN4C_REAL_PGDIR_SIZE;
- if (end < realend)
- realend = end;
- if ((realend - entry->vaddr) <= (PAGE_SIZE << 3)) {
- unsigned long page = entry->vaddr;
- while (page < realend) {
- sun4c_flush_page(page);
- page += PAGE_SIZE;
- }
- } else {
- sun4c_flush_segment(entry->vaddr);
- sun4c_user_unmap(entry);
- free_user_entry(new_ctx, entry);
- }
- entry = next;
- } while ((entry != head) && (entry->vaddr < end));
- sun4c_set_context(octx);
- }
- local_irq_restore(flags);
- }
-}
-
-static void sun4c_flush_cache_page(struct vm_area_struct *vma, unsigned long page)
-{
- struct mm_struct *mm = vma->vm_mm;
- int new_ctx = mm->context;
-
- /* Sun4c has no separate I/D caches so cannot optimize for non
- * text page flushes.
- */
- if (new_ctx != NO_CONTEXT) {
- int octx = sun4c_get_context();
- unsigned long flags;
-
- flush_user_windows();
- local_irq_save(flags);
- sun4c_set_context(new_ctx);
- sun4c_flush_page(page);
- sun4c_set_context(octx);
- local_irq_restore(flags);
- }
-}
-
-static void sun4c_flush_page_to_ram(unsigned long page)
-{
- unsigned long flags;
-
- local_irq_save(flags);
- sun4c_flush_page(page);
- local_irq_restore(flags);
-}
-
-/* Sun4c cache is unified, both instructions and data live there, so
- * no need to flush the on-stack instructions for new signal handlers.
- */
-static void sun4c_flush_sig_insns(struct mm_struct *mm, unsigned long insn_addr)
-{
-}
-
-/* TLB flushing on the sun4c. These routines count on the cache
- * flushing code to flush the user register windows so that we need
- * not do so when we get here.
- */
-
-static void sun4c_flush_tlb_all(void)
-{
- struct sun4c_mmu_entry *this_entry, *next_entry;
- unsigned long flags;
- int savectx, ctx;
-
- local_irq_save(flags);
- this_entry = sun4c_kernel_ring.ringhd.next;
- savectx = sun4c_get_context();
- flush_user_windows();
- while (sun4c_kernel_ring.num_entries) {
- next_entry = this_entry->next;
- sun4c_flush_segment(this_entry->vaddr);
- for (ctx = 0; ctx < num_contexts; ctx++) {
- sun4c_set_context(ctx);
- sun4c_put_segmap(this_entry->vaddr, invalid_segment);
- }
- free_kernel_entry(this_entry, &sun4c_kernel_ring);
- this_entry = next_entry;
- }
- sun4c_set_context(savectx);
- local_irq_restore(flags);
-}
-
-static void sun4c_flush_tlb_mm(struct mm_struct *mm)
-{
- int new_ctx = mm->context;
-
- if (new_ctx != NO_CONTEXT) {
- struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd;
- unsigned long flags;
-
- local_irq_save(flags);
- if (head->next != head) {
- struct sun4c_mmu_entry *entry = head->next;
- int savectx = sun4c_get_context();
-
- sun4c_set_context(new_ctx);
- sun4c_flush_context();
- do {
- struct sun4c_mmu_entry *next = entry->next;
-
- sun4c_user_unmap(entry);
- free_user_entry(new_ctx, entry);
-
- entry = next;
- } while (entry != head);
- sun4c_set_context(savectx);
- }
- local_irq_restore(flags);
- }
-}
-
-static void sun4c_flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end)
-{
- struct mm_struct *mm = vma->vm_mm;
- int new_ctx = mm->context;
-
- if (new_ctx != NO_CONTEXT) {
- struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd;
- struct sun4c_mmu_entry *entry;
- unsigned long flags;
-
- local_irq_save(flags);
- /* See commentary in sun4c_flush_cache_range(). */
- for (entry = head->next;
- (entry != head) && ((entry->vaddr+SUN4C_REAL_PGDIR_SIZE) < start);
- entry = entry->next)
- ;
-
- if ((entry != head) && (entry->vaddr < end)) {
- int octx = sun4c_get_context();
-
- sun4c_set_context(new_ctx);
- do {
- struct sun4c_mmu_entry *next = entry->next;
-
- sun4c_flush_segment(entry->vaddr);
- sun4c_user_unmap(entry);
- free_user_entry(new_ctx, entry);
-
- entry = next;
- } while ((entry != head) && (entry->vaddr < end));
- sun4c_set_context(octx);
- }
- local_irq_restore(flags);
- }
-}
-
-static void sun4c_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
-{
- struct mm_struct *mm = vma->vm_mm;
- int new_ctx = mm->context;
-
- if (new_ctx != NO_CONTEXT) {
- int savectx = sun4c_get_context();
- unsigned long flags;
-
- local_irq_save(flags);
- sun4c_set_context(new_ctx);
- page &= PAGE_MASK;
- sun4c_flush_page(page);
- sun4c_put_pte(page, 0);
- sun4c_set_context(savectx);
- local_irq_restore(flags);
- }
-}
-
-static inline void sun4c_mapioaddr(unsigned long physaddr, unsigned long virt_addr)
-{
- unsigned long page_entry, pg_iobits;
-
- pg_iobits = _SUN4C_PAGE_PRESENT | _SUN4C_READABLE | _SUN4C_WRITEABLE |
- _SUN4C_PAGE_IO | _SUN4C_PAGE_NOCACHE;
-
- page_entry = ((physaddr >> PAGE_SHIFT) & SUN4C_PFN_MASK);
- page_entry |= ((pg_iobits | _SUN4C_PAGE_PRIV) & ~(_SUN4C_PAGE_PRESENT));
- sun4c_put_pte(virt_addr, page_entry);
-}
-
-static void sun4c_mapiorange(unsigned int bus, unsigned long xpa,
- unsigned long xva, unsigned int len)
-{
- while (len != 0) {
- len -= PAGE_SIZE;
- sun4c_mapioaddr(xpa, xva);
- xva += PAGE_SIZE;
- xpa += PAGE_SIZE;
- }
-}
-
-static void sun4c_unmapiorange(unsigned long virt_addr, unsigned int len)
-{
- while (len != 0) {
- len -= PAGE_SIZE;
- sun4c_put_pte(virt_addr, 0);
- virt_addr += PAGE_SIZE;
- }
-}
-
-static void sun4c_alloc_context(struct mm_struct *old_mm, struct mm_struct *mm)
-{
- struct ctx_list *ctxp;
-
- ctxp = ctx_free.next;
- if (ctxp != &ctx_free) {
- remove_from_ctx_list(ctxp);
- add_to_used_ctxlist(ctxp);
- mm->context = ctxp->ctx_number;
- ctxp->ctx_mm = mm;
- return;
- }
- ctxp = ctx_used.next;
- if (ctxp->ctx_mm == old_mm)
- ctxp = ctxp->next;
- remove_from_ctx_list(ctxp);
- add_to_used_ctxlist(ctxp);
- ctxp->ctx_mm->context = NO_CONTEXT;
- ctxp->ctx_mm = mm;
- mm->context = ctxp->ctx_number;
- sun4c_demap_context(&sun4c_context_ring[ctxp->ctx_number],
- ctxp->ctx_number);
-}
-
-/* Switch the current MM context. */
-static void sun4c_switch_mm(struct mm_struct *old_mm, struct mm_struct *mm, struct task_struct *tsk, int cpu)
-{
- struct ctx_list *ctx;
- int dirty = 0;
-
- if (mm->context == NO_CONTEXT) {
- dirty = 1;
- sun4c_alloc_context(old_mm, mm);
- } else {
- /* Update the LRU ring of contexts. */
- ctx = ctx_list_pool + mm->context;
- remove_from_ctx_list(ctx);
- add_to_used_ctxlist(ctx);
- }
- if (dirty || old_mm != mm)
- sun4c_set_context(mm->context);
-}
-
-static void sun4c_destroy_context(struct mm_struct *mm)
-{
- struct ctx_list *ctx_old;
-
- if (mm->context != NO_CONTEXT) {
- sun4c_demap_context(&sun4c_context_ring[mm->context], mm->context);
- ctx_old = ctx_list_pool + mm->context;
- remove_from_ctx_list(ctx_old);
- add_to_free_ctxlist(ctx_old);
- mm->context = NO_CONTEXT;
- }
-}
-
-static void sun4c_mmu_info(struct seq_file *m)
-{
- int used_user_entries, i;
-
- used_user_entries = 0;
- for (i = 0; i < num_contexts; i++)
- used_user_entries += sun4c_context_ring[i].num_entries;
-
- seq_printf(m,
- "vacsize\t\t: %d bytes\n"
- "vachwflush\t: %s\n"
- "vaclinesize\t: %d bytes\n"
- "mmuctxs\t\t: %d\n"
- "mmupsegs\t: %d\n"
- "kernelpsegs\t: %d\n"
- "kfreepsegs\t: %d\n"
- "usedpsegs\t: %d\n"
- "ufreepsegs\t: %d\n"
- "user_taken\t: %d\n"
- "max_taken\t: %d\n",
- sun4c_vacinfo.num_bytes,
- (sun4c_vacinfo.do_hwflushes ? "yes" : "no"),
- sun4c_vacinfo.linesize,
- num_contexts,
- (invalid_segment + 1),
- sun4c_kernel_ring.num_entries,
- sun4c_kfree_ring.num_entries,
- used_user_entries,
- sun4c_ufree_ring.num_entries,
- sun4c_user_taken_entries,
- max_user_taken_entries);
-}
-
-/* Nothing below here should touch the mmu hardware nor the mmu_entry
- * data structures.
- */
-
-/* First the functions which the mid-level code uses to directly
- * manipulate the software page tables. Some defines since we are
- * emulating the i386 page directory layout.
- */
-#define PGD_PRESENT 0x001
-#define PGD_RW 0x002
-#define PGD_USER 0x004
-#define PGD_ACCESSED 0x020
-#define PGD_DIRTY 0x040
-#define PGD_TABLE (PGD_PRESENT | PGD_RW | PGD_USER | PGD_ACCESSED | PGD_DIRTY)
-
-static void sun4c_set_pte(pte_t *ptep, pte_t pte)
-{
- *ptep = pte;
-}
-
-static void sun4c_pgd_set(pgd_t * pgdp, pmd_t * pmdp)
-{
-}
-
-static void sun4c_pmd_set(pmd_t * pmdp, pte_t * ptep)
-{
- pmdp->pmdv[0] = PGD_TABLE | (unsigned long) ptep;
-}
-
-static void sun4c_pmd_populate(pmd_t * pmdp, struct page * ptep)
-{
- if (page_address(ptep) == NULL) BUG(); /* No highmem on sun4c */
- pmdp->pmdv[0] = PGD_TABLE | (unsigned long) page_address(ptep);
-}
-
-static int sun4c_pte_present(pte_t pte)
-{
- return ((pte_val(pte) & (_SUN4C_PAGE_PRESENT | _SUN4C_PAGE_PRIV)) != 0);
-}
-static void sun4c_pte_clear(pte_t *ptep) { *ptep = __pte(0); }
-
-static int sun4c_pmd_bad(pmd_t pmd)
-{
- return (((pmd_val(pmd) & ~PAGE_MASK) != PGD_TABLE) ||
- (!virt_addr_valid(pmd_val(pmd))));
-}
-
-static int sun4c_pmd_present(pmd_t pmd)
-{
- return ((pmd_val(pmd) & PGD_PRESENT) != 0);
-}
-
-#if 0 /* if PMD takes one word */
-static void sun4c_pmd_clear(pmd_t *pmdp) { *pmdp = __pmd(0); }
-#else /* if pmd_t is a longish aggregate */
-static void sun4c_pmd_clear(pmd_t *pmdp) {
- memset((void *)pmdp, 0, sizeof(pmd_t));
-}
-#endif
-
-static int sun4c_pgd_none(pgd_t pgd) { return 0; }
-static int sun4c_pgd_bad(pgd_t pgd) { return 0; }
-static int sun4c_pgd_present(pgd_t pgd) { return 1; }
-static void sun4c_pgd_clear(pgd_t * pgdp) { }
-
-/*
- * The following only work if pte_present() is true.
- * Undefined behaviour if not..
- */
-static pte_t sun4c_pte_mkwrite(pte_t pte)
-{
- pte = __pte(pte_val(pte) | _SUN4C_PAGE_WRITE);
- if (pte_val(pte) & _SUN4C_PAGE_MODIFIED)
- pte = __pte(pte_val(pte) | _SUN4C_PAGE_SILENT_WRITE);
- return pte;
-}
-
-static pte_t sun4c_pte_mkdirty(pte_t pte)
-{
- pte = __pte(pte_val(pte) | _SUN4C_PAGE_MODIFIED);
- if (pte_val(pte) & _SUN4C_PAGE_WRITE)
- pte = __pte(pte_val(pte) | _SUN4C_PAGE_SILENT_WRITE);
- return pte;
-}
-
-static pte_t sun4c_pte_mkyoung(pte_t pte)
-{
- pte = __pte(pte_val(pte) | _SUN4C_PAGE_ACCESSED);
- if (pte_val(pte) & _SUN4C_PAGE_READ)
- pte = __pte(pte_val(pte) | _SUN4C_PAGE_SILENT_READ);
- return pte;
-}
-
-/*
- * Conversion functions: convert a page and protection to a page entry,
- * and a page entry and page directory to the page they refer to.
- */
-static pte_t sun4c_mk_pte(struct page *page, pgprot_t pgprot)
-{
- return __pte(page_to_pfn(page) | pgprot_val(pgprot));
-}
-
-static pte_t sun4c_mk_pte_phys(unsigned long phys_page, pgprot_t pgprot)
-{
- return __pte((phys_page >> PAGE_SHIFT) | pgprot_val(pgprot));
-}
-
-static pte_t sun4c_mk_pte_io(unsigned long page, pgprot_t pgprot, int space)
-{
- return __pte(((page - PAGE_OFFSET) >> PAGE_SHIFT) | pgprot_val(pgprot));
-}
-
-static unsigned long sun4c_pte_pfn(pte_t pte)
-{
- return pte_val(pte) & SUN4C_PFN_MASK;
-}
-
-static pte_t sun4c_pgoff_to_pte(unsigned long pgoff)
-{
- return __pte(pgoff | _SUN4C_PAGE_FILE);
-}
-
-static unsigned long sun4c_pte_to_pgoff(pte_t pte)
-{
- return pte_val(pte) & ((1UL << PTE_FILE_MAX_BITS) - 1);
-}
-
-
-static inline unsigned long sun4c_pmd_page_v(pmd_t pmd)
-{
- return (pmd_val(pmd) & PAGE_MASK);
-}
-
-static struct page *sun4c_pmd_page(pmd_t pmd)
-{
- return virt_to_page(sun4c_pmd_page_v(pmd));
-}
-
-static unsigned long sun4c_pgd_page(pgd_t pgd) { return 0; }
-
-/* to find an entry in a page-table-directory */
-static inline pgd_t *sun4c_pgd_offset(struct mm_struct * mm, unsigned long address)
-{
- return mm->pgd + (address >> SUN4C_PGDIR_SHIFT);
-}
-
-/* Find an entry in the second-level page table.. */
-static pmd_t *sun4c_pmd_offset(pgd_t * dir, unsigned long address)
-{
- return (pmd_t *) dir;
-}
-
-/* Find an entry in the third-level page table.. */
-pte_t *sun4c_pte_offset_kernel(pmd_t * dir, unsigned long address)
-{
- return (pte_t *) sun4c_pmd_page_v(*dir) +
- ((address >> PAGE_SHIFT) & (SUN4C_PTRS_PER_PTE - 1));
-}
-
-static unsigned long sun4c_swp_type(swp_entry_t entry)
-{
- return (entry.val & SUN4C_SWP_TYPE_MASK);
-}
-
-static unsigned long sun4c_swp_offset(swp_entry_t entry)
-{
- return (entry.val >> SUN4C_SWP_OFF_SHIFT) & SUN4C_SWP_OFF_MASK;
-}
-
-static swp_entry_t sun4c_swp_entry(unsigned long type, unsigned long offset)
-{
- return (swp_entry_t) {
- (offset & SUN4C_SWP_OFF_MASK) << SUN4C_SWP_OFF_SHIFT
- | (type & SUN4C_SWP_TYPE_MASK) };
-}
-
-static void sun4c_free_pte_slow(pte_t *pte)
-{
- free_page((unsigned long)pte);
-}
-
-static void sun4c_free_pgd_slow(pgd_t *pgd)
-{
- free_page((unsigned long)pgd);
-}
-
-static pgd_t *sun4c_get_pgd_fast(void)
-{
- unsigned long *ret;
-
- if ((ret = pgd_quicklist) != NULL) {
- pgd_quicklist = (unsigned long *)(*ret);
- ret[0] = ret[1];
- pgtable_cache_size--;
- } else {
- pgd_t *init;
-
- ret = (unsigned long *)__get_free_page(GFP_KERNEL);
- memset (ret, 0, (KERNBASE / SUN4C_PGDIR_SIZE) * sizeof(pgd_t));
- init = sun4c_pgd_offset(&init_mm, 0);
- memcpy (((pgd_t *)ret) + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD,
- (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
- }
- return (pgd_t *)ret;
-}
-
-static void sun4c_free_pgd_fast(pgd_t *pgd)
-{
- *(unsigned long *)pgd = (unsigned long) pgd_quicklist;
- pgd_quicklist = (unsigned long *) pgd;
- pgtable_cache_size++;
-}
-
-
-static inline pte_t *
-sun4c_pte_alloc_one_fast(struct mm_struct *mm, unsigned long address)
-{
- unsigned long *ret;
-
- if ((ret = (unsigned long *)pte_quicklist) != NULL) {
- pte_quicklist = (unsigned long *)(*ret);
- ret[0] = ret[1];
- pgtable_cache_size--;
- }
- return (pte_t *)ret;
-}
-
-static pte_t *sun4c_pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address)
-{
- pte_t *pte;
-
- if ((pte = sun4c_pte_alloc_one_fast(mm, address)) != NULL)
- return pte;
-
- pte = (pte_t *)get_zeroed_page(GFP_KERNEL|__GFP_REPEAT);
- return pte;
-}
-
-static pgtable_t sun4c_pte_alloc_one(struct mm_struct *mm, unsigned long address)
-{
- pte_t *pte;
- struct page *page;
-
- pte = sun4c_pte_alloc_one_kernel(mm, address);
- if (pte == NULL)
- return NULL;
- page = virt_to_page(pte);
- pgtable_page_ctor(page);
- return page;
-}
-
-static inline void sun4c_free_pte_fast(pte_t *pte)
-{
- *(unsigned long *)pte = (unsigned long) pte_quicklist;
- pte_quicklist = (unsigned long *) pte;
- pgtable_cache_size++;
-}
-
-static void sun4c_pte_free(pgtable_t pte)
-{
- pgtable_page_dtor(pte);
- sun4c_free_pte_fast(page_address(pte));
-}
-
-/*
- * allocating and freeing a pmd is trivial: the 1-entry pmd is
- * inside the pgd, so has no extra memory associated with it.
- */
-static pmd_t *sun4c_pmd_alloc_one(struct mm_struct *mm, unsigned long address)
-{
- BUG();
- return NULL;
-}
-
-static void sun4c_free_pmd_fast(pmd_t * pmd) { }
-
-static void sun4c_check_pgt_cache(int low, int high)
-{
- if (pgtable_cache_size > high) {
- do {
- if (pgd_quicklist)
- sun4c_free_pgd_slow(sun4c_get_pgd_fast());
- if (pte_quicklist)
- sun4c_free_pte_slow(sun4c_pte_alloc_one_fast(NULL, 0));
- } while (pgtable_cache_size > low);
- }
-}
-
-/* An experiment, turn off by default for now... -DaveM */
-#define SUN4C_PRELOAD_PSEG
-
-void sun4c_update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t *ptep)
-{
- unsigned long flags;
- int pseg;
-
- if (vma->vm_mm->context == NO_CONTEXT)
- return;
-
- local_irq_save(flags);
- address &= PAGE_MASK;
- if ((pseg = sun4c_get_segmap(address)) == invalid_segment) {
- struct sun4c_mmu_entry *entry = sun4c_user_strategy();
- struct mm_struct *mm = vma->vm_mm;
- unsigned long start, end;
-
- entry->vaddr = start = (address & SUN4C_REAL_PGDIR_MASK);
- entry->ctx = mm->context;
- add_ring_ordered(sun4c_context_ring + mm->context, entry);
- sun4c_put_segmap(entry->vaddr, entry->pseg);
- end = start + SUN4C_REAL_PGDIR_SIZE;
- while (start < end) {
-#ifdef SUN4C_PRELOAD_PSEG
- pgd_t *pgdp = sun4c_pgd_offset(mm, start);
- pte_t *ptep;
-
- if (!pgdp)
- goto no_mapping;
- ptep = sun4c_pte_offset_kernel((pmd_t *) pgdp, start);
- if (!ptep || !(pte_val(*ptep) & _SUN4C_PAGE_PRESENT))
- goto no_mapping;
- sun4c_put_pte(start, pte_val(*ptep));
- goto next;
-
- no_mapping:
-#endif
- sun4c_put_pte(start, 0);
-#ifdef SUN4C_PRELOAD_PSEG
- next:
-#endif
- start += PAGE_SIZE;
- }
-#ifndef SUN4C_PRELOAD_PSEG
- sun4c_put_pte(address, pte_val(*ptep));
-#endif
- local_irq_restore(flags);
- return;
- } else {
- struct sun4c_mmu_entry *entry = &mmu_entry_pool[pseg];
-
- remove_lru(entry);
- add_lru(entry);
- }
-
- sun4c_put_pte(address, pte_val(*ptep));
- local_irq_restore(flags);
-}
-
-extern void sparc_context_init(int);
-extern unsigned long bootmem_init(unsigned long *pages_avail);
-extern unsigned long last_valid_pfn;
-
-void __init sun4c_paging_init(void)
-{
- int i, cnt;
- unsigned long kernel_end, vaddr;
- extern struct resource sparc_iomap;
- unsigned long end_pfn, pages_avail;
-
- kernel_end = (unsigned long) &_end;
- kernel_end = SUN4C_REAL_PGDIR_ALIGN(kernel_end);
-
- pages_avail = 0;
- last_valid_pfn = bootmem_init(&pages_avail);
- end_pfn = last_valid_pfn;
-
- sun4c_probe_mmu();
- invalid_segment = (num_segmaps - 1);
- sun4c_init_mmu_entry_pool();
- sun4c_init_rings();
- sun4c_init_map_kernelprom(kernel_end);
- sun4c_init_clean_mmu(kernel_end);
- sun4c_init_fill_kernel_ring(SUN4C_KERNEL_BUCKETS);
- sun4c_init_lock_area(sparc_iomap.start, IOBASE_END);
- sun4c_init_lock_area(DVMA_VADDR, DVMA_END);
- sun4c_init_lock_areas();
- sun4c_init_fill_user_ring();
-
- sun4c_set_context(0);
- memset(swapper_pg_dir, 0, PAGE_SIZE);
- memset(pg0, 0, PAGE_SIZE);
- memset(pg1, 0, PAGE_SIZE);
- memset(pg2, 0, PAGE_SIZE);
- memset(pg3, 0, PAGE_SIZE);
-
- /* Save work later. */
- vaddr = VMALLOC_START;
- swapper_pg_dir[vaddr>>SUN4C_PGDIR_SHIFT] = __pgd(PGD_TABLE | (unsigned long) pg0);
- vaddr += SUN4C_PGDIR_SIZE;
- swapper_pg_dir[vaddr>>SUN4C_PGDIR_SHIFT] = __pgd(PGD_TABLE | (unsigned long) pg1);
- vaddr += SUN4C_PGDIR_SIZE;
- swapper_pg_dir[vaddr>>SUN4C_PGDIR_SHIFT] = __pgd(PGD_TABLE | (unsigned long) pg2);
- vaddr += SUN4C_PGDIR_SIZE;
- swapper_pg_dir[vaddr>>SUN4C_PGDIR_SHIFT] = __pgd(PGD_TABLE | (unsigned long) pg3);
- sun4c_init_ss2_cache_bug();
- sparc_context_init(num_contexts);
-
- {
- unsigned long zones_size[MAX_NR_ZONES];
- unsigned long zholes_size[MAX_NR_ZONES];
- unsigned long npages;
- int znum;
-
- for (znum = 0; znum < MAX_NR_ZONES; znum++)
- zones_size[znum] = zholes_size[znum] = 0;
-
- npages = max_low_pfn - pfn_base;
-
- zones_size[ZONE_DMA] = npages;
- zholes_size[ZONE_DMA] = npages - pages_avail;
-
- npages = highend_pfn - max_low_pfn;
- zones_size[ZONE_HIGHMEM] = npages;
- zholes_size[ZONE_HIGHMEM] = npages - calc_highpages();
-
- free_area_init_node(0, zones_size, pfn_base, zholes_size);
- }
-
- cnt = 0;
- for (i = 0; i < num_segmaps; i++)
- if (mmu_entry_pool[i].locked)
- cnt++;
-
- max_user_taken_entries = num_segmaps - cnt - 40 - 1;
-
- printk("SUN4C: %d mmu entries for the kernel\n", cnt);
-}
-
-static pgprot_t sun4c_pgprot_noncached(pgprot_t prot)
-{
- prot |= __pgprot(_SUN4C_PAGE_IO | _SUN4C_PAGE_NOCACHE);
-
- return prot;
-}
-
-/* Load up routines and constants for sun4c mmu */
-void __init ld_mmu_sun4c(void)
-{
- extern void ___xchg32_sun4c(void);
-
- printk("Loading sun4c MMU routines\n");
-
- /* First the constants */
- BTFIXUPSET_SIMM13(pgdir_shift, SUN4C_PGDIR_SHIFT);
- BTFIXUPSET_SETHI(pgdir_size, SUN4C_PGDIR_SIZE);
- BTFIXUPSET_SETHI(pgdir_mask, SUN4C_PGDIR_MASK);
-
- BTFIXUPSET_SIMM13(ptrs_per_pmd, SUN4C_PTRS_PER_PMD);
- BTFIXUPSET_SIMM13(ptrs_per_pgd, SUN4C_PTRS_PER_PGD);
- BTFIXUPSET_SIMM13(user_ptrs_per_pgd, KERNBASE / SUN4C_PGDIR_SIZE);
-
- BTFIXUPSET_INT(page_none, pgprot_val(SUN4C_PAGE_NONE));
- PAGE_SHARED = pgprot_val(SUN4C_PAGE_SHARED);
- BTFIXUPSET_INT(page_copy, pgprot_val(SUN4C_PAGE_COPY));
- BTFIXUPSET_INT(page_readonly, pgprot_val(SUN4C_PAGE_READONLY));
- BTFIXUPSET_INT(page_kernel, pgprot_val(SUN4C_PAGE_KERNEL));
- page_kernel = pgprot_val(SUN4C_PAGE_KERNEL);
-
- /* Functions */
- BTFIXUPSET_CALL(pgprot_noncached, sun4c_pgprot_noncached, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(___xchg32, ___xchg32_sun4c, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(do_check_pgt_cache, sun4c_check_pgt_cache, BTFIXUPCALL_NORM);
-
- BTFIXUPSET_CALL(flush_cache_all, sun4c_flush_cache_all, BTFIXUPCALL_NORM);
-
- if (sun4c_vacinfo.do_hwflushes) {
- BTFIXUPSET_CALL(sun4c_flush_page, sun4c_flush_page_hw, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(sun4c_flush_segment, sun4c_flush_segment_hw, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(sun4c_flush_context, sun4c_flush_context_hw, BTFIXUPCALL_NORM);
- } else {
- BTFIXUPSET_CALL(sun4c_flush_page, sun4c_flush_page_sw, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(sun4c_flush_segment, sun4c_flush_segment_sw, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(sun4c_flush_context, sun4c_flush_context_sw, BTFIXUPCALL_NORM);
- }
-
- BTFIXUPSET_CALL(flush_tlb_mm, sun4c_flush_tlb_mm, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_cache_mm, sun4c_flush_cache_mm, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(destroy_context, sun4c_destroy_context, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(switch_mm, sun4c_switch_mm, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_cache_page, sun4c_flush_cache_page, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_tlb_page, sun4c_flush_tlb_page, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_tlb_range, sun4c_flush_tlb_range, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_cache_range, sun4c_flush_cache_range, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(__flush_page_to_ram, sun4c_flush_page_to_ram, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_tlb_all, sun4c_flush_tlb_all, BTFIXUPCALL_NORM);
-
- BTFIXUPSET_CALL(flush_sig_insns, sun4c_flush_sig_insns, BTFIXUPCALL_NOP);
-
- BTFIXUPSET_CALL(set_pte, sun4c_set_pte, BTFIXUPCALL_STO1O0);
-
- BTFIXUPSET_CALL(pte_pfn, sun4c_pte_pfn, BTFIXUPCALL_NORM);
-#if 0 /* PAGE_SHIFT <= 12 */ /* Eek. Investigate. XXX */
- BTFIXUPSET_CALL(pmd_page, sun4c_pmd_page, BTFIXUPCALL_ANDNINT(PAGE_SIZE - 1));
-#else
- BTFIXUPSET_CALL(pmd_page, sun4c_pmd_page, BTFIXUPCALL_NORM);
-#endif
- BTFIXUPSET_CALL(pmd_set, sun4c_pmd_set, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(pmd_populate, sun4c_pmd_populate, BTFIXUPCALL_NORM);
-
- BTFIXUPSET_CALL(pte_present, sun4c_pte_present, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(pte_clear, sun4c_pte_clear, BTFIXUPCALL_STG0O0);
-
- BTFIXUPSET_CALL(pmd_bad, sun4c_pmd_bad, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(pmd_present, sun4c_pmd_present, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(pmd_clear, sun4c_pmd_clear, BTFIXUPCALL_STG0O0);
-
- BTFIXUPSET_CALL(pgd_none, sun4c_pgd_none, BTFIXUPCALL_RETINT(0));
- BTFIXUPSET_CALL(pgd_bad, sun4c_pgd_bad, BTFIXUPCALL_RETINT(0));
- BTFIXUPSET_CALL(pgd_present, sun4c_pgd_present, BTFIXUPCALL_RETINT(1));
- BTFIXUPSET_CALL(pgd_clear, sun4c_pgd_clear, BTFIXUPCALL_NOP);
-
- BTFIXUPSET_CALL(mk_pte, sun4c_mk_pte, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(mk_pte_phys, sun4c_mk_pte_phys, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(mk_pte_io, sun4c_mk_pte_io, BTFIXUPCALL_NORM);
-
- BTFIXUPSET_INT(pte_modify_mask, _SUN4C_PAGE_CHG_MASK);
- BTFIXUPSET_CALL(pmd_offset, sun4c_pmd_offset, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(pte_offset_kernel, sun4c_pte_offset_kernel, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(free_pte_fast, sun4c_free_pte_fast, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(pte_free, sun4c_pte_free, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(pte_alloc_one_kernel, sun4c_pte_alloc_one_kernel, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(pte_alloc_one, sun4c_pte_alloc_one, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(free_pmd_fast, sun4c_free_pmd_fast, BTFIXUPCALL_NOP);
- BTFIXUPSET_CALL(pmd_alloc_one, sun4c_pmd_alloc_one, BTFIXUPCALL_RETO0);
- BTFIXUPSET_CALL(free_pgd_fast, sun4c_free_pgd_fast, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(get_pgd_fast, sun4c_get_pgd_fast, BTFIXUPCALL_NORM);
-
- BTFIXUPSET_HALF(pte_writei, _SUN4C_PAGE_WRITE);
- BTFIXUPSET_HALF(pte_dirtyi, _SUN4C_PAGE_MODIFIED);
- BTFIXUPSET_HALF(pte_youngi, _SUN4C_PAGE_ACCESSED);
- BTFIXUPSET_HALF(pte_filei, _SUN4C_PAGE_FILE);
- BTFIXUPSET_HALF(pte_wrprotecti, _SUN4C_PAGE_WRITE|_SUN4C_PAGE_SILENT_WRITE);
- BTFIXUPSET_HALF(pte_mkcleani, _SUN4C_PAGE_MODIFIED|_SUN4C_PAGE_SILENT_WRITE);
- BTFIXUPSET_HALF(pte_mkoldi, _SUN4C_PAGE_ACCESSED|_SUN4C_PAGE_SILENT_READ);
- BTFIXUPSET_CALL(pte_mkwrite, sun4c_pte_mkwrite, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(pte_mkdirty, sun4c_pte_mkdirty, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(pte_mkyoung, sun4c_pte_mkyoung, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(update_mmu_cache, sun4c_update_mmu_cache, BTFIXUPCALL_NORM);
-
- BTFIXUPSET_CALL(pte_to_pgoff, sun4c_pte_to_pgoff, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(pgoff_to_pte, sun4c_pgoff_to_pte, BTFIXUPCALL_NORM);
-
- BTFIXUPSET_CALL(mmu_lockarea, sun4c_lockarea, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(mmu_unlockarea, sun4c_unlockarea, BTFIXUPCALL_NORM);
-
- BTFIXUPSET_CALL(mmu_get_scsi_one, sun4c_get_scsi_one, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(mmu_get_scsi_sgl, sun4c_get_scsi_sgl, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(mmu_release_scsi_one, sun4c_release_scsi_one, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(mmu_release_scsi_sgl, sun4c_release_scsi_sgl, BTFIXUPCALL_NORM);
-
- BTFIXUPSET_CALL(mmu_map_dma_area, sun4c_map_dma_area, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(mmu_unmap_dma_area, sun4c_unmap_dma_area, BTFIXUPCALL_NORM);
-
- BTFIXUPSET_CALL(sparc_mapiorange, sun4c_mapiorange, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(sparc_unmapiorange, sun4c_unmapiorange, BTFIXUPCALL_NORM);
-
- BTFIXUPSET_CALL(__swp_type, sun4c_swp_type, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(__swp_offset, sun4c_swp_offset, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(__swp_entry, sun4c_swp_entry, BTFIXUPCALL_NORM);
-
- BTFIXUPSET_CALL(alloc_thread_info_node, sun4c_alloc_thread_info_node, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(free_thread_info, sun4c_free_thread_info, BTFIXUPCALL_NORM);
-
- BTFIXUPSET_CALL(mmu_info, sun4c_mmu_info, BTFIXUPCALL_NORM);
-
- /* These should _never_ get called with two level tables. */
- BTFIXUPSET_CALL(pgd_set, sun4c_pgd_set, BTFIXUPCALL_NOP);
- BTFIXUPSET_CALL(pgd_page_vaddr, sun4c_pgd_page, BTFIXUPCALL_RETO0);
-}
diff --git a/arch/sparc/mm/ultra.S b/arch/sparc/mm/ultra.S
index b57a5942ba64..874162a11ceb 100644
--- a/arch/sparc/mm/ultra.S
+++ b/arch/sparc/mm/ultra.S
@@ -495,11 +495,11 @@ xcall_fetch_glob_regs:
stx %o7, [%g1 + GR_SNAP_O7]
stx %i7, [%g1 + GR_SNAP_I7]
/* Don't try this at home kids... */
- rdpr %cwp, %g2
- sub %g2, 1, %g7
+ rdpr %cwp, %g3
+ sub %g3, 1, %g7
wrpr %g7, %cwp
mov %i7, %g7
- wrpr %g2, %cwp
+ wrpr %g3, %cwp
stx %g7, [%g1 + GR_SNAP_RPC]
sethi %hi(trap_block), %g7
or %g7, %lo(trap_block), %g7
diff --git a/arch/sparc/mm/viking.S b/arch/sparc/mm/viking.S
index 6dfcc13d3100..bf8ee0613ae7 100644
--- a/arch/sparc/mm/viking.S
+++ b/arch/sparc/mm/viking.S
@@ -14,7 +14,6 @@
#include <asm/page.h>
#include <asm/pgtsrmmu.h>
#include <asm/viking.h>
-#include <asm/btfixup.h>
#ifdef CONFIG_SMP
.data