diff options
Diffstat (limited to 'arch/sparc')
| -rw-r--r-- | arch/sparc/Kconfig | 8 | ||||
| -rw-r--r-- | arch/sparc/include/asm/Kbuild | 5 | ||||
| -rw-r--r-- | arch/sparc/include/asm/cputime.h | 6 | ||||
| -rw-r--r-- | arch/sparc/include/asm/emergency-restart.h | 6 | ||||
| -rw-r--r-- | arch/sparc/include/asm/mutex.h | 9 | ||||
| -rw-r--r-- | arch/sparc/include/asm/pgtable_64.h | 1 | ||||
| -rw-r--r-- | arch/sparc/include/asm/serial.h | 6 | ||||
| -rw-r--r-- | arch/sparc/include/asm/smp_32.h | 5 | ||||
| -rw-r--r-- | arch/sparc/include/asm/spitfire.h | 1 | ||||
| -rw-r--r-- | arch/sparc/include/asm/switch_to_64.h | 3 | ||||
| -rw-r--r-- | arch/sparc/include/asm/tlbflush_64.h | 37 | ||||
| -rw-r--r-- | arch/sparc/include/uapi/asm/Kbuild | 1 | ||||
| -rw-r--r-- | arch/sparc/include/uapi/asm/types.h | 17 | ||||
| -rw-r--r-- | arch/sparc/kernel/cpu.c | 6 | ||||
| -rw-r--r-- | arch/sparc/kernel/head_64.S | 25 | ||||
| -rw-r--r-- | arch/sparc/kernel/leon_pci_grpci2.c | 41 | ||||
| -rw-r--r-- | arch/sparc/kernel/smp_64.c | 41 | ||||
| -rw-r--r-- | arch/sparc/lib/bitext.c | 6 | ||||
| -rw-r--r-- | arch/sparc/mm/iommu.c | 2 | ||||
| -rw-r--r-- | arch/sparc/mm/srmmu.c | 4 | ||||
| -rw-r--r-- | arch/sparc/mm/tlb.c | 38 | ||||
| -rw-r--r-- | arch/sparc/mm/tsb.c | 57 | ||||
| -rw-r--r-- | arch/sparc/mm/ultra.S | 119 | 
23 files changed, 308 insertions, 136 deletions
diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig index 289127d5241..3d361f23630 100644 --- a/arch/sparc/Kconfig +++ b/arch/sparc/Kconfig @@ -84,12 +84,6 @@ config ARCH_DEFCONFIG  	default "arch/sparc/configs/sparc32_defconfig" if SPARC32  	default "arch/sparc/configs/sparc64_defconfig" if SPARC64 -# CONFIG_BITS can be used at source level to get 32/64 bits -config BITS -	int -	default 32 if SPARC32 -	default 64 if SPARC64 -  config IOMMU_HELPER  	bool  	default y if SPARC64 @@ -197,7 +191,7 @@ config RWSEM_XCHGADD_ALGORITHM  config GENERIC_HWEIGHT  	bool -	default y if !ULTRA_HAS_POPULATION_COUNT +	default y  config GENERIC_CALIBRATE_DELAY  	bool diff --git a/arch/sparc/include/asm/Kbuild b/arch/sparc/include/asm/Kbuild index e26d430ce2f..ff18e3cfb6b 100644 --- a/arch/sparc/include/asm/Kbuild +++ b/arch/sparc/include/asm/Kbuild @@ -2,11 +2,16 @@  generic-y += clkdev.h +generic-y += cputime.h  generic-y += div64.h +generic-y += emergency-restart.h  generic-y += exec.h  generic-y += local64.h +generic-y += mutex.h  generic-y += irq_regs.h  generic-y += local.h  generic-y += module.h +generic-y += serial.h  generic-y += trace_clock.h +generic-y += types.h  generic-y += word-at-a-time.h diff --git a/arch/sparc/include/asm/cputime.h b/arch/sparc/include/asm/cputime.h deleted file mode 100644 index 1a642b81e01..00000000000 --- a/arch/sparc/include/asm/cputime.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef __SPARC_CPUTIME_H -#define __SPARC_CPUTIME_H - -#include <asm-generic/cputime.h> - -#endif /* __SPARC_CPUTIME_H */ diff --git a/arch/sparc/include/asm/emergency-restart.h b/arch/sparc/include/asm/emergency-restart.h deleted file mode 100644 index 108d8c48e42..00000000000 --- a/arch/sparc/include/asm/emergency-restart.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _ASM_EMERGENCY_RESTART_H -#define _ASM_EMERGENCY_RESTART_H - -#include <asm-generic/emergency-restart.h> - -#endif /* _ASM_EMERGENCY_RESTART_H */ diff --git a/arch/sparc/include/asm/mutex.h b/arch/sparc/include/asm/mutex.h deleted file mode 100644 index 458c1f7fbc1..00000000000 --- a/arch/sparc/include/asm/mutex.h +++ /dev/null @@ -1,9 +0,0 @@ -/* - * Pull in the generic implementation for the mutex fastpath. - * - * TODO: implement optimized primitives instead, or leave the generic - * implementation in place, or pick the atomic_xchg() based generic - * implementation. (see asm-generic/mutex-xchg.h for details) - */ - -#include <asm-generic/mutex-dec.h> diff --git a/arch/sparc/include/asm/pgtable_64.h b/arch/sparc/include/asm/pgtable_64.h index 08fcce90316..7619f2f792a 100644 --- a/arch/sparc/include/asm/pgtable_64.h +++ b/arch/sparc/include/asm/pgtable_64.h @@ -915,6 +915,7 @@ static inline int io_remap_pfn_range(struct vm_area_struct *vma,  	return remap_pfn_range(vma, from, phys_base >> PAGE_SHIFT, size, prot);  } +#include <asm/tlbflush.h>  #include <asm-generic/pgtable.h>  /* We provide our own get_unmapped_area to cope with VA holes and diff --git a/arch/sparc/include/asm/serial.h b/arch/sparc/include/asm/serial.h deleted file mode 100644 index f90d61c2805..00000000000 --- a/arch/sparc/include/asm/serial.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef __SPARC_SERIAL_H -#define __SPARC_SERIAL_H - -#define BASE_BAUD ( 1843200 / 16 ) - -#endif /* __SPARC_SERIAL_H */ diff --git a/arch/sparc/include/asm/smp_32.h b/arch/sparc/include/asm/smp_32.h index b73da3c5f10..3c8917f054d 100644 --- a/arch/sparc/include/asm/smp_32.h +++ b/arch/sparc/include/asm/smp_32.h @@ -36,7 +36,6 @@ typedef void (*smpfunc_t)(unsigned long, unsigned long, unsigned long,  		       unsigned long, unsigned long);  void cpu_panic(void); -extern void smp4m_irq_rotate(int cpu);  /*   *	General functions that each host system must provide. @@ -46,7 +45,6 @@ void sun4m_init_smp(void);  void sun4d_init_smp(void);  void smp_callin(void); -void smp_boot_cpus(void);  void smp_store_cpu_info(int);  void smp_resched_interrupt(void); @@ -107,9 +105,6 @@ extern int hard_smp_processor_id(void);  #define raw_smp_processor_id()		(current_thread_info()->cpu) -#define prof_multiplier(__cpu)		cpu_data(__cpu).multiplier -#define prof_counter(__cpu)		cpu_data(__cpu).counter -  void smp_setup_cpu_possible_map(void);  #endif /* !(__ASSEMBLY__) */ diff --git a/arch/sparc/include/asm/spitfire.h b/arch/sparc/include/asm/spitfire.h index d06a2660175..6b67e50fb9b 100644 --- a/arch/sparc/include/asm/spitfire.h +++ b/arch/sparc/include/asm/spitfire.h @@ -45,6 +45,7 @@  #define SUN4V_CHIP_NIAGARA3	0x03  #define SUN4V_CHIP_NIAGARA4	0x04  #define SUN4V_CHIP_NIAGARA5	0x05 +#define SUN4V_CHIP_SPARC64X	0x8a  #define SUN4V_CHIP_UNKNOWN	0xff  #ifndef __ASSEMBLY__ diff --git a/arch/sparc/include/asm/switch_to_64.h b/arch/sparc/include/asm/switch_to_64.h index cad36f56fa0..c7de3323819 100644 --- a/arch/sparc/include/asm/switch_to_64.h +++ b/arch/sparc/include/asm/switch_to_64.h @@ -18,8 +18,7 @@ do {						\  	 * and 2 stores in this critical code path.  -DaveM  	 */  #define switch_to(prev, next, last)					\ -do {	flush_tlb_pending();						\ -	save_and_clear_fpu();						\ +do {	save_and_clear_fpu();						\  	/* If you are tempted to conditionalize the following */	\  	/* so that ASI is only written if it changes, think again. */	\  	__asm__ __volatile__("wr %%g0, %0, %%asi"			\ diff --git a/arch/sparc/include/asm/tlbflush_64.h b/arch/sparc/include/asm/tlbflush_64.h index 2ef46349415..f0d6a9700f4 100644 --- a/arch/sparc/include/asm/tlbflush_64.h +++ b/arch/sparc/include/asm/tlbflush_64.h @@ -11,24 +11,40 @@  struct tlb_batch {  	struct mm_struct *mm;  	unsigned long tlb_nr; +	unsigned long active;  	unsigned long vaddrs[TLB_BATCH_NR];  };  extern void flush_tsb_kernel_range(unsigned long start, unsigned long end);  extern void flush_tsb_user(struct tlb_batch *tb); +extern void flush_tsb_user_page(struct mm_struct *mm, unsigned long vaddr);  /* TLB flush operations. */ -extern void flush_tlb_pending(void); +static inline void flush_tlb_mm(struct mm_struct *mm) +{ +} + +static inline void flush_tlb_page(struct vm_area_struct *vma, +				  unsigned long vmaddr) +{ +} + +static inline void flush_tlb_range(struct vm_area_struct *vma, +				   unsigned long start, unsigned long end) +{ +} + +#define __HAVE_ARCH_ENTER_LAZY_MMU_MODE -#define flush_tlb_range(vma,start,end)	\ -	do { (void)(start); flush_tlb_pending(); } while (0) -#define flush_tlb_page(vma,addr)	flush_tlb_pending() -#define flush_tlb_mm(mm)		flush_tlb_pending() +extern void flush_tlb_pending(void); +extern void arch_enter_lazy_mmu_mode(void); +extern void arch_leave_lazy_mmu_mode(void); +#define arch_flush_lazy_mmu_mode()      do {} while (0)  /* Local cpu only.  */  extern void __flush_tlb_all(void); - +extern void __flush_tlb_page(unsigned long context, unsigned long vaddr);  extern void __flush_tlb_kernel_range(unsigned long start, unsigned long end);  #ifndef CONFIG_SMP @@ -38,15 +54,24 @@ do {	flush_tsb_kernel_range(start,end); \  	__flush_tlb_kernel_range(start,end); \  } while (0) +static inline void global_flush_tlb_page(struct mm_struct *mm, unsigned long vaddr) +{ +	__flush_tlb_page(CTX_HWBITS(mm->context), vaddr); +} +  #else /* CONFIG_SMP */  extern void smp_flush_tlb_kernel_range(unsigned long start, unsigned long end); +extern void smp_flush_tlb_page(struct mm_struct *mm, unsigned long vaddr);  #define flush_tlb_kernel_range(start, end) \  do {	flush_tsb_kernel_range(start,end); \  	smp_flush_tlb_kernel_range(start, end); \  } while (0) +#define global_flush_tlb_page(mm, vaddr) \ +	smp_flush_tlb_page(mm, vaddr) +  #endif /* ! CONFIG_SMP */  #endif /* _SPARC64_TLBFLUSH_H */ diff --git a/arch/sparc/include/uapi/asm/Kbuild b/arch/sparc/include/uapi/asm/Kbuild index ce175aff71b..b5843ee09fb 100644 --- a/arch/sparc/include/uapi/asm/Kbuild +++ b/arch/sparc/include/uapi/asm/Kbuild @@ -44,7 +44,6 @@ header-y += swab.h  header-y += termbits.h  header-y += termios.h  header-y += traps.h -header-y += types.h  header-y += uctx.h  header-y += unistd.h  header-y += utrap.h diff --git a/arch/sparc/include/uapi/asm/types.h b/arch/sparc/include/uapi/asm/types.h deleted file mode 100644 index 383d156cde9..00000000000 --- a/arch/sparc/include/uapi/asm/types.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef _SPARC_TYPES_H -#define _SPARC_TYPES_H -/* - * This file is never included by application software unless - * explicitly requested (e.g., via linux/types.h) in which case the - * application is Linux specific so (user-) name space pollution is - * not a major issue.  However, for interoperability, libraries still - * need to be careful to avoid a name clashes. - */ - -#if defined(__sparc__) - -#include <asm-generic/int-ll64.h> - -#endif /* defined(__sparc__) */ - -#endif /* defined(_SPARC_TYPES_H) */ diff --git a/arch/sparc/kernel/cpu.c b/arch/sparc/kernel/cpu.c index a6c94a2bf9d..5c5125895db 100644 --- a/arch/sparc/kernel/cpu.c +++ b/arch/sparc/kernel/cpu.c @@ -493,6 +493,12 @@ static void __init sun4v_cpu_probe(void)  		sparc_pmu_type = "niagara5";  		break; +	case SUN4V_CHIP_SPARC64X: +		sparc_cpu_type = "SPARC64-X"; +		sparc_fpu_type = "SPARC64-X integrated FPU"; +		sparc_pmu_type = "sparc64-x"; +		break; +  	default:  		printk(KERN_WARNING "CPU: Unknown sun4v cpu type [%s]\n",  		       prom_cpu_compatible); diff --git a/arch/sparc/kernel/head_64.S b/arch/sparc/kernel/head_64.S index 2feb15c35d9..26b706a1867 100644 --- a/arch/sparc/kernel/head_64.S +++ b/arch/sparc/kernel/head_64.S @@ -134,6 +134,8 @@ prom_niagara_prefix:  	.asciz	"SUNW,UltraSPARC-T"  prom_sparc_prefix:  	.asciz	"SPARC-" +prom_sparc64x_prefix: +	.asciz	"SPARC64-X"  	.align	4  prom_root_compatible:  	.skip	64 @@ -412,7 +414,7 @@ sun4v_chip_type:  	cmp	%g2, 'T'  	be,pt	%xcc, 70f  	 cmp	%g2, 'M' -	bne,pn	%xcc, 4f +	bne,pn	%xcc, 49f  	 nop  70:	ldub	[%g1 + 7], %g2 @@ -425,7 +427,7 @@ sun4v_chip_type:  	cmp	%g2, '5'  	be,pt	%xcc, 5f  	 mov	SUN4V_CHIP_NIAGARA5, %g4 -	ba,pt	%xcc, 4f +	ba,pt	%xcc, 49f  	 nop  91:	sethi	%hi(prom_cpu_compatible), %g1 @@ -439,6 +441,25 @@ sun4v_chip_type:  	 mov	SUN4V_CHIP_NIAGARA2, %g4  4: +	/* Athena */ +	sethi	%hi(prom_cpu_compatible), %g1 +	or	%g1, %lo(prom_cpu_compatible), %g1 +	sethi	%hi(prom_sparc64x_prefix), %g7 +	or	%g7, %lo(prom_sparc64x_prefix), %g7 +	mov	9, %g3 +41:	ldub	[%g7], %g2 +	ldub	[%g1], %g4 +	cmp	%g2, %g4 +	bne,pn	%icc, 49f +	add	%g7, 1, %g7 +	subcc	%g3, 1, %g3 +	bne,pt	%xcc, 41b +	add	%g1, 1, %g1 +	mov	SUN4V_CHIP_SPARC64X, %g4 +	ba,pt	%xcc, 5f +	nop + +49:  	mov	SUN4V_CHIP_UNKNOWN, %g4  5:	sethi	%hi(sun4v_chip_type), %g2  	or	%g2, %lo(sun4v_chip_type), %g2 diff --git a/arch/sparc/kernel/leon_pci_grpci2.c b/arch/sparc/kernel/leon_pci_grpci2.c index fc4320886a3..4d1487138d2 100644 --- a/arch/sparc/kernel/leon_pci_grpci2.c +++ b/arch/sparc/kernel/leon_pci_grpci2.c @@ -186,6 +186,8 @@ struct grpci2_cap_first {  #define CAP9_IOMAP_OFS 0x20  #define CAP9_BARSIZE_OFS 0x24 +#define TGT 256 +  struct grpci2_priv {  	struct leon_pci_info	info; /* must be on top of this structure */  	struct grpci2_regs	*regs; @@ -237,8 +239,12 @@ static int grpci2_cfg_r32(struct grpci2_priv *priv, unsigned int bus,  	if (where & 0x3)  		return -EINVAL; -	if (bus == 0 && PCI_SLOT(devfn) != 0) -		devfn += (0x8 * 6); +	if (bus == 0) { +		devfn += (0x8 * 6); /* start at AD16=Device0 */ +	} else if (bus == TGT) { +		bus = 0; +		devfn = 0; /* special case: bridge controller itself */ +	}  	/* Select bus */  	spin_lock_irqsave(&grpci2_dev_lock, flags); @@ -303,8 +309,12 @@ static int grpci2_cfg_w32(struct grpci2_priv *priv, unsigned int bus,  	if (where & 0x3)  		return -EINVAL; -	if (bus == 0 && PCI_SLOT(devfn) != 0) -		devfn += (0x8 * 6); +	if (bus == 0) { +		devfn += (0x8 * 6); /* start at AD16=Device0 */ +	} else if (bus == TGT) { +		bus = 0; +		devfn = 0; /* special case: bridge controller itself */ +	}  	/* Select bus */  	spin_lock_irqsave(&grpci2_dev_lock, flags); @@ -368,7 +378,7 @@ static int grpci2_read_config(struct pci_bus *bus, unsigned int devfn,  	unsigned int busno = bus->number;  	int ret; -	if (PCI_SLOT(devfn) > 15 || (PCI_SLOT(devfn) == 0 && busno == 0)) { +	if (PCI_SLOT(devfn) > 15 || busno > 255) {  		*val = ~0;  		return 0;  	} @@ -406,7 +416,7 @@ static int grpci2_write_config(struct pci_bus *bus, unsigned int devfn,  	struct grpci2_priv *priv = grpci2priv;  	unsigned int busno = bus->number; -	if (PCI_SLOT(devfn) > 15 || (PCI_SLOT(devfn) == 0 && busno == 0)) +	if (PCI_SLOT(devfn) > 15 || busno > 255)  		return 0;  #ifdef GRPCI2_DEBUG_CFGACCESS @@ -578,15 +588,15 @@ void grpci2_hw_init(struct grpci2_priv *priv)  		REGSTORE(regs->ahbmst_map[i], priv->pci_area);  	/* Get the GRPCI2 Host PCI ID */ -	grpci2_cfg_r32(priv, 0, 0, PCI_VENDOR_ID, &priv->pciid); +	grpci2_cfg_r32(priv, TGT, 0, PCI_VENDOR_ID, &priv->pciid);  	/* Get address to first (always defined) capability structure */ -	grpci2_cfg_r8(priv, 0, 0, PCI_CAPABILITY_LIST, &capptr); +	grpci2_cfg_r8(priv, TGT, 0, PCI_CAPABILITY_LIST, &capptr);  	/* Enable/Disable Byte twisting */ -	grpci2_cfg_r32(priv, 0, 0, capptr+CAP9_IOMAP_OFS, &io_map); +	grpci2_cfg_r32(priv, TGT, 0, capptr+CAP9_IOMAP_OFS, &io_map);  	io_map = (io_map & ~0x1) | (priv->bt_enabled ? 1 : 0); -	grpci2_cfg_w32(priv, 0, 0, capptr+CAP9_IOMAP_OFS, io_map); +	grpci2_cfg_w32(priv, TGT, 0, capptr+CAP9_IOMAP_OFS, io_map);  	/* Setup the Host's PCI Target BARs for other peripherals to access,  	 * and do DMA to the host's memory. The target BARs can be sized and @@ -617,17 +627,18 @@ void grpci2_hw_init(struct grpci2_priv *priv)  				pciadr = 0;  			}  		} -		grpci2_cfg_w32(priv, 0, 0, capptr+CAP9_BARSIZE_OFS+i*4, bar_sz); -		grpci2_cfg_w32(priv, 0, 0, PCI_BASE_ADDRESS_0+i*4, pciadr); -		grpci2_cfg_w32(priv, 0, 0, capptr+CAP9_BAR_OFS+i*4, ahbadr); +		grpci2_cfg_w32(priv, TGT, 0, capptr+CAP9_BARSIZE_OFS+i*4, +				bar_sz); +		grpci2_cfg_w32(priv, TGT, 0, PCI_BASE_ADDRESS_0+i*4, pciadr); +		grpci2_cfg_w32(priv, TGT, 0, capptr+CAP9_BAR_OFS+i*4, ahbadr);  		printk(KERN_INFO "        TGT BAR[%d]: 0x%08x (PCI)-> 0x%08x\n",  			i, pciadr, ahbadr);  	}  	/* set as bus master and enable pci memory responses */ -	grpci2_cfg_r32(priv, 0, 0, PCI_COMMAND, &data); +	grpci2_cfg_r32(priv, TGT, 0, PCI_COMMAND, &data);  	data |= (PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); -	grpci2_cfg_w32(priv, 0, 0, PCI_COMMAND, data); +	grpci2_cfg_w32(priv, TGT, 0, PCI_COMMAND, data);  	/* Enable Error respone (CPU-TRAP) on illegal memory access. */  	REGSTORE(regs->ctrl, CTRL_ER | CTRL_PE); diff --git a/arch/sparc/kernel/smp_64.c b/arch/sparc/kernel/smp_64.c index 537eb66abd0..ca64d2a86ec 100644 --- a/arch/sparc/kernel/smp_64.c +++ b/arch/sparc/kernel/smp_64.c @@ -849,7 +849,7 @@ void smp_tsb_sync(struct mm_struct *mm)  }  extern unsigned long xcall_flush_tlb_mm; -extern unsigned long xcall_flush_tlb_pending; +extern unsigned long xcall_flush_tlb_page;  extern unsigned long xcall_flush_tlb_kernel_range;  extern unsigned long xcall_fetch_glob_regs;  extern unsigned long xcall_fetch_glob_pmu; @@ -1074,23 +1074,56 @@ local_flush_and_out:  	put_cpu();  } +struct tlb_pending_info { +	unsigned long ctx; +	unsigned long nr; +	unsigned long *vaddrs; +}; + +static void tlb_pending_func(void *info) +{ +	struct tlb_pending_info *t = info; + +	__flush_tlb_pending(t->ctx, t->nr, t->vaddrs); +} +  void smp_flush_tlb_pending(struct mm_struct *mm, unsigned long nr, unsigned long *vaddrs)  {  	u32 ctx = CTX_HWBITS(mm->context); +	struct tlb_pending_info info;  	int cpu = get_cpu(); +	info.ctx = ctx; +	info.nr = nr; +	info.vaddrs = vaddrs; +  	if (mm == current->mm && atomic_read(&mm->mm_users) == 1)  		cpumask_copy(mm_cpumask(mm), cpumask_of(cpu));  	else -		smp_cross_call_masked(&xcall_flush_tlb_pending, -				      ctx, nr, (unsigned long) vaddrs, -				      mm_cpumask(mm)); +		smp_call_function_many(mm_cpumask(mm), tlb_pending_func, +				       &info, 1);  	__flush_tlb_pending(ctx, nr, vaddrs);  	put_cpu();  } +void smp_flush_tlb_page(struct mm_struct *mm, unsigned long vaddr) +{ +	unsigned long context = CTX_HWBITS(mm->context); +	int cpu = get_cpu(); + +	if (mm == current->mm && atomic_read(&mm->mm_users) == 1) +		cpumask_copy(mm_cpumask(mm), cpumask_of(cpu)); +	else +		smp_cross_call_masked(&xcall_flush_tlb_page, +				      context, vaddr, 0, +				      mm_cpumask(mm)); +	__flush_tlb_page(context, vaddr); + +	put_cpu(); +} +  void smp_flush_tlb_kernel_range(unsigned long start, unsigned long end)  {  	start &= PAGE_MASK; diff --git a/arch/sparc/lib/bitext.c b/arch/sparc/lib/bitext.c index 48d00e72ce1..8ec4e9c0251 100644 --- a/arch/sparc/lib/bitext.c +++ b/arch/sparc/lib/bitext.c @@ -119,11 +119,7 @@ void bit_map_clear(struct bit_map *t, int offset, int len)  void bit_map_init(struct bit_map *t, unsigned long *map, int size)  { - -	if ((size & 07) != 0) -		BUG(); -	memset(map, 0, size>>3); - +	bitmap_zero(map, size);  	memset(t, 0, sizeof *t);  	spin_lock_init(&t->lock);  	t->map = map; diff --git a/arch/sparc/mm/iommu.c b/arch/sparc/mm/iommu.c index 0f4f7191fbb..28f96f27c76 100644 --- a/arch/sparc/mm/iommu.c +++ b/arch/sparc/mm/iommu.c @@ -34,7 +34,7 @@  #define IOMMU_RNGE	IOMMU_RNGE_256MB  #define IOMMU_START	0xF0000000  #define IOMMU_WINSIZE	(256*1024*1024U) -#define IOMMU_NPTES	(IOMMU_WINSIZE/PAGE_SIZE)	/* 64K PTEs, 265KB */ +#define IOMMU_NPTES	(IOMMU_WINSIZE/PAGE_SIZE)	/* 64K PTEs, 256KB */  #define IOMMU_ORDER	6				/* 4096 * (1<<6) */  /* srmmu.c */ diff --git a/arch/sparc/mm/srmmu.c b/arch/sparc/mm/srmmu.c index c38bb72e3e8..036c2797dec 100644 --- a/arch/sparc/mm/srmmu.c +++ b/arch/sparc/mm/srmmu.c @@ -280,7 +280,9 @@ static void __init srmmu_nocache_init(void)  		SRMMU_NOCACHE_ALIGN_MAX, 0UL);  	memset(srmmu_nocache_pool, 0, srmmu_nocache_size); -	srmmu_nocache_bitmap = __alloc_bootmem(bitmap_bits >> 3, SMP_CACHE_BYTES, 0UL); +	srmmu_nocache_bitmap = +		__alloc_bootmem(BITS_TO_LONGS(bitmap_bits) * sizeof(long), +				SMP_CACHE_BYTES, 0UL);  	bit_map_init(&srmmu_nocache_map, srmmu_nocache_bitmap, bitmap_bits);  	srmmu_swapper_pg_dir = __srmmu_get_nocache(SRMMU_PGD_TABLE_SIZE, SRMMU_PGD_TABLE_SIZE); diff --git a/arch/sparc/mm/tlb.c b/arch/sparc/mm/tlb.c index ba6ae7ffdc2..272aa4f7657 100644 --- a/arch/sparc/mm/tlb.c +++ b/arch/sparc/mm/tlb.c @@ -24,11 +24,17 @@ static DEFINE_PER_CPU(struct tlb_batch, tlb_batch);  void flush_tlb_pending(void)  {  	struct tlb_batch *tb = &get_cpu_var(tlb_batch); +	struct mm_struct *mm = tb->mm; -	if (tb->tlb_nr) { -		flush_tsb_user(tb); +	if (!tb->tlb_nr) +		goto out; -		if (CTX_VALID(tb->mm->context)) { +	flush_tsb_user(tb); + +	if (CTX_VALID(mm->context)) { +		if (tb->tlb_nr == 1) { +			global_flush_tlb_page(mm, tb->vaddrs[0]); +		} else {  #ifdef CONFIG_SMP  			smp_flush_tlb_pending(tb->mm, tb->tlb_nr,  					      &tb->vaddrs[0]); @@ -37,12 +43,30 @@ void flush_tlb_pending(void)  					    tb->tlb_nr, &tb->vaddrs[0]);  #endif  		} -		tb->tlb_nr = 0;  	} +	tb->tlb_nr = 0; + +out:  	put_cpu_var(tlb_batch);  } +void arch_enter_lazy_mmu_mode(void) +{ +	struct tlb_batch *tb = &__get_cpu_var(tlb_batch); + +	tb->active = 1; +} + +void arch_leave_lazy_mmu_mode(void) +{ +	struct tlb_batch *tb = &__get_cpu_var(tlb_batch); + +	if (tb->tlb_nr) +		flush_tlb_pending(); +	tb->active = 0; +} +  static void tlb_batch_add_one(struct mm_struct *mm, unsigned long vaddr,  			      bool exec)  { @@ -60,6 +84,12 @@ static void tlb_batch_add_one(struct mm_struct *mm, unsigned long vaddr,  		nr = 0;  	} +	if (!tb->active) { +		global_flush_tlb_page(mm, vaddr); +		flush_tsb_user_page(mm, vaddr); +		return; +	} +  	if (nr == 0)  		tb->mm = mm; diff --git a/arch/sparc/mm/tsb.c b/arch/sparc/mm/tsb.c index 428982b9bec..2cc3bce5ee9 100644 --- a/arch/sparc/mm/tsb.c +++ b/arch/sparc/mm/tsb.c @@ -7,11 +7,10 @@  #include <linux/preempt.h>  #include <linux/slab.h>  #include <asm/page.h> -#include <asm/tlbflush.h> -#include <asm/tlb.h> -#include <asm/mmu_context.h>  #include <asm/pgtable.h> +#include <asm/mmu_context.h>  #include <asm/tsb.h> +#include <asm/tlb.h>  #include <asm/oplib.h>  extern struct tsb swapper_tsb[KERNEL_TSB_NENTRIES]; @@ -46,23 +45,27 @@ void flush_tsb_kernel_range(unsigned long start, unsigned long end)  	}  } -static void __flush_tsb_one(struct tlb_batch *tb, unsigned long hash_shift, -			    unsigned long tsb, unsigned long nentries) +static void __flush_tsb_one_entry(unsigned long tsb, unsigned long v, +				  unsigned long hash_shift, +				  unsigned long nentries)  { -	unsigned long i; +	unsigned long tag, ent, hash; -	for (i = 0; i < tb->tlb_nr; i++) { -		unsigned long v = tb->vaddrs[i]; -		unsigned long tag, ent, hash; +	v &= ~0x1UL; +	hash = tsb_hash(v, hash_shift, nentries); +	ent = tsb + (hash * sizeof(struct tsb)); +	tag = (v >> 22UL); -		v &= ~0x1UL; +	tsb_flush(ent, tag); +} -		hash = tsb_hash(v, hash_shift, nentries); -		ent = tsb + (hash * sizeof(struct tsb)); -		tag = (v >> 22UL); +static void __flush_tsb_one(struct tlb_batch *tb, unsigned long hash_shift, +			    unsigned long tsb, unsigned long nentries) +{ +	unsigned long i; -		tsb_flush(ent, tag); -	} +	for (i = 0; i < tb->tlb_nr; i++) +		__flush_tsb_one_entry(tsb, tb->vaddrs[i], hash_shift, nentries);  }  void flush_tsb_user(struct tlb_batch *tb) @@ -90,6 +93,30 @@ void flush_tsb_user(struct tlb_batch *tb)  	spin_unlock_irqrestore(&mm->context.lock, flags);  } +void flush_tsb_user_page(struct mm_struct *mm, unsigned long vaddr) +{ +	unsigned long nentries, base, flags; + +	spin_lock_irqsave(&mm->context.lock, flags); + +	base = (unsigned long) mm->context.tsb_block[MM_TSB_BASE].tsb; +	nentries = mm->context.tsb_block[MM_TSB_BASE].tsb_nentries; +	if (tlb_type == cheetah_plus || tlb_type == hypervisor) +		base = __pa(base); +	__flush_tsb_one_entry(base, vaddr, PAGE_SHIFT, nentries); + +#if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE) +	if (mm->context.tsb_block[MM_TSB_HUGE].tsb) { +		base = (unsigned long) mm->context.tsb_block[MM_TSB_HUGE].tsb; +		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); +	} +#endif +	spin_unlock_irqrestore(&mm->context.lock, flags); +} +  #define HV_PGSZ_IDX_BASE	HV_PGSZ_IDX_8K  #define HV_PGSZ_MASK_BASE	HV_PGSZ_MASK_8K diff --git a/arch/sparc/mm/ultra.S b/arch/sparc/mm/ultra.S index f8e13d421fc..432aa0cb1b3 100644 --- a/arch/sparc/mm/ultra.S +++ b/arch/sparc/mm/ultra.S @@ -53,6 +53,33 @@ __flush_tlb_mm:		/* 18 insns */  	nop  	.align		32 +	.globl		__flush_tlb_page +__flush_tlb_page:	/* 22 insns */ +	/* %o0 = context, %o1 = vaddr */ +	rdpr		%pstate, %g7 +	andn		%g7, PSTATE_IE, %g2 +	wrpr		%g2, %pstate +	mov		SECONDARY_CONTEXT, %o4 +	ldxa		[%o4] ASI_DMMU, %g2 +	stxa		%o0, [%o4] ASI_DMMU +	andcc		%o1, 1, %g0 +	andn		%o1, 1, %o3 +	be,pn		%icc, 1f +	 or		%o3, 0x10, %o3 +	stxa		%g0, [%o3] ASI_IMMU_DEMAP +1:	stxa		%g0, [%o3] ASI_DMMU_DEMAP +	membar		#Sync +	stxa		%g2, [%o4] ASI_DMMU +	sethi		%hi(KERNBASE), %o4 +	flush		%o4 +	retl +	 wrpr		%g7, 0x0, %pstate +	nop +	nop +	nop +	nop + +	.align		32  	.globl		__flush_tlb_pending  __flush_tlb_pending:	/* 26 insns */  	/* %o0 = context, %o1 = nr, %o2 = vaddrs[] */ @@ -203,6 +230,31 @@ __cheetah_flush_tlb_mm: /* 19 insns */  	retl  	 wrpr		%g7, 0x0, %pstate +__cheetah_flush_tlb_page:	/* 22 insns */ +	/* %o0 = context, %o1 = vaddr */ +	rdpr		%pstate, %g7 +	andn		%g7, PSTATE_IE, %g2 +	wrpr		%g2, 0x0, %pstate +	wrpr		%g0, 1, %tl +	mov		PRIMARY_CONTEXT, %o4 +	ldxa		[%o4] ASI_DMMU, %g2 +	srlx		%g2, CTX_PGSZ1_NUC_SHIFT, %o3 +	sllx		%o3, CTX_PGSZ1_NUC_SHIFT, %o3 +	or		%o0, %o3, %o0	/* Preserve nucleus page size fields */ +	stxa		%o0, [%o4] ASI_DMMU +	andcc		%o1, 1, %g0 +	be,pn		%icc, 1f +	 andn		%o1, 1, %o3 +	stxa		%g0, [%o3] ASI_IMMU_DEMAP +1:	stxa		%g0, [%o3] ASI_DMMU_DEMAP	 +	membar		#Sync +	stxa		%g2, [%o4] ASI_DMMU +	sethi		%hi(KERNBASE), %o4 +	flush		%o4 +	wrpr		%g0, 0, %tl +	retl +	 wrpr		%g7, 0x0, %pstate +  __cheetah_flush_tlb_pending:	/* 27 insns */  	/* %o0 = context, %o1 = nr, %o2 = vaddrs[] */  	rdpr		%pstate, %g7 @@ -269,6 +321,20 @@ __hypervisor_flush_tlb_mm: /* 10 insns */  	retl  	 nop +__hypervisor_flush_tlb_page: /* 11 insns */ +	/* %o0 = context, %o1 = vaddr */ +	mov		%o0, %g2 +	mov		%o1, %o0              /* ARG0: vaddr + IMMU-bit */ +	mov		%g2, %o1	      /* ARG1: mmu context */ +	mov		HV_MMU_ALL, %o2	      /* ARG2: flags */ +	srlx		%o0, PAGE_SHIFT, %o0 +	sllx		%o0, PAGE_SHIFT, %o0 +	ta		HV_MMU_UNMAP_ADDR_TRAP +	brnz,pn		%o0, __hypervisor_tlb_tl0_error +	 mov		HV_MMU_UNMAP_ADDR_TRAP, %o1 +	retl +	 nop +  __hypervisor_flush_tlb_pending: /* 16 insns */  	/* %o0 = context, %o1 = nr, %o2 = vaddrs[] */  	sllx		%o1, 3, %g1 @@ -339,6 +405,13 @@ cheetah_patch_cachetlbops:  	call		tlb_patch_one  	 mov		19, %o2 +	sethi		%hi(__flush_tlb_page), %o0 +	or		%o0, %lo(__flush_tlb_page), %o0 +	sethi		%hi(__cheetah_flush_tlb_page), %o1 +	or		%o1, %lo(__cheetah_flush_tlb_page), %o1 +	call		tlb_patch_one +	 mov		22, %o2 +  	sethi		%hi(__flush_tlb_pending), %o0  	or		%o0, %lo(__flush_tlb_pending), %o0  	sethi		%hi(__cheetah_flush_tlb_pending), %o1 @@ -397,10 +470,9 @@ xcall_flush_tlb_mm:	/* 21 insns */  	nop  	nop -	.globl		xcall_flush_tlb_pending -xcall_flush_tlb_pending:	/* 21 insns */ -	/* %g5=context, %g1=nr, %g7=vaddrs[] */ -	sllx		%g1, 3, %g1 +	.globl		xcall_flush_tlb_page +xcall_flush_tlb_page:	/* 17 insns */ +	/* %g5=context, %g1=vaddr */  	mov		PRIMARY_CONTEXT, %g4  	ldxa		[%g4] ASI_DMMU, %g2  	srlx		%g2, CTX_PGSZ1_NUC_SHIFT, %g4 @@ -408,20 +480,16 @@ xcall_flush_tlb_pending:	/* 21 insns */  	or		%g5, %g4, %g5  	mov		PRIMARY_CONTEXT, %g4  	stxa		%g5, [%g4] ASI_DMMU -1:	sub		%g1, (1 << 3), %g1 -	ldx		[%g7 + %g1], %g5 -	andcc		%g5, 0x1, %g0 +	andcc		%g1, 0x1, %g0  	be,pn		%icc, 2f - -	 andn		%g5, 0x1, %g5 +	 andn		%g1, 0x1, %g5  	stxa		%g0, [%g5] ASI_IMMU_DEMAP  2:	stxa		%g0, [%g5] ASI_DMMU_DEMAP  	membar		#Sync -	brnz,pt		%g1, 1b -	 nop  	stxa		%g2, [%g4] ASI_DMMU  	retry  	nop +	nop  	.globl		xcall_flush_tlb_kernel_range  xcall_flush_tlb_kernel_range:	/* 25 insns */ @@ -656,15 +724,13 @@ __hypervisor_xcall_flush_tlb_mm: /* 21 insns */  	membar		#Sync  	retry -	.globl		__hypervisor_xcall_flush_tlb_pending -__hypervisor_xcall_flush_tlb_pending: /* 21 insns */ -	/* %g5=ctx, %g1=nr, %g7=vaddrs[], %g2,%g3,%g4,g6=scratch */ -	sllx		%g1, 3, %g1 +	.globl		__hypervisor_xcall_flush_tlb_page +__hypervisor_xcall_flush_tlb_page: /* 17 insns */ +	/* %g5=ctx, %g1=vaddr */  	mov		%o0, %g2  	mov		%o1, %g3  	mov		%o2, %g4 -1:	sub		%g1, (1 << 3), %g1 -	ldx		[%g7 + %g1], %o0	/* ARG0: virtual address */ +	mov		%g1, %o0	        /* ARG0: virtual address */  	mov		%g5, %o1		/* ARG1: mmu context */  	mov		HV_MMU_ALL, %o2		/* ARG2: flags */  	srlx		%o0, PAGE_SHIFT, %o0 @@ -673,8 +739,6 @@ __hypervisor_xcall_flush_tlb_pending: /* 21 insns */  	mov		HV_MMU_UNMAP_ADDR_TRAP, %g6  	brnz,a,pn	%o0, __hypervisor_tlb_xcall_error  	 mov		%o0, %g5 -	brnz,pt		%g1, 1b -	 nop  	mov		%g2, %o0  	mov		%g3, %o1  	mov		%g4, %o2 @@ -757,6 +821,13 @@ hypervisor_patch_cachetlbops:  	call		tlb_patch_one  	 mov		10, %o2 +	sethi		%hi(__flush_tlb_page), %o0 +	or		%o0, %lo(__flush_tlb_page), %o0 +	sethi		%hi(__hypervisor_flush_tlb_page), %o1 +	or		%o1, %lo(__hypervisor_flush_tlb_page), %o1 +	call		tlb_patch_one +	 mov		11, %o2 +  	sethi		%hi(__flush_tlb_pending), %o0  	or		%o0, %lo(__flush_tlb_pending), %o0  	sethi		%hi(__hypervisor_flush_tlb_pending), %o1 @@ -788,12 +859,12 @@ hypervisor_patch_cachetlbops:  	call		tlb_patch_one  	 mov		21, %o2 -	sethi		%hi(xcall_flush_tlb_pending), %o0 -	or		%o0, %lo(xcall_flush_tlb_pending), %o0 -	sethi		%hi(__hypervisor_xcall_flush_tlb_pending), %o1 -	or		%o1, %lo(__hypervisor_xcall_flush_tlb_pending), %o1 +	sethi		%hi(xcall_flush_tlb_page), %o0 +	or		%o0, %lo(xcall_flush_tlb_page), %o0 +	sethi		%hi(__hypervisor_xcall_flush_tlb_page), %o1 +	or		%o1, %lo(__hypervisor_xcall_flush_tlb_page), %o1  	call		tlb_patch_one -	 mov		21, %o2 +	 mov		17, %o2  	sethi		%hi(xcall_flush_tlb_kernel_range), %o0  	or		%o0, %lo(xcall_flush_tlb_kernel_range), %o0  |