diff options
Diffstat (limited to 'arch/sparc')
| -rw-r--r-- | arch/sparc/Kconfig | 15 | ||||
| -rw-r--r-- | arch/sparc/include/asm/mmu_64.h | 2 | ||||
| -rw-r--r-- | arch/sparc/include/asm/mmu_context_64.h | 32 | ||||
| -rw-r--r-- | arch/sparc/include/asm/pil.h | 1 | ||||
| -rw-r--r-- | arch/sparc/include/asm/processor_32.h | 3 | ||||
| -rw-r--r-- | arch/sparc/include/asm/processor_64.h | 2 | ||||
| -rw-r--r-- | arch/sparc/include/asm/vio.h | 1 | ||||
| -rw-r--r-- | arch/sparc/kernel/ds.c | 2 | ||||
| -rw-r--r-- | arch/sparc/kernel/irq_64.c | 17 | ||||
| -rw-r--r-- | arch/sparc/kernel/kernel.h | 1 | ||||
| -rw-r--r-- | arch/sparc/kernel/process_32.c | 8 | ||||
| -rw-r--r-- | arch/sparc/kernel/process_64.c | 19 | ||||
| -rw-r--r-- | arch/sparc/kernel/smp_64.c | 31 | ||||
| -rw-r--r-- | arch/sparc/kernel/sys_sparc_64.c | 4 | ||||
| -rw-r--r-- | arch/sparc/kernel/tsb.S | 11 | ||||
| -rw-r--r-- | arch/sparc/kernel/ttable_64.S | 2 | ||||
| -rw-r--r-- | arch/sparc/kernel/vio.c | 68 | ||||
| -rw-r--r-- | arch/sparc/lib/Makefile | 1 | ||||
| -rw-r--r-- | arch/sparc/lib/multi3.S | 35 | ||||
| -rw-r--r-- | arch/sparc/mm/hugetlbpage.c | 2 | ||||
| -rw-r--r-- | arch/sparc/mm/init_64.c | 89 | ||||
| -rw-r--r-- | arch/sparc/mm/tsb.c | 7 | ||||
| -rw-r--r-- | arch/sparc/mm/ultra.S | 5 | 
23 files changed, 204 insertions, 154 deletions
diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig index 58243b0d21c0..5639c9fe5b55 100644 --- a/arch/sparc/Kconfig +++ b/arch/sparc/Kconfig @@ -192,9 +192,9 @@ config NR_CPUS  	int "Maximum number of CPUs"  	depends on SMP  	range 2 32 if SPARC32 -	range 2 1024 if SPARC64 +	range 2 4096 if SPARC64  	default 32 if SPARC32 -	default 64 if SPARC64 +	default 4096 if SPARC64  source kernel/Kconfig.hz @@ -295,9 +295,13 @@ config NUMA  	depends on SPARC64 && SMP  config NODES_SHIFT -	int -	default "4" +	int "Maximum NUMA Nodes (as a power of 2)" +	range 4 5 if SPARC64 +	default "5"  	depends on NEED_MULTIPLE_NODES +	help +	  Specify the maximum number of NUMA Nodes available on the target +	  system.  Increases memory reserved to accommodate various tables.  # Some NUMA nodes have memory ranges that span  # other nodes.  Even though a pfn is valid and @@ -573,9 +577,6 @@ config SYSVIPC_COMPAT  	depends on COMPAT && SYSVIPC  	default y -config KEYS_COMPAT -	def_bool y if COMPAT && KEYS -  endmenu  source "net/Kconfig" diff --git a/arch/sparc/include/asm/mmu_64.h b/arch/sparc/include/asm/mmu_64.h index f7de0dbc38af..83b36a5371ff 100644 --- a/arch/sparc/include/asm/mmu_64.h +++ b/arch/sparc/include/asm/mmu_64.h @@ -52,7 +52,7 @@  #define CTX_NR_MASK		TAG_CONTEXT_BITS  #define CTX_HW_MASK		(CTX_NR_MASK | CTX_PGSZ_MASK) -#define CTX_FIRST_VERSION	((_AC(1,UL) << CTX_VERSION_SHIFT) + _AC(1,UL)) +#define CTX_FIRST_VERSION	BIT(CTX_VERSION_SHIFT)  #define CTX_VALID(__ctx)	\  	 (!(((__ctx.sparc64_ctx_val) ^ tlb_context_cache) & CTX_VERSION_MASK))  #define CTX_HWBITS(__ctx)	((__ctx.sparc64_ctx_val) & CTX_HW_MASK) diff --git a/arch/sparc/include/asm/mmu_context_64.h b/arch/sparc/include/asm/mmu_context_64.h index 22fede6eba11..2cddcda4f85f 100644 --- a/arch/sparc/include/asm/mmu_context_64.h +++ b/arch/sparc/include/asm/mmu_context_64.h @@ -19,13 +19,8 @@ extern spinlock_t ctx_alloc_lock;  extern unsigned long tlb_context_cache;  extern unsigned long mmu_context_bmap[]; +DECLARE_PER_CPU(struct mm_struct *, per_cpu_secondary_mm);  void get_new_mmu_context(struct mm_struct *mm); -#ifdef CONFIG_SMP -void smp_new_mmu_context_version(void); -#else -#define smp_new_mmu_context_version() do { } while (0) -#endif -  int init_new_context(struct task_struct *tsk, struct mm_struct *mm);  void destroy_context(struct mm_struct *mm); @@ -76,8 +71,9 @@ void __flush_tlb_mm(unsigned long, unsigned long);  static inline void switch_mm(struct mm_struct *old_mm, struct mm_struct *mm, struct task_struct *tsk)  {  	unsigned long ctx_valid, flags; -	int cpu; +	int cpu = smp_processor_id(); +	per_cpu(per_cpu_secondary_mm, cpu) = mm;  	if (unlikely(mm == &init_mm))  		return; @@ -123,7 +119,6 @@ static inline void switch_mm(struct mm_struct *old_mm, struct mm_struct *mm, str  	 * for the first time, we must flush that context out of the  	 * local TLB.  	 */ -	cpu = smp_processor_id();  	if (!ctx_valid || !cpumask_test_cpu(cpu, mm_cpumask(mm))) {  		cpumask_set_cpu(cpu, mm_cpumask(mm));  		__flush_tlb_mm(CTX_HWBITS(mm->context), @@ -133,26 +128,7 @@ static inline void switch_mm(struct mm_struct *old_mm, struct mm_struct *mm, str  }  #define deactivate_mm(tsk,mm)	do { } while (0) - -/* Activate a new MM instance for the current task. */ -static inline void activate_mm(struct mm_struct *active_mm, struct mm_struct *mm) -{ -	unsigned long flags; -	int cpu; - -	spin_lock_irqsave(&mm->context.lock, flags); -	if (!CTX_VALID(mm->context)) -		get_new_mmu_context(mm); -	cpu = smp_processor_id(); -	if (!cpumask_test_cpu(cpu, mm_cpumask(mm))) -		cpumask_set_cpu(cpu, mm_cpumask(mm)); - -	load_secondary_context(mm); -	__flush_tlb_mm(CTX_HWBITS(mm->context), SECONDARY_CONTEXT); -	tsb_context_switch(mm); -	spin_unlock_irqrestore(&mm->context.lock, flags); -} - +#define activate_mm(active_mm, mm) switch_mm(active_mm, mm, NULL)  #endif /* !(__ASSEMBLY__) */  #endif /* !(__SPARC64_MMU_CONTEXT_H) */ diff --git a/arch/sparc/include/asm/pil.h b/arch/sparc/include/asm/pil.h index 266937030546..522b43db2ed3 100644 --- a/arch/sparc/include/asm/pil.h +++ b/arch/sparc/include/asm/pil.h @@ -20,7 +20,6 @@  #define PIL_SMP_CALL_FUNC	1  #define PIL_SMP_RECEIVE_SIGNAL	2  #define PIL_SMP_CAPTURE		3 -#define PIL_SMP_CTX_NEW_VERSION	4  #define PIL_DEVICE_IRQ		5  #define PIL_SMP_CALL_FUNC_SNGL	6  #define PIL_DEFERRED_PCR_WORK	7 diff --git a/arch/sparc/include/asm/processor_32.h b/arch/sparc/include/asm/processor_32.h index dd27159819eb..b395e5620c0b 100644 --- a/arch/sparc/include/asm/processor_32.h +++ b/arch/sparc/include/asm/processor_32.h @@ -67,9 +67,6 @@ struct thread_struct {  	.current_ds = KERNEL_DS, \  } -/* Return saved PC of a blocked thread. */ -unsigned long thread_saved_pc(struct task_struct *t); -  /* Do necessary setup to start up a newly executed thread. */  static inline void start_thread(struct pt_regs * regs, unsigned long pc,  				    unsigned long sp) diff --git a/arch/sparc/include/asm/processor_64.h b/arch/sparc/include/asm/processor_64.h index b58ee9018433..f04dc5a43062 100644 --- a/arch/sparc/include/asm/processor_64.h +++ b/arch/sparc/include/asm/processor_64.h @@ -89,9 +89,7 @@ struct thread_struct {  #include <linux/types.h>  #include <asm/fpumacro.h> -/* Return saved PC of a blocked thread. */  struct task_struct; -unsigned long thread_saved_pc(struct task_struct *);  /* On Uniprocessor, even in RMO processes see TSO semantics */  #ifdef CONFIG_SMP diff --git a/arch/sparc/include/asm/vio.h b/arch/sparc/include/asm/vio.h index 8174f6cdbbbb..9dca7a892978 100644 --- a/arch/sparc/include/asm/vio.h +++ b/arch/sparc/include/asm/vio.h @@ -327,6 +327,7 @@ struct vio_dev {  	int			compat_len;  	u64			dev_no; +	u64			id;  	unsigned long		channel_id; diff --git a/arch/sparc/kernel/ds.c b/arch/sparc/kernel/ds.c index b542cc7c8d94..f87265afb175 100644 --- a/arch/sparc/kernel/ds.c +++ b/arch/sparc/kernel/ds.c @@ -909,7 +909,7 @@ static int register_services(struct ds_info *dp)  		pbuf.req.handle = cp->handle;  		pbuf.req.major = 1;  		pbuf.req.minor = 0; -		strcpy(pbuf.req.svc_id, cp->service_id); +		strcpy(pbuf.id_buf, cp->service_id);  		err = __ds_send(lp, &pbuf, msg_len);  		if (err > 0) diff --git a/arch/sparc/kernel/irq_64.c b/arch/sparc/kernel/irq_64.c index 4d0248aa0928..99dd133a029f 100644 --- a/arch/sparc/kernel/irq_64.c +++ b/arch/sparc/kernel/irq_64.c @@ -1034,17 +1034,26 @@ static void __init init_cpu_send_mondo_info(struct trap_per_cpu *tb)  {  #ifdef CONFIG_SMP  	unsigned long page; +	void *mondo, *p; -	BUILD_BUG_ON((NR_CPUS * sizeof(u16)) > (PAGE_SIZE - 64)); +	BUILD_BUG_ON((NR_CPUS * sizeof(u16)) > PAGE_SIZE); + +	/* Make sure mondo block is 64byte aligned */ +	p = kzalloc(127, GFP_KERNEL); +	if (!p) { +		prom_printf("SUN4V: Error, cannot allocate mondo block.\n"); +		prom_halt(); +	} +	mondo = (void *)(((unsigned long)p + 63) & ~0x3f); +	tb->cpu_mondo_block_pa = __pa(mondo);  	page = get_zeroed_page(GFP_KERNEL);  	if (!page) { -		prom_printf("SUN4V: Error, cannot allocate cpu mondo page.\n"); +		prom_printf("SUN4V: Error, cannot allocate cpu list page.\n");  		prom_halt();  	} -	tb->cpu_mondo_block_pa = __pa(page); -	tb->cpu_list_pa = __pa(page + 64); +	tb->cpu_list_pa = __pa(page);  #endif  } diff --git a/arch/sparc/kernel/kernel.h b/arch/sparc/kernel/kernel.h index c9804551262c..6ae1e77be0bf 100644 --- a/arch/sparc/kernel/kernel.h +++ b/arch/sparc/kernel/kernel.h @@ -37,7 +37,6 @@ void handle_stdfmna(struct pt_regs *regs, unsigned long sfar, unsigned long sfsr  /* smp_64.c */  void __irq_entry smp_call_function_client(int irq, struct pt_regs *regs);  void __irq_entry smp_call_function_single_client(int irq, struct pt_regs *regs); -void __irq_entry smp_new_mmu_context_version_client(int irq, struct pt_regs *regs);  void __irq_entry smp_penguin_jailcell(int irq, struct pt_regs *regs);  void __irq_entry smp_receive_signal_client(int irq, struct pt_regs *regs); diff --git a/arch/sparc/kernel/process_32.c b/arch/sparc/kernel/process_32.c index b6dac8e980f0..9245f93398c7 100644 --- a/arch/sparc/kernel/process_32.c +++ b/arch/sparc/kernel/process_32.c @@ -177,14 +177,6 @@ void show_stack(struct task_struct *tsk, unsigned long *_ksp)  }  /* - * Note: sparc64 has a pretty intricated thread_saved_pc, check it out. - */ -unsigned long thread_saved_pc(struct task_struct *tsk) -{ -	return task_thread_info(tsk)->kpc; -} - -/*   * Free current thread data structures etc..   */  void exit_thread(struct task_struct *tsk) diff --git a/arch/sparc/kernel/process_64.c b/arch/sparc/kernel/process_64.c index 1badc493e62e..b96104da5bd6 100644 --- a/arch/sparc/kernel/process_64.c +++ b/arch/sparc/kernel/process_64.c @@ -400,25 +400,6 @@ core_initcall(sparc_sysrq_init);  #endif -unsigned long thread_saved_pc(struct task_struct *tsk) -{ -	struct thread_info *ti = task_thread_info(tsk); -	unsigned long ret = 0xdeadbeefUL; -	 -	if (ti && ti->ksp) { -		unsigned long *sp; -		sp = (unsigned long *)(ti->ksp + STACK_BIAS); -		if (((unsigned long)sp & (sizeof(long) - 1)) == 0UL && -		    sp[14]) { -			unsigned long *fp; -			fp = (unsigned long *)(sp[14] + STACK_BIAS); -			if (((unsigned long)fp & (sizeof(long) - 1)) == 0UL) -				ret = fp[15]; -		} -	} -	return ret; -} -  /* Free current thread data structures etc.. */  void exit_thread(struct task_struct *tsk)  { diff --git a/arch/sparc/kernel/smp_64.c b/arch/sparc/kernel/smp_64.c index b3bc0ac757cc..fdf31040a7dc 100644 --- a/arch/sparc/kernel/smp_64.c +++ b/arch/sparc/kernel/smp_64.c @@ -964,37 +964,6 @@ void flush_dcache_page_all(struct mm_struct *mm, struct page *page)  	preempt_enable();  } -void __irq_entry smp_new_mmu_context_version_client(int irq, struct pt_regs *regs) -{ -	struct mm_struct *mm; -	unsigned long flags; - -	clear_softint(1 << irq); - -	/* See if we need to allocate a new TLB context because -	 * the version of the one we are using is now out of date. -	 */ -	mm = current->active_mm; -	if (unlikely(!mm || (mm == &init_mm))) -		return; - -	spin_lock_irqsave(&mm->context.lock, flags); - -	if (unlikely(!CTX_VALID(mm->context))) -		get_new_mmu_context(mm); - -	spin_unlock_irqrestore(&mm->context.lock, flags); - -	load_secondary_context(mm); -	__flush_tlb_mm(CTX_HWBITS(mm->context), -		       SECONDARY_CONTEXT); -} - -void smp_new_mmu_context_version(void) -{ -	smp_cross_call(&xcall_new_mmu_context_version, 0, 0, 0); -} -  #ifdef CONFIG_KGDB  void kgdb_roundup_cpus(unsigned long flags)  { diff --git a/arch/sparc/kernel/sys_sparc_64.c b/arch/sparc/kernel/sys_sparc_64.c index ef4520efc813..043544d0cda3 100644 --- a/arch/sparc/kernel/sys_sparc_64.c +++ b/arch/sparc/kernel/sys_sparc_64.c @@ -120,7 +120,7 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsi  		vma = find_vma(mm, addr);  		if (task_size - len >= addr && -		    (!vma || addr + len <= vma->vm_start)) +		    (!vma || addr + len <= vm_start_gap(vma)))  			return addr;  	} @@ -183,7 +183,7 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0,  		vma = find_vma(mm, addr);  		if (task_size - len >= addr && -		    (!vma || addr + len <= vma->vm_start)) +		    (!vma || addr + len <= vm_start_gap(vma)))  			return addr;  	} diff --git a/arch/sparc/kernel/tsb.S b/arch/sparc/kernel/tsb.S index 10689cfd0ad4..07c0df924960 100644 --- a/arch/sparc/kernel/tsb.S +++ b/arch/sparc/kernel/tsb.S @@ -455,13 +455,16 @@ __tsb_context_switch:  	.type	copy_tsb,#function  copy_tsb:		/* %o0=old_tsb_base, %o1=old_tsb_size  			 * %o2=new_tsb_base, %o3=new_tsb_size +			 * %o4=page_size_shift  			 */  	sethi		%uhi(TSB_PASS_BITS), %g7  	srlx		%o3, 4, %o3 -	add		%o0, %o1, %g1	/* end of old tsb */ +	add		%o0, %o1, %o1	/* end of old tsb */  	sllx		%g7, 32, %g7  	sub		%o3, 1, %o3	/* %o3 == new tsb hash mask */ +	mov		%o4, %g1	/* page_size_shift */ +  661:	prefetcha	[%o0] ASI_N, #one_read  	.section	.tsb_phys_patch, "ax"  	.word		661b @@ -486,9 +489,9 @@ copy_tsb:		/* %o0=old_tsb_base, %o1=old_tsb_size  	/* This can definitely be computed faster... */  	srlx		%o0, 4, %o5	/* Build index */  	and		%o5, 511, %o5	/* Mask index */ -	sllx		%o5, PAGE_SHIFT, %o5 /* Put into vaddr position */ +	sllx		%o5, %g1, %o5	/* Put into vaddr position */  	or		%o4, %o5, %o4	/* Full VADDR. */ -	srlx		%o4, PAGE_SHIFT, %o4 /* Shift down to create index */ +	srlx		%o4, %g1, %o4	/* Shift down to create index */  	and		%o4, %o3, %o4	/* Mask with new_tsb_nents-1 */  	sllx		%o4, 4, %o4	/* Shift back up into tsb ent offset */  	TSB_STORE(%o2 + %o4, %g2)	/* Store TAG */ @@ -496,7 +499,7 @@ copy_tsb:		/* %o0=old_tsb_base, %o1=old_tsb_size  	TSB_STORE(%o2 + %o4, %g3)	/* Store TTE */  80:	add		%o0, 16, %o0 -	cmp		%o0, %g1 +	cmp		%o0, %o1  	bne,pt		%xcc, 90b  	 nop diff --git a/arch/sparc/kernel/ttable_64.S b/arch/sparc/kernel/ttable_64.S index 7bd8f6556352..efe93ab4a9c0 100644 --- a/arch/sparc/kernel/ttable_64.S +++ b/arch/sparc/kernel/ttable_64.S @@ -50,7 +50,7 @@ tl0_resv03e:	BTRAP(0x3e) BTRAP(0x3f) BTRAP(0x40)  tl0_irq1:	TRAP_IRQ(smp_call_function_client, 1)  tl0_irq2:	TRAP_IRQ(smp_receive_signal_client, 2)  tl0_irq3:	TRAP_IRQ(smp_penguin_jailcell, 3) -tl0_irq4:	TRAP_IRQ(smp_new_mmu_context_version_client, 4) +tl0_irq4:       BTRAP(0x44)  #else  tl0_irq1:	BTRAP(0x41)  tl0_irq2:	BTRAP(0x42) diff --git a/arch/sparc/kernel/vio.c b/arch/sparc/kernel/vio.c index f6bb857254fc..075d38980dee 100644 --- a/arch/sparc/kernel/vio.c +++ b/arch/sparc/kernel/vio.c @@ -302,13 +302,16 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp,  	if (!id) {  		dev_set_name(&vdev->dev, "%s", bus_id_name);  		vdev->dev_no = ~(u64)0; +		vdev->id = ~(u64)0;  	} else if (!cfg_handle) {  		dev_set_name(&vdev->dev, "%s-%llu", bus_id_name, *id);  		vdev->dev_no = *id; +		vdev->id = ~(u64)0;  	} else {  		dev_set_name(&vdev->dev, "%s-%llu-%llu", bus_id_name,  			     *cfg_handle, *id);  		vdev->dev_no = *cfg_handle; +		vdev->id = *id;  	}  	vdev->dev.parent = parent; @@ -351,27 +354,84 @@ static void vio_add(struct mdesc_handle *hp, u64 node)  	(void) vio_create_one(hp, node, &root_vdev->dev);  } +struct vio_md_node_query { +	const char *type; +	u64 dev_no; +	u64 id; +}; +  static int vio_md_node_match(struct device *dev, void *arg)  { +	struct vio_md_node_query *query = (struct vio_md_node_query *) arg;  	struct vio_dev *vdev = to_vio_dev(dev); -	if (vdev->mp == (u64) arg) -		return 1; +	if (vdev->dev_no != query->dev_no) +		return 0; +	if (vdev->id != query->id) +		return 0; +	if (strcmp(vdev->type, query->type)) +		return 0; -	return 0; +	return 1;  }  static void vio_remove(struct mdesc_handle *hp, u64 node)  { +	const char *type; +	const u64 *id, *cfg_handle; +	u64 a; +	struct vio_md_node_query query;  	struct device *dev; -	dev = device_find_child(&root_vdev->dev, (void *) node, +	type = mdesc_get_property(hp, node, "device-type", NULL); +	if (!type) { +		type = mdesc_get_property(hp, node, "name", NULL); +		if (!type) +			type = mdesc_node_name(hp, node); +	} + +	query.type = type; + +	id = mdesc_get_property(hp, node, "id", NULL); +	cfg_handle = NULL; +	mdesc_for_each_arc(a, hp, node, MDESC_ARC_TYPE_BACK) { +		u64 target; + +		target = mdesc_arc_target(hp, a); +		cfg_handle = mdesc_get_property(hp, target, +						"cfg-handle", NULL); +		if (cfg_handle) +			break; +	} + +	if (!id) { +		query.dev_no = ~(u64)0; +		query.id = ~(u64)0; +	} else if (!cfg_handle) { +		query.dev_no = *id; +		query.id = ~(u64)0; +	} else { +		query.dev_no = *cfg_handle; +		query.id = *id; +	} + +	dev = device_find_child(&root_vdev->dev, &query,  				vio_md_node_match);  	if (dev) {  		printk(KERN_INFO "VIO: Removing device %s\n", dev_name(dev));  		device_unregister(dev);  		put_device(dev); +	} else { +		if (!id) +			printk(KERN_ERR "VIO: Removed unknown %s node.\n", +			       type); +		else if (!cfg_handle) +			printk(KERN_ERR "VIO: Removed unknown %s node %llu.\n", +			       type, *id); +		else +			printk(KERN_ERR "VIO: Removed unknown %s node %llu-%llu.\n", +			       type, *cfg_handle, *id);  	}  } diff --git a/arch/sparc/lib/Makefile b/arch/sparc/lib/Makefile index 69912d2f8b54..07c03e72d812 100644 --- a/arch/sparc/lib/Makefile +++ b/arch/sparc/lib/Makefile @@ -15,6 +15,7 @@ lib-$(CONFIG_SPARC32) += copy_user.o locks.o  lib-$(CONFIG_SPARC64) += atomic_64.o  lib-$(CONFIG_SPARC32) += lshrdi3.o ashldi3.o  lib-$(CONFIG_SPARC32) += muldi3.o bitext.o cmpdi2.o +lib-$(CONFIG_SPARC64) += multi3.o  lib-$(CONFIG_SPARC64) += copy_page.o clear_page.o bzero.o  lib-$(CONFIG_SPARC64) += csum_copy.o csum_copy_from_user.o csum_copy_to_user.o diff --git a/arch/sparc/lib/multi3.S b/arch/sparc/lib/multi3.S new file mode 100644 index 000000000000..d6b6c97fe3c7 --- /dev/null +++ b/arch/sparc/lib/multi3.S @@ -0,0 +1,35 @@ +#include <linux/linkage.h> +#include <asm/export.h> + +	.text +	.align	4 +ENTRY(__multi3) /* %o0 = u, %o1 = v */ +	mov	%o1, %g1 +	srl	%o3, 0, %g4 +	mulx	%g4, %g1, %o1 +	srlx	%g1, 0x20, %g3 +	mulx	%g3, %g4, %g5 +	sllx	%g5, 0x20, %o5 +	srl	%g1, 0, %g4 +	sub	%o1, %o5, %o5 +	srlx	%o5, 0x20, %o5 +	addcc	%g5, %o5, %g5 +	srlx	%o3, 0x20, %o5 +	mulx	%g4, %o5, %g4 +	mulx	%g3, %o5, %o5 +	sethi	%hi(0x80000000), %g3 +	addcc	%g5, %g4, %g5 +	srlx	%g5, 0x20, %g5 +	add	%g3, %g3, %g3 +	movcc	%xcc, %g0, %g3 +	addcc	%o5, %g5, %o5 +	sllx	%g4, 0x20, %g4 +	add	%o1, %g4, %o1 +	add	%o5, %g3, %g2 +	mulx	%g1, %o2, %g1 +	add	%g1, %g2, %g1 +	mulx	%o0, %o3, %o0 +	retl +	 add	%g1, %o0, %o0 +ENDPROC(__multi3) +EXPORT_SYMBOL(__multi3) diff --git a/arch/sparc/mm/hugetlbpage.c b/arch/sparc/mm/hugetlbpage.c index 7c29d38e6b99..88855e383b34 100644 --- a/arch/sparc/mm/hugetlbpage.c +++ b/arch/sparc/mm/hugetlbpage.c @@ -120,7 +120,7 @@ hugetlb_get_unmapped_area(struct file *file, unsigned long addr,  		addr = ALIGN(addr, huge_page_size(h));  		vma = find_vma(mm, addr);  		if (task_size - len >= addr && -		    (!vma || addr + len <= vma->vm_start)) +		    (!vma || addr + len <= vm_start_gap(vma)))  			return addr;  	}  	if (mm->get_unmapped_area == arch_get_unmapped_area) diff --git a/arch/sparc/mm/init_64.c b/arch/sparc/mm/init_64.c index 0cda653ae007..3c40ebd50f92 100644 --- a/arch/sparc/mm/init_64.c +++ b/arch/sparc/mm/init_64.c @@ -358,7 +358,8 @@ static int __init setup_hugepagesz(char *string)  	}  	if ((hv_pgsz_mask & cpu_pgsz_mask) == 0U) { -		pr_warn("hugepagesz=%llu not supported by MMU.\n", +		hugetlb_bad_size(); +		pr_err("hugepagesz=%llu not supported by MMU.\n",  			hugepage_size);  		goto out;  	} @@ -706,10 +707,58 @@ EXPORT_SYMBOL(__flush_dcache_range);  /* get_new_mmu_context() uses "cache + 1".  */  DEFINE_SPINLOCK(ctx_alloc_lock); -unsigned long tlb_context_cache = CTX_FIRST_VERSION - 1; +unsigned long tlb_context_cache = CTX_FIRST_VERSION;  #define MAX_CTX_NR	(1UL << CTX_NR_BITS)  #define CTX_BMAP_SLOTS	BITS_TO_LONGS(MAX_CTX_NR)  DECLARE_BITMAP(mmu_context_bmap, MAX_CTX_NR); +DEFINE_PER_CPU(struct mm_struct *, per_cpu_secondary_mm) = {0}; + +static void mmu_context_wrap(void) +{ +	unsigned long old_ver = tlb_context_cache & CTX_VERSION_MASK; +	unsigned long new_ver, new_ctx, old_ctx; +	struct mm_struct *mm; +	int cpu; + +	bitmap_zero(mmu_context_bmap, 1 << CTX_NR_BITS); + +	/* Reserve kernel context */ +	set_bit(0, mmu_context_bmap); + +	new_ver = (tlb_context_cache & CTX_VERSION_MASK) + CTX_FIRST_VERSION; +	if (unlikely(new_ver == 0)) +		new_ver = CTX_FIRST_VERSION; +	tlb_context_cache = new_ver; + +	/* +	 * Make sure that any new mm that are added into per_cpu_secondary_mm, +	 * are going to go through get_new_mmu_context() path. +	 */ +	mb(); + +	/* +	 * Updated versions to current on those CPUs that had valid secondary +	 * contexts +	 */ +	for_each_online_cpu(cpu) { +		/* +		 * If a new mm is stored after we took this mm from the array, +		 * it will go into get_new_mmu_context() path, because we +		 * already bumped the version in tlb_context_cache. +		 */ +		mm = per_cpu(per_cpu_secondary_mm, cpu); + +		if (unlikely(!mm || mm == &init_mm)) +			continue; + +		old_ctx = mm->context.sparc64_ctx_val; +		if (likely((old_ctx & CTX_VERSION_MASK) == old_ver)) { +			new_ctx = (old_ctx & ~CTX_VERSION_MASK) | new_ver; +			set_bit(new_ctx & CTX_NR_MASK, mmu_context_bmap); +			mm->context.sparc64_ctx_val = new_ctx; +		} +	} +}  /* Caller does TLB context flushing on local CPU if necessary.   * The caller also ensures that CTX_VALID(mm->context) is false. @@ -725,48 +774,30 @@ void get_new_mmu_context(struct mm_struct *mm)  {  	unsigned long ctx, new_ctx;  	unsigned long orig_pgsz_bits; -	int new_version;  	spin_lock(&ctx_alloc_lock); +retry: +	/* wrap might have happened, test again if our context became valid */ +	if (unlikely(CTX_VALID(mm->context))) +		goto out;  	orig_pgsz_bits = (mm->context.sparc64_ctx_val & CTX_PGSZ_MASK);  	ctx = (tlb_context_cache + 1) & CTX_NR_MASK;  	new_ctx = find_next_zero_bit(mmu_context_bmap, 1 << CTX_NR_BITS, ctx); -	new_version = 0;  	if (new_ctx >= (1 << CTX_NR_BITS)) {  		new_ctx = find_next_zero_bit(mmu_context_bmap, ctx, 1);  		if (new_ctx >= ctx) { -			int i; -			new_ctx = (tlb_context_cache & CTX_VERSION_MASK) + -				CTX_FIRST_VERSION; -			if (new_ctx == 1) -				new_ctx = CTX_FIRST_VERSION; - -			/* Don't call memset, for 16 entries that's just -			 * plain silly... -			 */ -			mmu_context_bmap[0] = 3; -			mmu_context_bmap[1] = 0; -			mmu_context_bmap[2] = 0; -			mmu_context_bmap[3] = 0; -			for (i = 4; i < CTX_BMAP_SLOTS; i += 4) { -				mmu_context_bmap[i + 0] = 0; -				mmu_context_bmap[i + 1] = 0; -				mmu_context_bmap[i + 2] = 0; -				mmu_context_bmap[i + 3] = 0; -			} -			new_version = 1; -			goto out; +			mmu_context_wrap(); +			goto retry;  		}  	} +	if (mm->context.sparc64_ctx_val) +		cpumask_clear(mm_cpumask(mm));  	mmu_context_bmap[new_ctx>>6] |= (1UL << (new_ctx & 63));  	new_ctx |= (tlb_context_cache & CTX_VERSION_MASK); -out:  	tlb_context_cache = new_ctx;  	mm->context.sparc64_ctx_val = new_ctx | orig_pgsz_bits; +out:  	spin_unlock(&ctx_alloc_lock); - -	if (unlikely(new_version)) -		smp_new_mmu_context_version();  }  static int numa_enabled = 1; diff --git a/arch/sparc/mm/tsb.c b/arch/sparc/mm/tsb.c index bedf08b22a47..0d4b998c7d7b 100644 --- a/arch/sparc/mm/tsb.c +++ b/arch/sparc/mm/tsb.c @@ -496,7 +496,8 @@ retry_tsb_alloc:  		extern void copy_tsb(unsigned long old_tsb_base,  				     unsigned long old_tsb_size,  				     unsigned long new_tsb_base, -				     unsigned long new_tsb_size); +				     unsigned long new_tsb_size, +				     unsigned long page_size_shift);  		unsigned long old_tsb_base = (unsigned long) old_tsb;  		unsigned long new_tsb_base = (unsigned long) new_tsb; @@ -504,7 +505,9 @@ retry_tsb_alloc:  			old_tsb_base = __pa(old_tsb_base);  			new_tsb_base = __pa(new_tsb_base);  		} -		copy_tsb(old_tsb_base, old_size, new_tsb_base, new_size); +		copy_tsb(old_tsb_base, old_size, new_tsb_base, new_size, +			tsb_index == MM_TSB_BASE ? +			PAGE_SHIFT : REAL_HPAGE_SHIFT);  	}  	mm->context.tsb_block[tsb_index].tsb = new_tsb; diff --git a/arch/sparc/mm/ultra.S b/arch/sparc/mm/ultra.S index 5d2fd6cd3189..fcf4d27a38fb 100644 --- a/arch/sparc/mm/ultra.S +++ b/arch/sparc/mm/ultra.S @@ -971,11 +971,6 @@ xcall_capture:  	wr		%g0, (1 << PIL_SMP_CAPTURE), %set_softint  	retry -	.globl		xcall_new_mmu_context_version -xcall_new_mmu_context_version: -	wr		%g0, (1 << PIL_SMP_CTX_NEW_VERSION), %set_softint -	retry -  #ifdef CONFIG_KGDB  	.globl		xcall_kgdb_capture  xcall_kgdb_capture:  |