diff options
Diffstat (limited to 'arch/sparc/mm')
| -rw-r--r-- | arch/sparc/mm/fault_32.c | 9 | ||||
| -rw-r--r-- | arch/sparc/mm/fault_64.c | 116 | ||||
| -rw-r--r-- | arch/sparc/mm/gup.c | 9 | ||||
| -rw-r--r-- | arch/sparc/mm/hugetlbpage.c | 8 | ||||
| -rw-r--r-- | arch/sparc/mm/init_32.c | 7 | ||||
| -rw-r--r-- | arch/sparc/mm/init_64.c | 319 | ||||
| -rw-r--r-- | arch/sparc/mm/init_64.h | 8 | ||||
| -rw-r--r-- | arch/sparc/mm/io-unit.c | 21 | ||||
| -rw-r--r-- | arch/sparc/mm/iommu.c | 25 | ||||
| -rw-r--r-- | arch/sparc/mm/leon_mm.c | 4 | ||||
| -rw-r--r-- | arch/sparc/mm/mm_32.h | 24 | ||||
| -rw-r--r-- | arch/sparc/mm/srmmu.c | 20 | ||||
| -rw-r--r-- | arch/sparc/mm/srmmu.h | 4 | ||||
| -rw-r--r-- | arch/sparc/mm/tlb.c | 48 | ||||
| -rw-r--r-- | arch/sparc/mm/tsb.c | 30 | ||||
| -rw-r--r-- | arch/sparc/mm/ultra.S | 12 | 
16 files changed, 332 insertions, 332 deletions
diff --git a/arch/sparc/mm/fault_32.c b/arch/sparc/mm/fault_32.c index 59dbd464572..908e8c17c90 100644 --- a/arch/sparc/mm/fault_32.c +++ b/arch/sparc/mm/fault_32.c @@ -26,14 +26,14 @@  #include <asm/pgtable.h>  #include <asm/openprom.h>  #include <asm/oplib.h> +#include <asm/setup.h>  #include <asm/smp.h>  #include <asm/traps.h>  #include <asm/uaccess.h> -int show_unhandled_signals = 1; +#include "mm_32.h" -static void unhandled_fault(unsigned long, struct task_struct *, -		struct pt_regs *) __attribute__ ((noreturn)); +int show_unhandled_signals = 1;  static void __noreturn unhandled_fault(unsigned long address,  				       struct task_struct *tsk, @@ -141,9 +141,6 @@ static void __do_fault_siginfo(int code, int sig, struct pt_regs *regs,  	force_sig_info (sig, &info, current);  } -extern unsigned long safe_compute_effective_address(struct pt_regs *, -						    unsigned int); -  static unsigned long compute_si_addr(struct pt_regs *regs, int text_fault)  {  	unsigned int insn; diff --git a/arch/sparc/mm/fault_64.c b/arch/sparc/mm/fault_64.c index 2ebec263d68..587cd056512 100644 --- a/arch/sparc/mm/fault_64.c +++ b/arch/sparc/mm/fault_64.c @@ -21,6 +21,7 @@  #include <linux/kprobes.h>  #include <linux/kdebug.h>  #include <linux/percpu.h> +#include <linux/context_tracking.h>  #include <asm/page.h>  #include <asm/pgtable.h> @@ -31,6 +32,7 @@  #include <asm/lsu.h>  #include <asm/sections.h>  #include <asm/mmu_context.h> +#include <asm/setup.h>  int show_unhandled_signals = 1; @@ -95,38 +97,51 @@ static unsigned int get_user_insn(unsigned long tpc)  	pte_t *ptep, pte;  	unsigned long pa;  	u32 insn = 0; -	unsigned long pstate; -	if (pgd_none(*pgdp)) -		goto outret; +	if (pgd_none(*pgdp) || unlikely(pgd_bad(*pgdp))) +		goto out;  	pudp = pud_offset(pgdp, tpc); -	if (pud_none(*pudp)) -		goto outret; -	pmdp = pmd_offset(pudp, tpc); -	if (pmd_none(*pmdp)) -		goto outret; +	if (pud_none(*pudp) || unlikely(pud_bad(*pudp))) +		goto out;  	/* This disables preemption for us as well. */ -	__asm__ __volatile__("rdpr %%pstate, %0" : "=r" (pstate)); -	__asm__ __volatile__("wrpr %0, %1, %%pstate" -				: : "r" (pstate), "i" (PSTATE_IE)); -	ptep = pte_offset_map(pmdp, tpc); -	pte = *ptep; -	if (!pte_present(pte)) -		goto out; +	local_irq_disable(); -	pa  = (pte_pfn(pte) << PAGE_SHIFT); -	pa += (tpc & ~PAGE_MASK); +	pmdp = pmd_offset(pudp, tpc); +	if (pmd_none(*pmdp) || unlikely(pmd_bad(*pmdp))) +		goto out_irq_enable; + +#ifdef CONFIG_TRANSPARENT_HUGEPAGE +	if (pmd_trans_huge(*pmdp)) { +		if (pmd_trans_splitting(*pmdp)) +			goto out_irq_enable; -	/* Use phys bypass so we don't pollute dtlb/dcache. */ -	__asm__ __volatile__("lduwa [%1] %2, %0" -			     : "=r" (insn) -			     : "r" (pa), "i" (ASI_PHYS_USE_EC)); +		pa  = pmd_pfn(*pmdp) << PAGE_SHIFT; +		pa += tpc & ~HPAGE_MASK; +		/* Use phys bypass so we don't pollute dtlb/dcache. */ +		__asm__ __volatile__("lduwa [%1] %2, %0" +				     : "=r" (insn) +				     : "r" (pa), "i" (ASI_PHYS_USE_EC)); +	} else +#endif +	{ +		ptep = pte_offset_map(pmdp, tpc); +		pte = *ptep; +		if (pte_present(pte)) { +			pa  = (pte_pfn(pte) << PAGE_SHIFT); +			pa += (tpc & ~PAGE_MASK); + +			/* Use phys bypass so we don't pollute dtlb/dcache. */ +			__asm__ __volatile__("lduwa [%1] %2, %0" +					     : "=r" (insn) +					     : "r" (pa), "i" (ASI_PHYS_USE_EC)); +		} +		pte_unmap(ptep); +	} +out_irq_enable: +	local_irq_enable();  out: -	pte_unmap(ptep); -	__asm__ __volatile__("wrpr %0, 0x0, %%pstate" : : "r" (pstate)); -outret:  	return insn;  } @@ -152,7 +167,8 @@ show_signal_msg(struct pt_regs *regs, int sig, int code,  }  static void do_fault_siginfo(int code, int sig, struct pt_regs *regs, -			     unsigned int insn, int fault_code) +			     unsigned long fault_addr, unsigned int insn, +			     int fault_code)  {  	unsigned long addr;  	siginfo_t info; @@ -160,10 +176,18 @@ static void do_fault_siginfo(int code, int sig, struct pt_regs *regs,  	info.si_code = code;  	info.si_signo = sig;  	info.si_errno = 0; -	if (fault_code & FAULT_CODE_ITLB) +	if (fault_code & FAULT_CODE_ITLB) {  		addr = regs->tpc; -	else -		addr = compute_effective_address(regs, insn, 0); +	} else { +		/* If we were able to probe the faulting instruction, use it +		 * to compute a precise fault address.  Otherwise use the fault +		 * time provided address which may only have page granularity. +		 */ +		if (insn) +			addr = compute_effective_address(regs, insn, 0); +		else +			addr = fault_addr; +	}  	info.si_addr = (void __user *) addr;  	info.si_trapno = 0; @@ -173,9 +197,6 @@ static void do_fault_siginfo(int code, int sig, struct pt_regs *regs,  	force_sig_info(sig, &info, current);  } -extern int handle_ldf_stq(u32, struct pt_regs *); -extern int handle_ld_nf(u32, struct pt_regs *); -  static unsigned int get_fault_insn(struct pt_regs *regs, unsigned int insn)  {  	if (!insn) { @@ -238,7 +259,7 @@ static void __kprobes do_kernel_fault(struct pt_regs *regs, int si_code,  		/* The si_code was set to make clear whether  		 * this was a SEGV_MAPERR or SEGV_ACCERR fault.  		 */ -		do_fault_siginfo(si_code, SIGSEGV, regs, insn, fault_code); +		do_fault_siginfo(si_code, SIGSEGV, regs, address, insn, fault_code);  		return;  	} @@ -258,20 +279,9 @@ static void noinline __kprobes bogus_32bit_fault_tpc(struct pt_regs *regs)  	show_regs(regs);  } -static void noinline __kprobes bogus_32bit_fault_address(struct pt_regs *regs, -							 unsigned long addr) -{ -	static int times; - -	if (times++ < 10) -		printk(KERN_ERR "FAULT[%s:%d]: 32-bit process " -		       "reports 64-bit fault address [%lx]\n", -		       current->comm, current->pid, addr); -	show_regs(regs); -} -  asmlinkage void __kprobes do_sparc64_fault(struct pt_regs *regs)  { +	enum ctx_state prev_state = exception_enter();  	struct mm_struct *mm = current->mm;  	struct vm_area_struct *vma;  	unsigned int insn = 0; @@ -282,7 +292,7 @@ asmlinkage void __kprobes do_sparc64_fault(struct pt_regs *regs)  	fault_code = get_thread_fault_code();  	if (notify_page_fault(regs)) -		return; +		goto exit_exception;  	si_code = SEGV_MAPERR;  	address = current_thread_info()->fault_address; @@ -298,10 +308,8 @@ asmlinkage void __kprobes do_sparc64_fault(struct pt_regs *regs)  				goto intr_or_no_mm;  			}  		} -		if (unlikely((address >> 32) != 0)) { -			bogus_32bit_fault_address(regs, address); +		if (unlikely((address >> 32) != 0))  			goto intr_or_no_mm; -		}  	}  	if (regs->tstate & TSTATE_PRIV) { @@ -313,7 +321,7 @@ asmlinkage void __kprobes do_sparc64_fault(struct pt_regs *regs)  			/* Valid, no problems... */  		} else {  			bad_kernel_pc(regs, address); -			return; +			goto exit_exception;  		}  	} else  		flags |= FAULT_FLAG_USER; @@ -430,7 +438,7 @@ good_area:  	fault = handle_mm_fault(mm, vma, address, flags);  	if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current)) -		return; +		goto exit_exception;  	if (unlikely(fault & VM_FAULT_ERROR)) {  		if (fault & VM_FAULT_OOM) @@ -482,6 +490,8 @@ good_area:  	}  #endif +exit_exception: +	exception_exit(prev_state);  	return;  	/* @@ -494,7 +504,7 @@ bad_area:  handle_kernel_fault:  	do_kernel_fault(regs, si_code, fault_code, insn, address); -	return; +	goto exit_exception;  /*   * We ran out of memory, or some other thing happened to us that made @@ -505,7 +515,7 @@ out_of_memory:  	up_read(&mm->mmap_sem);  	if (!(regs->tstate & TSTATE_PRIV)) {  		pagefault_out_of_memory(); -		return; +		goto exit_exception;  	}  	goto handle_kernel_fault; @@ -521,7 +531,7 @@ do_sigbus:  	 * Send a sigbus, regardless of whether we were in kernel  	 * or user mode.  	 */ -	do_fault_siginfo(BUS_ADRERR, SIGBUS, regs, insn, fault_code); +	do_fault_siginfo(BUS_ADRERR, SIGBUS, regs, address, insn, fault_code);  	/* Kernel mode? Handle exceptions or die */  	if (regs->tstate & TSTATE_PRIV) diff --git a/arch/sparc/mm/gup.c b/arch/sparc/mm/gup.c index 01ee23dd724..1aed0432c64 100644 --- a/arch/sparc/mm/gup.c +++ b/arch/sparc/mm/gup.c @@ -71,13 +71,12 @@ static int gup_huge_pmd(pmd_t *pmdp, pmd_t pmd, unsigned long addr,  			int *nr)  {  	struct page *head, *page, *tail; -	u32 mask;  	int refs; -	mask = PMD_HUGE_PRESENT; -	if (write) -		mask |= PMD_HUGE_WRITE; -	if ((pmd_val(pmd) & mask) != mask) +	if (!(pmd_val(pmd) & _PAGE_VALID)) +		return 0; + +	if (write && !pmd_write(pmd))  		return 0;  	refs = 0; diff --git a/arch/sparc/mm/hugetlbpage.c b/arch/sparc/mm/hugetlbpage.c index 96399646570..d329537739c 100644 --- a/arch/sparc/mm/hugetlbpage.c +++ b/arch/sparc/mm/hugetlbpage.c @@ -4,7 +4,6 @@   * Copyright (C) 2002, 2003, 2006 David S. Miller (davem@davemloft.net)   */ -#include <linux/init.h>  #include <linux/fs.h>  #include <linux/mm.h>  #include <linux/hugetlb.h> @@ -21,8 +20,6 @@  /* Slightly simplified from the non-hugepage variant because by   * definition we don't have to worry about any page coloring stuff   */ -#define VA_EXCLUDE_START (0x0000080000000000UL - (1UL << 32UL)) -#define VA_EXCLUDE_END   (0xfffff80000000000UL + (1UL << 32UL))  static unsigned long hugetlb_get_unmapped_area_bottomup(struct file *filp,  							unsigned long addr, @@ -234,11 +231,6 @@ int pud_huge(pud_t pud)  	return 0;  } -int pmd_huge_support(void) -{ -	return 0; -} -  struct page *follow_huge_pmd(struct mm_struct *mm, unsigned long address,  			     pmd_t *pmd, int write)  { diff --git a/arch/sparc/mm/init_32.c b/arch/sparc/mm/init_32.c index db698708280..eb828715527 100644 --- a/arch/sparc/mm/init_32.c +++ b/arch/sparc/mm/init_32.c @@ -31,10 +31,13 @@  #include <asm/pgtable.h>  #include <asm/vaddrs.h>  #include <asm/pgalloc.h>	/* bug in asm-generic/tlb.h: check_pgt_cache */ +#include <asm/setup.h>  #include <asm/tlb.h>  #include <asm/prom.h>  #include <asm/leon.h> +#include "mm_32.h" +  unsigned long *sparc_valid_addr_bitmap;  EXPORT_SYMBOL(sparc_valid_addr_bitmap); @@ -63,7 +66,6 @@ void show_mem(unsigned int filter)  } -extern unsigned long cmdline_memory_size;  unsigned long last_valid_pfn;  unsigned long calc_highpages(void) @@ -246,9 +248,6 @@ unsigned long __init bootmem_init(unsigned long *pages_avail)   * init routine based upon the Sun model type on the Sparc.   *   */ -extern void srmmu_paging_init(void); -extern void device_scan(void); -  void __init paging_init(void)  {  	srmmu_paging_init(); diff --git a/arch/sparc/mm/init_64.c b/arch/sparc/mm/init_64.c index ed82edad1a3..16b58ff11e6 100644 --- a/arch/sparc/mm/init_64.c +++ b/arch/sparc/mm/init_64.c @@ -47,6 +47,7 @@  #include <asm/prom.h>  #include <asm/mdesc.h>  #include <asm/cpudata.h> +#include <asm/setup.h>  #include <asm/irq.h>  #include "init_64.h" @@ -354,7 +355,7 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t *  #if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE)  	if (mm->context.huge_pte_count && is_hugetlb_pte(pte)) -		__update_mmu_tsb_insert(mm, MM_TSB_HUGE, HPAGE_SHIFT, +		__update_mmu_tsb_insert(mm, MM_TSB_HUGE, REAL_HPAGE_SHIFT,  					address, pte_val(pte));  	else  #endif @@ -588,7 +589,7 @@ static void __init remap_kernel(void)  	int i, tlb_ent = sparc64_highest_locked_tlbent();  	tte_vaddr = (unsigned long) KERNBASE; -	phys_page = (prom_boot_mapping_phys_low >> 22UL) << 22UL; +	phys_page = (prom_boot_mapping_phys_low >> ILOG2_4MB) << ILOG2_4MB;  	tte_data = kern_large_tte(phys_page);  	kern_locked_tte_data = tte_data; @@ -794,11 +795,11 @@ struct node_mem_mask {  static struct node_mem_mask node_masks[MAX_NUMNODES];  static int num_node_masks; +#ifdef CONFIG_NEED_MULTIPLE_NODES +  int numa_cpu_lookup_table[NR_CPUS];  cpumask_t numa_cpumask_lookup_table[MAX_NUMNODES]; -#ifdef CONFIG_NEED_MULTIPLE_NODES -  struct mdesc_mblock {  	u64	base;  	u64	size; @@ -887,17 +888,21 @@ static void __init allocate_node_data(int nid)  static void init_node_masks_nonnuma(void)  { +#ifdef CONFIG_NEED_MULTIPLE_NODES  	int i; +#endif  	numadbg("Initializing tables for non-numa.\n");  	node_masks[0].mask = node_masks[0].val = 0;  	num_node_masks = 1; +#ifdef CONFIG_NEED_MULTIPLE_NODES  	for (i = 0; i < NR_CPUS; i++)  		numa_cpu_lookup_table[i] = 0;  	cpumask_setall(&numa_cpumask_lookup_table[0]); +#endif  }  #ifdef CONFIG_NEED_MULTIPLE_NODES @@ -1021,7 +1026,8 @@ static void __init add_node_ranges(void)  				"start[%lx] end[%lx]\n",  				nid, start, this_end); -			memblock_set_node(start, this_end - start, nid); +			memblock_set_node(start, this_end - start, +					  &memblock.memory, nid);  			start = this_end;  		}  	} @@ -1325,7 +1331,7 @@ static void __init bootmem_init_nonnuma(void)  	       (top_of_ram - total_ram) >> 20);  	init_node_masks_nonnuma(); -	memblock_set_node(0, (phys_addr_t)ULLONG_MAX, 0); +	memblock_set_node(0, (phys_addr_t)ULLONG_MAX, &memblock.memory, 0);  	allocate_node_data(0);  	node_set_online(0);  } @@ -1557,6 +1563,96 @@ unsigned long __init find_ecache_flush_span(unsigned long size)  	return ~0UL;  } +unsigned long PAGE_OFFSET; +EXPORT_SYMBOL(PAGE_OFFSET); + +static void __init page_offset_shift_patch_one(unsigned int *insn, unsigned long phys_bits) +{ +	unsigned long final_shift; +	unsigned int val = *insn; +	unsigned int cnt; + +	/* We are patching in ilog2(max_supported_phys_address), and +	 * we are doing so in a manner similar to a relocation addend. +	 * That is, we are adding the shift value to whatever value +	 * is in the shift instruction count field already. +	 */ +	cnt = (val & 0x3f); +	val &= ~0x3f; + +	/* If we are trying to shift >= 64 bits, clear the destination +	 * register.  This can happen when phys_bits ends up being equal +	 * to MAX_PHYS_ADDRESS_BITS. +	 */ +	final_shift = (cnt + (64 - phys_bits)); +	if (final_shift >= 64) { +		unsigned int rd = (val >> 25) & 0x1f; + +		val = 0x80100000 | (rd << 25); +	} else { +		val |= final_shift; +	} +	*insn = val; + +	__asm__ __volatile__("flush	%0" +			     : /* no outputs */ +			     : "r" (insn)); +} + +static void __init page_offset_shift_patch(unsigned long phys_bits) +{ +	extern unsigned int __page_offset_shift_patch; +	extern unsigned int __page_offset_shift_patch_end; +	unsigned int *p; + +	p = &__page_offset_shift_patch; +	while (p < &__page_offset_shift_patch_end) { +		unsigned int *insn = (unsigned int *)(unsigned long)*p; + +		page_offset_shift_patch_one(insn, phys_bits); + +		p++; +	} +} + +static void __init setup_page_offset(void) +{ +	unsigned long max_phys_bits = 40; + +	if (tlb_type == cheetah || tlb_type == cheetah_plus) { +		max_phys_bits = 42; +	} else if (tlb_type == hypervisor) { +		switch (sun4v_chip_type) { +		case SUN4V_CHIP_NIAGARA1: +		case SUN4V_CHIP_NIAGARA2: +			max_phys_bits = 39; +			break; +		case SUN4V_CHIP_NIAGARA3: +			max_phys_bits = 43; +			break; +		case SUN4V_CHIP_NIAGARA4: +		case SUN4V_CHIP_NIAGARA5: +		case SUN4V_CHIP_SPARC64X: +		default: +			max_phys_bits = 47; +			break; +		} +	} + +	if (max_phys_bits > MAX_PHYS_ADDRESS_BITS) { +		prom_printf("MAX_PHYS_ADDRESS_BITS is too small, need %lu\n", +			    max_phys_bits); +		prom_halt(); +	} + +	PAGE_OFFSET = PAGE_OFFSET_BY_BITS(max_phys_bits); + +	pr_info("PAGE_OFFSET is 0x%016lx (max_phys_bits == %lu)\n", +		PAGE_OFFSET, max_phys_bits); + +	page_offset_shift_patch(max_phys_bits); +} +  static void __init tsb_phys_patch(void)  {  	struct tsb_ldquad_phys_patch_entry *pquad; @@ -1722,7 +1818,7 @@ static void __init sun4v_linear_pte_xor_finalize(void)  #ifndef CONFIG_DEBUG_PAGEALLOC  	if (cpu_pgsz_mask & HV_PGSZ_MASK_256MB) {  		kern_linear_pte_xor[1] = (_PAGE_VALID | _PAGE_SZ256MB_4V) ^ -			0xfffff80000000000UL; +			PAGE_OFFSET;  		kern_linear_pte_xor[1] |= (_PAGE_CP_4V | _PAGE_CV_4V |  					   _PAGE_P_4V | _PAGE_W_4V);  	} else { @@ -1731,7 +1827,7 @@ static void __init sun4v_linear_pte_xor_finalize(void)  	if (cpu_pgsz_mask & HV_PGSZ_MASK_2GB) {  		kern_linear_pte_xor[2] = (_PAGE_VALID | _PAGE_SZ2GB_4V) ^ -			0xfffff80000000000UL; +			PAGE_OFFSET;  		kern_linear_pte_xor[2] |= (_PAGE_CP_4V | _PAGE_CV_4V |  					   _PAGE_P_4V | _PAGE_W_4V);  	} else { @@ -1740,7 +1836,7 @@ static void __init sun4v_linear_pte_xor_finalize(void)  	if (cpu_pgsz_mask & HV_PGSZ_MASK_16GB) {  		kern_linear_pte_xor[3] = (_PAGE_VALID | _PAGE_SZ16GB_4V) ^ -			0xfffff80000000000UL; +			PAGE_OFFSET;  		kern_linear_pte_xor[3] |= (_PAGE_CP_4V | _PAGE_CV_4V |  					   _PAGE_P_4V | _PAGE_W_4V);  	} else { @@ -1752,7 +1848,7 @@ static void __init sun4v_linear_pte_xor_finalize(void)  /* paging_init() sets up the page tables */  static unsigned long last_valid_pfn; -pgd_t swapper_pg_dir[2048]; +pgd_t swapper_pg_dir[PTRS_PER_PGD];  static void sun4u_pgprot_init(void);  static void sun4v_pgprot_init(void); @@ -1763,6 +1859,8 @@ void __init paging_init(void)  	unsigned long real_end, i;  	int node; +	setup_page_offset(); +  	/* These build time checkes make sure that the dcache_dirty_cpu()  	 * page->flags usage will work.  	 * @@ -1788,7 +1886,7 @@ void __init paging_init(void)  	BUILD_BUG_ON(NR_CPUS > 4096); -	kern_base = (prom_boot_mapping_phys_low >> 22UL) << 22UL; +	kern_base = (prom_boot_mapping_phys_low >> ILOG2_4MB) << ILOG2_4MB;  	kern_size = (unsigned long)&_end - (unsigned long)KERNBASE;  	/* Invalidate both kernel TSBs.  */ @@ -1844,7 +1942,7 @@ void __init paging_init(void)  	shift = kern_base + PAGE_OFFSET - ((unsigned long)KERNBASE);  	real_end = (unsigned long)_end; -	num_kernel_image_mappings = DIV_ROUND_UP(real_end - KERNBASE, 1 << 22); +	num_kernel_image_mappings = DIV_ROUND_UP(real_end - KERNBASE, 1 << ILOG2_4MB);  	printk("Kernel: Using %d locked TLB entries for main kernel image.\n",  	       num_kernel_image_mappings); @@ -2001,7 +2099,7 @@ static void __init setup_valid_addr_bitmap_from_pavail(unsigned long *bitmap)  				if (new_start <= old_start &&  				    new_end >= (old_start + PAGE_SIZE)) { -					set_bit(old_start >> 22, bitmap); +					set_bit(old_start >> ILOG2_4MB, bitmap);  					goto do_next_page;  				}  			} @@ -2050,7 +2148,7 @@ void __init mem_init(void)  	addr = PAGE_OFFSET + kern_base;  	last = PAGE_ALIGN(kern_size) + addr;  	while (addr < last) { -		set_bit(__pa(addr) >> 22, sparc64_valid_addr_bitmap); +		set_bit(__pa(addr) >> ILOG2_4MB, sparc64_valid_addr_bitmap);  		addr += PAGE_SIZE;  	} @@ -2174,7 +2272,7 @@ int __meminit vmemmap_populate(unsigned long vstart, unsigned long vend,  		void *block;  		if (!(*vmem_pp & _PAGE_VALID)) { -			block = vmemmap_alloc_block(1UL << 22, node); +			block = vmemmap_alloc_block(1UL << ILOG2_4MB, node);  			if (!block)  				return -ENOMEM; @@ -2261,10 +2359,10 @@ static void __init sun4u_pgprot_init(void)  		     __ACCESS_BITS_4U | _PAGE_E_4U);  #ifdef CONFIG_DEBUG_PAGEALLOC -	kern_linear_pte_xor[0] = _PAGE_VALID ^ 0xfffff80000000000UL; +	kern_linear_pte_xor[0] = _PAGE_VALID ^ PAGE_OFFSET;  #else  	kern_linear_pte_xor[0] = (_PAGE_VALID | _PAGE_SZ4MB_4U) ^ -		0xfffff80000000000UL; +		PAGE_OFFSET;  #endif  	kern_linear_pte_xor[0] |= (_PAGE_CP_4U | _PAGE_CV_4U |  				   _PAGE_P_4U | _PAGE_W_4U); @@ -2308,10 +2406,10 @@ static void __init sun4v_pgprot_init(void)  	_PAGE_CACHE = _PAGE_CACHE_4V;  #ifdef CONFIG_DEBUG_PAGEALLOC -	kern_linear_pte_xor[0] = _PAGE_VALID ^ 0xfffff80000000000UL; +	kern_linear_pte_xor[0] = _PAGE_VALID ^ PAGE_OFFSET;  #else  	kern_linear_pte_xor[0] = (_PAGE_VALID | _PAGE_SZ4MB_4V) ^ -		0xfffff80000000000UL; +		PAGE_OFFSET;  #endif  	kern_linear_pte_xor[0] |= (_PAGE_CP_4V | _PAGE_CV_4V |  				   _PAGE_P_4V | _PAGE_W_4V); @@ -2455,53 +2553,13 @@ void __flush_tlb_all(void)  			     : : "r" (pstate));  } -static pte_t *get_from_cache(struct mm_struct *mm) -{ -	struct page *page; -	pte_t *ret; - -	spin_lock(&mm->page_table_lock); -	page = mm->context.pgtable_page; -	ret = NULL; -	if (page) { -		void *p = page_address(page); - -		mm->context.pgtable_page = NULL; - -		ret = (pte_t *) (p + (PAGE_SIZE / 2)); -	} -	spin_unlock(&mm->page_table_lock); - -	return ret; -} - -static struct page *__alloc_for_cache(struct mm_struct *mm) -{ -	struct page *page = alloc_page(GFP_KERNEL | __GFP_NOTRACK | -				       __GFP_REPEAT | __GFP_ZERO); - -	if (page) { -		spin_lock(&mm->page_table_lock); -		if (!mm->context.pgtable_page) { -			atomic_set(&page->_count, 2); -			mm->context.pgtable_page = page; -		} -		spin_unlock(&mm->page_table_lock); -	} -	return page; -} -  pte_t *pte_alloc_one_kernel(struct mm_struct *mm,  			    unsigned long address)  { -	struct page *page; -	pte_t *pte; - -	pte = get_from_cache(mm); -	if (pte) -		return pte; +	struct page *page = alloc_page(GFP_KERNEL | __GFP_NOTRACK | +				       __GFP_REPEAT | __GFP_ZERO); +	pte_t *pte = NULL; -	page = __alloc_for_cache(mm);  	if (page)  		pte = (pte_t *) page_address(page); @@ -2511,36 +2569,28 @@ pte_t *pte_alloc_one_kernel(struct mm_struct *mm,  pgtable_t pte_alloc_one(struct mm_struct *mm,  			unsigned long address)  { -	struct page *page; -	pte_t *pte; - -	pte = get_from_cache(mm); -	if (pte) -		return pte; - -	page = __alloc_for_cache(mm); -	if (page) { -		pgtable_page_ctor(page); -		pte = (pte_t *) page_address(page); +	struct page *page = alloc_page(GFP_KERNEL | __GFP_NOTRACK | +				       __GFP_REPEAT | __GFP_ZERO); +	if (!page) +		return NULL; +	if (!pgtable_page_ctor(page)) { +		free_hot_cold_page(page, 0); +		return NULL;  	} - -	return pte; +	return (pte_t *) page_address(page);  }  void pte_free_kernel(struct mm_struct *mm, pte_t *pte)  { -	struct page *page = virt_to_page(pte); -	if (put_page_testzero(page)) -		free_hot_cold_page(page, 0); +	free_page((unsigned long)pte);  }  static void __pte_free(pgtable_t pte)  {  	struct page *page = virt_to_page(pte); -	if (put_page_testzero(page)) { -		pgtable_page_dtor(page); -		free_hot_cold_page(page, 0); -	} + +	pgtable_page_dtor(page); +	__free_page(page);  }  void pte_free(struct mm_struct *mm, pgtable_t pte) @@ -2557,124 +2607,27 @@ void pgtable_free(void *table, bool is_page)  }  #ifdef CONFIG_TRANSPARENT_HUGEPAGE -static pmd_t pmd_set_protbits(pmd_t pmd, pgprot_t pgprot, bool for_modify) -{ -	if (pgprot_val(pgprot) & _PAGE_VALID) -		pmd_val(pmd) |= PMD_HUGE_PRESENT; -	if (tlb_type == hypervisor) { -		if (pgprot_val(pgprot) & _PAGE_WRITE_4V) -			pmd_val(pmd) |= PMD_HUGE_WRITE; -		if (pgprot_val(pgprot) & _PAGE_EXEC_4V) -			pmd_val(pmd) |= PMD_HUGE_EXEC; - -		if (!for_modify) { -			if (pgprot_val(pgprot) & _PAGE_ACCESSED_4V) -				pmd_val(pmd) |= PMD_HUGE_ACCESSED; -			if (pgprot_val(pgprot) & _PAGE_MODIFIED_4V) -				pmd_val(pmd) |= PMD_HUGE_DIRTY; -		} -	} else { -		if (pgprot_val(pgprot) & _PAGE_WRITE_4U) -			pmd_val(pmd) |= PMD_HUGE_WRITE; -		if (pgprot_val(pgprot) & _PAGE_EXEC_4U) -			pmd_val(pmd) |= PMD_HUGE_EXEC; - -		if (!for_modify) { -			if (pgprot_val(pgprot) & _PAGE_ACCESSED_4U) -				pmd_val(pmd) |= PMD_HUGE_ACCESSED; -			if (pgprot_val(pgprot) & _PAGE_MODIFIED_4U) -				pmd_val(pmd) |= PMD_HUGE_DIRTY; -		} -	} - -	return pmd; -} - -pmd_t pfn_pmd(unsigned long page_nr, pgprot_t pgprot) -{ -	pmd_t pmd; - -	pmd_val(pmd) = (page_nr << ((PAGE_SHIFT - PMD_PADDR_SHIFT))); -	pmd_val(pmd) |= PMD_ISHUGE; -	pmd = pmd_set_protbits(pmd, pgprot, false); -	return pmd; -} - -pmd_t pmd_modify(pmd_t pmd, pgprot_t newprot) -{ -	pmd_val(pmd) &= ~(PMD_HUGE_PRESENT | -			  PMD_HUGE_WRITE | -			  PMD_HUGE_EXEC); -	pmd = pmd_set_protbits(pmd, newprot, true); -	return pmd; -} - -pgprot_t pmd_pgprot(pmd_t entry) -{ -	unsigned long pte = 0; - -	if (pmd_val(entry) & PMD_HUGE_PRESENT) -		pte |= _PAGE_VALID; - -	if (tlb_type == hypervisor) { -		if (pmd_val(entry) & PMD_HUGE_PRESENT) -			pte |= _PAGE_PRESENT_4V; -		if (pmd_val(entry) & PMD_HUGE_EXEC) -			pte |= _PAGE_EXEC_4V; -		if (pmd_val(entry) & PMD_HUGE_WRITE) -			pte |= _PAGE_W_4V; -		if (pmd_val(entry) & PMD_HUGE_ACCESSED) -			pte |= _PAGE_ACCESSED_4V; -		if (pmd_val(entry) & PMD_HUGE_DIRTY) -			pte |= _PAGE_MODIFIED_4V; -		pte |= _PAGE_CP_4V|_PAGE_CV_4V; -	} else { -		if (pmd_val(entry) & PMD_HUGE_PRESENT) -			pte |= _PAGE_PRESENT_4U; -		if (pmd_val(entry) & PMD_HUGE_EXEC) -			pte |= _PAGE_EXEC_4U; -		if (pmd_val(entry) & PMD_HUGE_WRITE) -			pte |= _PAGE_W_4U; -		if (pmd_val(entry) & PMD_HUGE_ACCESSED) -			pte |= _PAGE_ACCESSED_4U; -		if (pmd_val(entry) & PMD_HUGE_DIRTY) -			pte |= _PAGE_MODIFIED_4U; -		pte |= _PAGE_CP_4U|_PAGE_CV_4U; -	} - -	return __pgprot(pte); -} -  void update_mmu_cache_pmd(struct vm_area_struct *vma, unsigned long addr,  			  pmd_t *pmd)  {  	unsigned long pte, flags;  	struct mm_struct *mm;  	pmd_t entry = *pmd; -	pgprot_t prot;  	if (!pmd_large(entry) || !pmd_young(entry))  		return; -	pte = (pmd_val(entry) & ~PMD_HUGE_PROTBITS); -	pte <<= PMD_PADDR_SHIFT; -	pte |= _PAGE_VALID; - -	prot = pmd_pgprot(entry); - -	if (tlb_type == hypervisor) -		pgprot_val(prot) |= _PAGE_SZHUGE_4V; -	else -		pgprot_val(prot) |= _PAGE_SZHUGE_4U; +	pte = pmd_val(entry); -	pte |= pgprot_val(prot); +	/* We are fabricating 8MB pages using 4MB real hw pages.  */ +	pte |= (addr & (1UL << REAL_HPAGE_SHIFT));  	mm = vma->vm_mm;  	spin_lock_irqsave(&mm->context.lock, flags);  	if (mm->context.tsb_block[MM_TSB_HUGE].tsb != NULL) -		__update_mmu_tsb_insert(mm, MM_TSB_HUGE, HPAGE_SHIFT, +		__update_mmu_tsb_insert(mm, MM_TSB_HUGE, REAL_HPAGE_SHIFT,  					addr, pte);  	spin_unlock_irqrestore(&mm->context.lock, flags); diff --git a/arch/sparc/mm/init_64.h b/arch/sparc/mm/init_64.h index 0661aa606de..0668b364f44 100644 --- a/arch/sparc/mm/init_64.h +++ b/arch/sparc/mm/init_64.h @@ -1,11 +1,13 @@  #ifndef _SPARC64_MM_INIT_H  #define _SPARC64_MM_INIT_H +#include <asm/page.h> +  /* Most of the symbols in this file are defined in init.c and   * marked non-static so that assembler code can get at them.   */ -#define MAX_PHYS_ADDRESS	(1UL << 41UL) +#define MAX_PHYS_ADDRESS	(1UL << MAX_PHYS_ADDRESS_BITS)  #define KPTE_BITMAP_CHUNK_SZ		(256UL * 1024UL * 1024UL)  #define KPTE_BITMAP_BYTES	\  	((MAX_PHYS_ADDRESS / KPTE_BITMAP_CHUNK_SZ) / 4) @@ -19,7 +21,7 @@ extern unsigned int sparc64_highest_unlocked_tlb_ent;  extern unsigned long sparc64_kern_pri_context;  extern unsigned long sparc64_kern_pri_nuc_bits;  extern unsigned long sparc64_kern_sec_context; -extern void mmu_info(struct seq_file *m); +void mmu_info(struct seq_file *m);  struct linux_prom_translation {  	unsigned long virt; @@ -34,7 +36,7 @@ extern unsigned int prom_trans_ents;  /* Exported for SMP bootup purposes. */  extern unsigned long kern_locked_tte_data; -extern void prom_world(int enter); +void prom_world(int enter);  #ifdef CONFIG_SPARSEMEM_VMEMMAP  #define VMEMMAP_CHUNK_SHIFT	22 diff --git a/arch/sparc/mm/io-unit.c b/arch/sparc/mm/io-unit.c index eb99862e965..f311bf21901 100644 --- a/arch/sparc/mm/io-unit.c +++ b/arch/sparc/mm/io-unit.c @@ -25,6 +25,8 @@  #include <asm/dma.h>  #include <asm/oplib.h> +#include "mm_32.h" +  /* #define IOUNIT_DEBUG */  #ifdef IOUNIT_DEBUG  #define IOD(x) printk(x) @@ -38,7 +40,8 @@  static void __init iounit_iommu_init(struct platform_device *op)  {  	struct iounit_struct *iounit; -	iopte_t *xpt, *xptend; +	iopte_t __iomem *xpt; +	iopte_t __iomem *xptend;  	iounit = kzalloc(sizeof(struct iounit_struct), GFP_ATOMIC);  	if (!iounit) { @@ -62,10 +65,10 @@ static void __init iounit_iommu_init(struct platform_device *op)  	op->dev.archdata.iommu = iounit;  	iounit->page_table = xpt;  	spin_lock_init(&iounit->lock); -	 -	for (xptend = iounit->page_table + (16 * PAGE_SIZE) / sizeof(iopte_t); -	     xpt < xptend;) -	     	iopte_val(*xpt++) = 0; + +	xptend = iounit->page_table + (16 * PAGE_SIZE) / sizeof(iopte_t); +	for (; xpt < xptend; xpt++) +		sbus_writel(0, xpt);  }  static int __init iounit_init(void) @@ -130,7 +133,7 @@ nexti:	scan = find_next_zero_bit(iounit->bmap, limit, scan);  	vaddr = IOUNIT_DMA_BASE + (scan << PAGE_SHIFT) + (vaddr & ~PAGE_MASK);  	for (k = 0; k < npages; k++, iopte = __iopte(iopte_val(iopte) + 0x100), scan++) {  		set_bit(scan, iounit->bmap); -		iounit->page_table[scan] = iopte; +		sbus_writel(iopte, &iounit->page_table[scan]);  	}  	IOD(("%08lx\n", vaddr));  	return vaddr; @@ -202,7 +205,7 @@ static int iounit_map_dma_area(struct device *dev, dma_addr_t *pba, unsigned lon  	struct iounit_struct *iounit = dev->archdata.iommu;  	unsigned long page, end;  	pgprot_t dvma_prot; -	iopte_t *iopte; +	iopte_t __iomem *iopte;  	*pba = addr; @@ -224,8 +227,8 @@ static int iounit_map_dma_area(struct device *dev, dma_addr_t *pba, unsigned lon  			i = ((addr - IOUNIT_DMA_BASE) >> PAGE_SHIFT); -			iopte = (iopte_t *)(iounit->page_table + i); -			*iopte = MKIOPTE(__pa(page)); +			iopte = iounit->page_table + i; +			sbus_writel(MKIOPTE(__pa(page)), iopte);  		}  		addr += PAGE_SIZE;  		va += PAGE_SIZE; diff --git a/arch/sparc/mm/iommu.c b/arch/sparc/mm/iommu.c index 28f96f27c76..491511d37e3 100644 --- a/arch/sparc/mm/iommu.c +++ b/arch/sparc/mm/iommu.c @@ -27,6 +27,8 @@  #include <asm/iommu.h>  #include <asm/dma.h> +#include "mm_32.h" +  /*   * This can be sized dynamically, but we will do this   * only when we have a guidance about actual I/O pressures. @@ -37,9 +39,6 @@  #define IOMMU_NPTES	(IOMMU_WINSIZE/PAGE_SIZE)	/* 64K PTEs, 256KB */  #define IOMMU_ORDER	6				/* 4096 * (1<<6) */ -/* srmmu.c */ -extern int viking_mxcc_present; -extern int flush_page_for_dma_global;  static int viking_flush;  /* viking.S */  extern void viking_flush_page(unsigned long page); @@ -59,6 +58,8 @@ static void __init sbus_iommu_init(struct platform_device *op)  	struct iommu_struct *iommu;  	unsigned int impl, vers;  	unsigned long *bitmap; +	unsigned long control; +	unsigned long base;  	unsigned long tmp;  	iommu = kmalloc(sizeof(struct iommu_struct), GFP_KERNEL); @@ -73,12 +74,14 @@ static void __init sbus_iommu_init(struct platform_device *op)  		prom_printf("Cannot map IOMMU registers\n");  		prom_halt();  	} -	impl = (iommu->regs->control & IOMMU_CTRL_IMPL) >> 28; -	vers = (iommu->regs->control & IOMMU_CTRL_VERS) >> 24; -	tmp = iommu->regs->control; -	tmp &= ~(IOMMU_CTRL_RNGE); -	tmp |= (IOMMU_RNGE_256MB | IOMMU_CTRL_ENAB); -	iommu->regs->control = tmp; + +	control = sbus_readl(&iommu->regs->control); +	impl = (control & IOMMU_CTRL_IMPL) >> 28; +	vers = (control & IOMMU_CTRL_VERS) >> 24; +	control &= ~(IOMMU_CTRL_RNGE); +	control |= (IOMMU_RNGE_256MB | IOMMU_CTRL_ENAB); +	sbus_writel(control, &iommu->regs->control); +  	iommu_invalidate(iommu->regs);  	iommu->start = IOMMU_START;  	iommu->end = 0xffffffff; @@ -100,7 +103,9 @@ static void __init sbus_iommu_init(struct platform_device *op)  	memset(iommu->page_table, 0, IOMMU_NPTES*sizeof(iopte_t));  	flush_cache_all();  	flush_tlb_all(); -	iommu->regs->base = __pa((unsigned long) iommu->page_table) >> 4; + +	base = __pa((unsigned long)iommu->page_table) >> 4; +	sbus_writel(base, &iommu->regs->base);  	iommu_invalidate(iommu->regs);  	bitmap = kmalloc(IOMMU_NPTES>>3, GFP_KERNEL); diff --git a/arch/sparc/mm/leon_mm.c b/arch/sparc/mm/leon_mm.c index 5bed085a2c1..3b17b6f7895 100644 --- a/arch/sparc/mm/leon_mm.c +++ b/arch/sparc/mm/leon_mm.c @@ -15,10 +15,10 @@  #include <asm/leon.h>  #include <asm/tlbflush.h> -#include "srmmu.h" +#include "mm_32.h"  int leon_flush_during_switch = 1; -int srmmu_swprobe_trace; +static int srmmu_swprobe_trace;  static inline unsigned long leon_get_ctable_ptr(void)  { diff --git a/arch/sparc/mm/mm_32.h b/arch/sparc/mm/mm_32.h new file mode 100644 index 00000000000..a6c27ca9a72 --- /dev/null +++ b/arch/sparc/mm/mm_32.h @@ -0,0 +1,24 @@ +/* fault_32.c - visible as they are called from assembler */ +asmlinkage int lookup_fault(unsigned long pc, unsigned long ret_pc, +                            unsigned long address); +asmlinkage void do_sparc_fault(struct pt_regs *regs, int text_fault, int write, +                               unsigned long address); + +void window_overflow_fault(void); +void window_underflow_fault(unsigned long sp); +void window_ret_fault(struct pt_regs *regs); + +/* srmmu.c */ +extern char *srmmu_name; +extern int viking_mxcc_present; +extern int flush_page_for_dma_global; + +extern void (*poke_srmmu)(void); + +void __init srmmu_paging_init(void); + +/* iommu.c */ +void ld_mmu_iommu(void); + +/* io-unit.c */ +void ld_mmu_iounit(void); diff --git a/arch/sparc/mm/srmmu.c b/arch/sparc/mm/srmmu.c index 5d721df48a7..be65f035d18 100644 --- a/arch/sparc/mm/srmmu.c +++ b/arch/sparc/mm/srmmu.c @@ -14,6 +14,7 @@  #include <linux/pagemap.h>  #include <linux/vmalloc.h>  #include <linux/kdebug.h> +#include <linux/export.h>  #include <linux/kernel.h>  #include <linux/init.h>  #include <linux/log2.h> @@ -48,7 +49,7 @@  #include <asm/mxcc.h>  #include <asm/ross.h> -#include "srmmu.h" +#include "mm_32.h"  enum mbus_module srmmu_modtype;  static unsigned int hwbug_bitmask; @@ -62,6 +63,7 @@ extern unsigned long last_valid_pfn;  static pgd_t *srmmu_swapper_pg_dir;  const struct sparc32_cachetlb_ops *sparc32_cachetlb_ops; +EXPORT_SYMBOL(sparc32_cachetlb_ops);  #ifdef CONFIG_SMP  const struct sparc32_cachetlb_ops *local_ops; @@ -98,7 +100,6 @@ static unsigned long srmmu_nocache_end;  #define SRMMU_NOCACHE_ALIGN_MAX (sizeof(ctxd_t)*SRMMU_MAX_CONTEXTS)  void *srmmu_nocache_pool; -void *srmmu_nocache_bitmap;  static struct bit_map srmmu_nocache_map;  static inline int srmmu_pmd_none(pmd_t pmd) @@ -171,7 +172,7 @@ static void *__srmmu_get_nocache(int size, int align)  		printk(KERN_ERR "srmmu: out of nocache %d: %d/%d\n",  		       size, (int) srmmu_nocache_size,  		       srmmu_nocache_map.used << SRMMU_NOCACHE_BITMAP_SHIFT); -		return 0; +		return NULL;  	}  	addr = SRMMU_NOCACHE_VADDR + (offset << SRMMU_NOCACHE_BITMAP_SHIFT); @@ -267,6 +268,7 @@ static void __init srmmu_nocache_calcsize(void)  static void __init srmmu_nocache_init(void)  { +	void *srmmu_nocache_bitmap;  	unsigned int bitmap_bits;  	pgd_t *pgd;  	pmd_t *pmd; @@ -345,7 +347,10 @@ pgtable_t pte_alloc_one(struct mm_struct *mm, unsigned long address)  	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); +	if (!pgtable_page_ctor(page)) { +		__free_page(page); +		return NULL; +	}  	return page;  } @@ -723,7 +728,7 @@ static inline unsigned long srmmu_probe(unsigned long vaddr)  				     "=r" (retval) :  				     "r" (vaddr | 0x400), "i" (ASI_M_FLUSH_PROBE));  	} else { -		retval = leon_swprobe(vaddr, 0); +		retval = leon_swprobe(vaddr, NULL);  	}  	return retval;  } @@ -860,8 +865,6 @@ static void __init map_kernel(void)  void (*poke_srmmu)(void) = NULL; -extern unsigned long bootmem_init(unsigned long *pages_avail); -  void __init srmmu_paging_init(void)  {  	int i; @@ -1766,9 +1769,6 @@ static struct sparc32_cachetlb_ops smp_cachetlb_ops = {  /* 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(); diff --git a/arch/sparc/mm/srmmu.h b/arch/sparc/mm/srmmu.h deleted file mode 100644 index 5703274ccf8..00000000000 --- a/arch/sparc/mm/srmmu.h +++ /dev/null @@ -1,4 +0,0 @@ -/* srmmu.c */ -extern char *srmmu_name; - -extern void (*poke_srmmu)(void); diff --git a/arch/sparc/mm/tlb.c b/arch/sparc/mm/tlb.c index 7a91f288c70..b89aba217e3 100644 --- a/arch/sparc/mm/tlb.c +++ b/arch/sparc/mm/tlb.c @@ -4,7 +4,6 @@   */  #include <linux/kernel.h> -#include <linux/init.h>  #include <linux/percpu.h>  #include <linux/mm.h>  #include <linux/swap.h> @@ -135,7 +134,7 @@ no_cache_flush:  #ifdef CONFIG_TRANSPARENT_HUGEPAGE  static void tlb_batch_pmd_scan(struct mm_struct *mm, unsigned long vaddr, -			       pmd_t pmd, bool exec) +			       pmd_t pmd)  {  	unsigned long end;  	pte_t *pte; @@ -143,8 +142,11 @@ static void tlb_batch_pmd_scan(struct mm_struct *mm, unsigned long vaddr,  	pte = pte_offset_map(&pmd, vaddr);  	end = vaddr + HPAGE_SIZE;  	while (vaddr < end) { -		if (pte_val(*pte) & _PAGE_VALID) +		if (pte_val(*pte) & _PAGE_VALID) { +			bool exec = pte_exec(*pte); +  			tlb_batch_add_one(mm, vaddr, exec); +		}  		pte++;  		vaddr += PAGE_SIZE;  	} @@ -161,8 +163,8 @@ void set_pmd_at(struct mm_struct *mm, unsigned long addr,  	if (mm == &init_mm)  		return; -	if ((pmd_val(pmd) ^ pmd_val(orig)) & PMD_ISHUGE) { -		if (pmd_val(pmd) & PMD_ISHUGE) +	if ((pmd_val(pmd) ^ pmd_val(orig)) & _PAGE_PMD_HUGE) { +		if (pmd_val(pmd) & _PAGE_PMD_HUGE)  			mm->context.huge_pte_count++;  		else  			mm->context.huge_pte_count--; @@ -178,16 +180,30 @@ void set_pmd_at(struct mm_struct *mm, unsigned long addr,  	}  	if (!pmd_none(orig)) { -		bool exec = ((pmd_val(orig) & PMD_HUGE_EXEC) != 0); -  		addr &= HPAGE_MASK; -		if (pmd_val(orig) & PMD_ISHUGE) +		if (pmd_trans_huge(orig)) { +			pte_t orig_pte = __pte(pmd_val(orig)); +			bool exec = pte_exec(orig_pte); +  			tlb_batch_add_one(mm, addr, exec); -		else -			tlb_batch_pmd_scan(mm, addr, orig, exec); +			tlb_batch_add_one(mm, addr + REAL_HPAGE_SIZE, exec); +		} else { +			tlb_batch_pmd_scan(mm, addr, orig); +		}  	}  } +void pmdp_invalidate(struct vm_area_struct *vma, unsigned long address, +		     pmd_t *pmdp) +{ +	pmd_t entry = *pmdp; + +	pmd_val(entry) &= ~_PAGE_VALID; + +	set_pmd_at(vma->vm_mm, address, pmdp, entry); +	flush_tlb_range(vma, address, address + HPAGE_PMD_SIZE); +} +  void pgtable_trans_huge_deposit(struct mm_struct *mm, pmd_t *pmdp,  				pgtable_t pgtable)  { @@ -196,11 +212,11 @@ void pgtable_trans_huge_deposit(struct mm_struct *mm, pmd_t *pmdp,  	assert_spin_locked(&mm->page_table_lock);  	/* FIFO */ -	if (!mm->pmd_huge_pte) +	if (!pmd_huge_pte(mm, pmdp))  		INIT_LIST_HEAD(lh);  	else -		list_add(lh, (struct list_head *) mm->pmd_huge_pte); -	mm->pmd_huge_pte = pgtable; +		list_add(lh, (struct list_head *) pmd_huge_pte(mm, pmdp)); +	pmd_huge_pte(mm, pmdp) = pgtable;  }  pgtable_t pgtable_trans_huge_withdraw(struct mm_struct *mm, pmd_t *pmdp) @@ -211,12 +227,12 @@ pgtable_t pgtable_trans_huge_withdraw(struct mm_struct *mm, pmd_t *pmdp)  	assert_spin_locked(&mm->page_table_lock);  	/* FIFO */ -	pgtable = mm->pmd_huge_pte; +	pgtable = pmd_huge_pte(mm, pmdp);  	lh = (struct list_head *) pgtable;  	if (list_empty(lh)) -		mm->pmd_huge_pte = NULL; +		pmd_huge_pte(mm, pmdp) = NULL;  	else { -		mm->pmd_huge_pte = (pgtable_t) lh->next; +		pmd_huge_pte(mm, pmdp) = (pgtable_t) lh->next;  		list_del(lh);  	}  	pte_val(pgtable[0]) = 0; diff --git a/arch/sparc/mm/tsb.c b/arch/sparc/mm/tsb.c index 2cc3bce5ee9..a06576683c3 100644 --- a/arch/sparc/mm/tsb.c +++ b/arch/sparc/mm/tsb.c @@ -9,6 +9,7 @@  #include <asm/page.h>  #include <asm/pgtable.h>  #include <asm/mmu_context.h> +#include <asm/setup.h>  #include <asm/tsb.h>  #include <asm/tlb.h>  #include <asm/oplib.h> @@ -87,7 +88,7 @@ void flush_tsb_user(struct tlb_batch *tb)  		nentries = mm->context.tsb_block[MM_TSB_HUGE].tsb_nentries;  		if (tlb_type == cheetah_plus || tlb_type == hypervisor)  			base = __pa(base); -		__flush_tsb_one(tb, HPAGE_SHIFT, base, nentries); +		__flush_tsb_one(tb, REAL_HPAGE_SHIFT, base, nentries);  	}  #endif  	spin_unlock_irqrestore(&mm->context.lock, flags); @@ -111,7 +112,7 @@ void flush_tsb_user_page(struct mm_struct *mm, unsigned long vaddr)  		nentries = mm->context.tsb_block[MM_TSB_HUGE].tsb_nentries;  		if (tlb_type == cheetah_plus || tlb_type == hypervisor)  			base = __pa(base); -		__flush_tsb_one_entry(base, vaddr, HPAGE_SHIFT, nentries); +		__flush_tsb_one_entry(base, vaddr, REAL_HPAGE_SHIFT, nentries);  	}  #endif  	spin_unlock_irqrestore(&mm->context.lock, flags); @@ -133,7 +134,19 @@ static void setup_tsb_params(struct mm_struct *mm, unsigned long tsb_idx, unsign  	mm->context.tsb_block[tsb_idx].tsb_nentries =  		tsb_bytes / sizeof(struct tsb); -	base = TSBMAP_BASE; +	switch (tsb_idx) { +	case MM_TSB_BASE: +		base = TSBMAP_8K_BASE; +		break; +#if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE) +	case MM_TSB_HUGE: +		base = TSBMAP_4M_BASE; +		break; +#endif +	default: +		BUG(); +	} +  	tte = pgprot_val(PAGE_KERNEL_LOCKED);  	tsb_paddr = __pa(mm->context.tsb_block[tsb_idx].tsb);  	BUG_ON(tsb_paddr & (tsb_bytes - 1UL)); @@ -273,7 +286,7 @@ void __init pgtable_cache_init(void)  		prom_halt();  	} -	for (i = 0; i < 8; i++) { +	for (i = 0; i < ARRAY_SIZE(tsb_cache_names); i++) {  		unsigned long size = 8192 << i;  		const char *name = tsb_cache_names[i]; @@ -472,8 +485,6 @@ int init_new_context(struct task_struct *tsk, struct mm_struct *mm)  	mm->context.huge_pte_count = 0;  #endif -	mm->context.pgtable_page = NULL; -  	/* copy_mm() copies over the parent's mm_struct before calling  	 * us, so we need to zero out the TSB pointer or else tsb_grow()  	 * will be confused and think there is an older TSB to free up. @@ -512,17 +523,10 @@ static void tsb_destroy_one(struct tsb_config *tp)  void destroy_context(struct mm_struct *mm)  {  	unsigned long flags, i; -	struct page *page;  	for (i = 0; i < MM_NUM_TSBS; i++)  		tsb_destroy_one(&mm->context.tsb_block[i]); -	page = mm->context.pgtable_page; -	if (page && put_page_testzero(page)) { -		pgtable_page_dtor(page); -		free_hot_cold_page(page, 0); -	} -  	spin_lock_irqsave(&ctx_alloc_lock, flags);  	if (CTX_VALID(mm->context)) { diff --git a/arch/sparc/mm/ultra.S b/arch/sparc/mm/ultra.S index 432aa0cb1b3..b4f4733abc6 100644 --- a/arch/sparc/mm/ultra.S +++ b/arch/sparc/mm/ultra.S @@ -153,10 +153,10 @@ __spitfire_flush_tlb_mm_slow:  	.globl		__flush_icache_page  __flush_icache_page:	/* %o0 = phys_page */  	srlx		%o0, PAGE_SHIFT, %o0 -	sethi		%uhi(PAGE_OFFSET), %g1 +	sethi		%hi(PAGE_OFFSET), %g1  	sllx		%o0, PAGE_SHIFT, %o0  	sethi		%hi(PAGE_SIZE), %g2 -	sllx		%g1, 32, %g1 +	ldx		[%g1 + %lo(PAGE_OFFSET)], %g1  	add		%o0, %g1, %o0  1:	subcc		%g2, 32, %g2  	bne,pt		%icc, 1b @@ -178,8 +178,8 @@ __flush_icache_page:	/* %o0 = phys_page */  	.align		64  	.globl		__flush_dcache_page  __flush_dcache_page:	/* %o0=kaddr, %o1=flush_icache */ -	sethi		%uhi(PAGE_OFFSET), %g1 -	sllx		%g1, 32, %g1 +	sethi		%hi(PAGE_OFFSET), %g1 +	ldx		[%g1 + %lo(PAGE_OFFSET)], %g1  	sub		%o0, %g1, %o0			! physical address  	srlx		%o0, 11, %o0			! make D-cache TAG  	sethi		%hi(1 << 14), %o2		! D-cache size @@ -287,8 +287,8 @@ __cheetah_flush_tlb_pending:	/* 27 insns */  #ifdef DCACHE_ALIASING_POSSIBLE  __cheetah_flush_dcache_page: /* 11 insns */ -	sethi		%uhi(PAGE_OFFSET), %g1 -	sllx		%g1, 32, %g1 +	sethi		%hi(PAGE_OFFSET), %g1 +	ldx		[%g1 + %lo(PAGE_OFFSET)], %g1  	sub		%o0, %g1, %o0  	sethi		%hi(PAGE_SIZE), %o4  1:	subcc		%o4, (1 << 5), %o4  | 
