MIPS: Add support for XPA.
Add support for extended physical addressing (XPA) so that
32-bit platforms can access equal to or greater than 40 bits
of physical addresses.
NOTE:
      1) XPA and EVA are not the same and cannot be used
         simultaneously.
      2) If you configure your kernel for XPA, the PTEs
         and all address sizes become 64-bit.
      3) Your platform MUST have working HIGHMEM support.
Signed-off-by: Steven J. Hill <Steven.Hill@imgtec.com>
Cc: linux-mips@linux-mips.org
Patchwork: https://patchwork.linux-mips.org/patch/9355/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
	
	
This commit is contained in:
		
					parent
					
						
							
								be0c37c985
							
						
					
				
			
			
				commit
				
					
						c5b367835c
					
				
			
		
					 11 changed files with 173 additions and 44 deletions
				
			
		|  | @ -377,6 +377,7 @@ config MIPS_MALTA | |||
| 	select SYS_HAS_CPU_MIPS32_R1 | ||||
| 	select SYS_HAS_CPU_MIPS32_R2 | ||||
| 	select SYS_HAS_CPU_MIPS32_R3_5 | ||||
| 	select SYS_HAS_CPU_MIPS32_R5 | ||||
| 	select SYS_HAS_CPU_MIPS32_R6 | ||||
| 	select SYS_HAS_CPU_MIPS64_R1 | ||||
| 	select SYS_HAS_CPU_MIPS64_R2 | ||||
|  | @ -386,6 +387,7 @@ config MIPS_MALTA | |||
| 	select SYS_SUPPORTS_32BIT_KERNEL | ||||
| 	select SYS_SUPPORTS_64BIT_KERNEL | ||||
| 	select SYS_SUPPORTS_BIG_ENDIAN | ||||
| 	select SYS_SUPPORTS_HIGHMEM | ||||
| 	select SYS_SUPPORTS_LITTLE_ENDIAN | ||||
| 	select SYS_SUPPORTS_MICROMIPS | ||||
| 	select SYS_SUPPORTS_MIPS_CMP | ||||
|  | @ -1596,6 +1598,33 @@ config CPU_MIPS32_3_5_EVA | |||
| 	  One of its primary benefits is an increase in the maximum size | ||||
| 	  of lowmem (up to 3GB). If unsure, say 'N' here. | ||||
| 
 | ||||
| config CPU_MIPS32_R5_FEATURES | ||||
| 	bool "MIPS32 Release 5 Features" | ||||
| 	depends on SYS_HAS_CPU_MIPS32_R5 | ||||
| 	depends on CPU_MIPS32_R2 | ||||
| 	help | ||||
| 	  Choose this option to build a kernel for release 2 or later of the | ||||
| 	  MIPS32 architecture including features from release 5 such as | ||||
| 	  support for Extended Physical Addressing (XPA). | ||||
| 
 | ||||
| config CPU_MIPS32_R5_XPA | ||||
| 	bool "Extended Physical Addressing (XPA)" | ||||
| 	depends on CPU_MIPS32_R5_FEATURES | ||||
| 	depends on !EVA | ||||
| 	depends on !PAGE_SIZE_4KB | ||||
| 	depends on SYS_SUPPORTS_HIGHMEM | ||||
| 	select XPA | ||||
| 	select HIGHMEM | ||||
| 	select ARCH_PHYS_ADDR_T_64BIT | ||||
| 	default n | ||||
| 	help | ||||
| 	  Choose this option if you want to enable the Extended Physical | ||||
| 	  Addressing (XPA) on your MIPS32 core (such as P5600 series). The | ||||
| 	  benefit is to increase physical addressing equal to or greater | ||||
| 	  than 40 bits. Note that this has the side effect of turning on | ||||
| 	  64-bit addressing which in turn makes the PTEs 64-bit in size. | ||||
| 	  If unsure, say 'N' here. | ||||
| 
 | ||||
| if CPU_LOONGSON2F | ||||
| config CPU_NOP_WORKAROUNDS | ||||
| 	bool | ||||
|  | @ -1699,6 +1728,9 @@ config SYS_HAS_CPU_MIPS32_R2 | |||
| config SYS_HAS_CPU_MIPS32_R3_5 | ||||
| 	bool | ||||
| 
 | ||||
| config SYS_HAS_CPU_MIPS32_R5 | ||||
| 	bool | ||||
| 
 | ||||
| config SYS_HAS_CPU_MIPS32_R6 | ||||
| 	bool | ||||
| 
 | ||||
|  | @ -1836,6 +1868,9 @@ config CPU_MIPSR6 | |||
| config EVA | ||||
| 	bool | ||||
| 
 | ||||
| config XPA | ||||
| 	bool | ||||
| 
 | ||||
| config SYS_SUPPORTS_32BIT_KERNEL | ||||
| 	bool | ||||
| config SYS_SUPPORTS_64BIT_KERNEL | ||||
|  |  | |||
|  | @ -139,6 +139,9 @@ | |||
| # endif | ||||
| #endif | ||||
| 
 | ||||
| #ifndef cpu_has_xpa | ||||
| #define cpu_has_xpa		(cpu_data[0].options & MIPS_CPU_XPA) | ||||
| #endif | ||||
| #ifndef cpu_has_vtag_icache | ||||
| #define cpu_has_vtag_icache	(cpu_data[0].icache.flags & MIPS_CACHE_VTAG) | ||||
| #endif | ||||
|  |  | |||
|  | @ -377,6 +377,7 @@ enum cpu_type_enum { | |||
| #define MIPS_CPU_MAAR		0x400000000ull /* MAAR(I) registers are present */ | ||||
| #define MIPS_CPU_FRE		0x800000000ull /* FRE & UFE bits implemented */ | ||||
| #define MIPS_CPU_RW_LLB		0x1000000000ull /* LLADDR/LLB writes are allowed */ | ||||
| #define MIPS_CPU_XPA		0x2000000000ull /* CPU supports Extended Physical Addressing */ | ||||
| 
 | ||||
| /*
 | ||||
|  * CPU ASE encodings | ||||
|  |  | |||
|  | @ -105,13 +105,16 @@ static inline void pmd_clear(pmd_t *pmdp) | |||
| 
 | ||||
| #if defined(CONFIG_PHYS_ADDR_T_64BIT) && defined(CONFIG_CPU_MIPS32) | ||||
| #define pte_page(x)		pfn_to_page(pte_pfn(x)) | ||||
| #define pte_pfn(x)		((unsigned long)((x).pte_high >> 6)) | ||||
| #define pte_pfn(x)		(((unsigned long)((x).pte_high >> _PFN_SHIFT)) | (unsigned long)((x).pte_low << _PAGE_PRESENT_SHIFT)) | ||||
| static inline pte_t | ||||
| pfn_pte(unsigned long pfn, pgprot_t prot) | ||||
| { | ||||
| 	pte_t pte; | ||||
| 	pte.pte_high = (pfn << 6) | (pgprot_val(prot) & 0x3f); | ||||
| 	pte.pte_low = pgprot_val(prot); | ||||
| 
 | ||||
| 	pte.pte_low = (pfn >> _PAGE_PRESENT_SHIFT) | | ||||
| 				(pgprot_val(prot) & ~_PFNX_MASK); | ||||
| 	pte.pte_high = (pfn << _PFN_SHIFT) | | ||||
| 				(pgprot_val(prot) & ~_PFN_MASK); | ||||
| 	return pte; | ||||
| } | ||||
| 
 | ||||
|  | @ -166,9 +169,9 @@ pfn_pte(unsigned long pfn, pgprot_t prot) | |||
| #if defined(CONFIG_PHYS_ADDR_T_64BIT) && defined(CONFIG_CPU_MIPS32) | ||||
| 
 | ||||
| /* Swap entries must have VALID and GLOBAL bits cleared. */ | ||||
| #define __swp_type(x)			(((x).val >> 2) & 0x1f) | ||||
| #define __swp_offset(x)			 ((x).val >> 7) | ||||
| #define __swp_entry(type,offset)	((swp_entry_t)	{ ((type) << 2) | ((offset) << 7) }) | ||||
| #define __swp_type(x)			(((x).val >> 4) & 0x1f) | ||||
| #define __swp_offset(x)			 ((x).val >> 9) | ||||
| #define __swp_entry(type,offset)	((swp_entry_t)  { ((type) << 4) | ((offset) << 9) }) | ||||
| #define __pte_to_swp_entry(pte)		((swp_entry_t) { (pte).pte_high }) | ||||
| #define __swp_entry_to_pte(x)		((pte_t) { 0, (x).val }) | ||||
| 
 | ||||
|  |  | |||
|  | @ -37,7 +37,11 @@ | |||
| /*
 | ||||
|  * The following bits are implemented by the TLB hardware | ||||
|  */ | ||||
| #define _PAGE_GLOBAL_SHIFT	0 | ||||
| #define _PAGE_NO_EXEC_SHIFT	0 | ||||
| #define _PAGE_NO_EXEC		(1 << _PAGE_NO_EXEC_SHIFT) | ||||
| #define _PAGE_NO_READ_SHIFT	(_PAGE_NO_EXEC_SHIFT + 1) | ||||
| #define _PAGE_NO_READ		(1 << _PAGE_NO_READ_SHIFT) | ||||
| #define _PAGE_GLOBAL_SHIFT	(_PAGE_NO_READ_SHIFT + 1) | ||||
| #define _PAGE_GLOBAL		(1 << _PAGE_GLOBAL_SHIFT) | ||||
| #define _PAGE_VALID_SHIFT	(_PAGE_GLOBAL_SHIFT + 1) | ||||
| #define _PAGE_VALID		(1 << _PAGE_VALID_SHIFT) | ||||
|  | @ -49,7 +53,7 @@ | |||
| /*
 | ||||
|  * The following bits are implemented in software | ||||
|  */ | ||||
| #define _PAGE_PRESENT_SHIFT	(_CACHE_SHIFT + 3) | ||||
| #define _PAGE_PRESENT_SHIFT	(24) | ||||
| #define _PAGE_PRESENT		(1 << _PAGE_PRESENT_SHIFT) | ||||
| #define _PAGE_READ_SHIFT	(_PAGE_PRESENT_SHIFT + 1) | ||||
| #define _PAGE_READ		(1 << _PAGE_READ_SHIFT) | ||||
|  | @ -62,6 +66,11 @@ | |||
| 
 | ||||
| #define _PFN_SHIFT		(PAGE_SHIFT - 12 + _CACHE_SHIFT + 3) | ||||
| 
 | ||||
| /*
 | ||||
|  * Bits for extended EntryLo0/EntryLo1 registers | ||||
|  */ | ||||
| #define _PFNX_MASK		0xffffff | ||||
| 
 | ||||
| #elif defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_TX39XX) | ||||
| 
 | ||||
| /*
 | ||||
|  |  | |||
|  | @ -133,7 +133,7 @@ extern void set_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *ptep, | |||
| 
 | ||||
| #if defined(CONFIG_PHYS_ADDR_T_64BIT) && defined(CONFIG_CPU_MIPS32) | ||||
| 
 | ||||
| #define pte_none(pte)		(!(((pte).pte_low | (pte).pte_high) & ~_PAGE_GLOBAL)) | ||||
| #define pte_none(pte)		(!(((pte).pte_high) & ~_PAGE_GLOBAL)) | ||||
| #define pte_present(pte)	((pte).pte_low & _PAGE_PRESENT) | ||||
| 
 | ||||
| static inline void set_pte(pte_t *ptep, pte_t pte) | ||||
|  | @ -142,16 +142,14 @@ static inline void set_pte(pte_t *ptep, pte_t pte) | |||
| 	smp_wmb(); | ||||
| 	ptep->pte_low = pte.pte_low; | ||||
| 
 | ||||
| 	if (pte.pte_low & _PAGE_GLOBAL) { | ||||
| 	if (pte.pte_high & _PAGE_GLOBAL) { | ||||
| 		pte_t *buddy = ptep_buddy(ptep); | ||||
| 		/*
 | ||||
| 		 * Make sure the buddy is global too (if it's !none, | ||||
| 		 * it better already be global) | ||||
| 		 */ | ||||
| 		if (pte_none(*buddy)) { | ||||
| 			buddy->pte_low	|= _PAGE_GLOBAL; | ||||
| 		if (pte_none(*buddy)) | ||||
| 			buddy->pte_high |= _PAGE_GLOBAL; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
|  | @ -161,8 +159,8 @@ static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *pt | |||
| 
 | ||||
| 	htw_stop(); | ||||
| 	/* Preserve global status for the pair */ | ||||
| 	if (ptep_buddy(ptep)->pte_low & _PAGE_GLOBAL) | ||||
| 		null.pte_low = null.pte_high = _PAGE_GLOBAL; | ||||
| 	if (ptep_buddy(ptep)->pte_high & _PAGE_GLOBAL) | ||||
| 		null.pte_high = _PAGE_GLOBAL; | ||||
| 
 | ||||
| 	set_pte_at(mm, addr, ptep, null); | ||||
| 	htw_start(); | ||||
|  | @ -242,21 +240,21 @@ static inline int pte_young(pte_t pte)	{ return pte.pte_low & _PAGE_ACCESSED; } | |||
| 
 | ||||
| static inline pte_t pte_wrprotect(pte_t pte) | ||||
| { | ||||
| 	pte.pte_low  &= ~(_PAGE_WRITE | _PAGE_SILENT_WRITE); | ||||
| 	pte.pte_low  &= ~_PAGE_WRITE; | ||||
| 	pte.pte_high &= ~_PAGE_SILENT_WRITE; | ||||
| 	return pte; | ||||
| } | ||||
| 
 | ||||
| static inline pte_t pte_mkclean(pte_t pte) | ||||
| { | ||||
| 	pte.pte_low  &= ~(_PAGE_MODIFIED | _PAGE_SILENT_WRITE); | ||||
| 	pte.pte_low  &= ~_PAGE_MODIFIED; | ||||
| 	pte.pte_high &= ~_PAGE_SILENT_WRITE; | ||||
| 	return pte; | ||||
| } | ||||
| 
 | ||||
| static inline pte_t pte_mkold(pte_t pte) | ||||
| { | ||||
| 	pte.pte_low  &= ~(_PAGE_ACCESSED | _PAGE_SILENT_READ); | ||||
| 	pte.pte_low  &= ~_PAGE_ACCESSED; | ||||
| 	pte.pte_high &= ~_PAGE_SILENT_READ; | ||||
| 	return pte; | ||||
| } | ||||
|  | @ -264,30 +262,24 @@ static inline pte_t pte_mkold(pte_t pte) | |||
| static inline pte_t pte_mkwrite(pte_t pte) | ||||
| { | ||||
| 	pte.pte_low |= _PAGE_WRITE; | ||||
| 	if (pte.pte_low & _PAGE_MODIFIED) { | ||||
| 		pte.pte_low  |= _PAGE_SILENT_WRITE; | ||||
| 	if (pte.pte_low & _PAGE_MODIFIED) | ||||
| 		pte.pte_high |= _PAGE_SILENT_WRITE; | ||||
| 	} | ||||
| 	return pte; | ||||
| } | ||||
| 
 | ||||
| static inline pte_t pte_mkdirty(pte_t pte) | ||||
| { | ||||
| 	pte.pte_low |= _PAGE_MODIFIED; | ||||
| 	if (pte.pte_low & _PAGE_WRITE) { | ||||
| 		pte.pte_low  |= _PAGE_SILENT_WRITE; | ||||
| 	if (pte.pte_low & _PAGE_WRITE) | ||||
| 		pte.pte_high |= _PAGE_SILENT_WRITE; | ||||
| 	} | ||||
| 	return pte; | ||||
| } | ||||
| 
 | ||||
| static inline pte_t pte_mkyoung(pte_t pte) | ||||
| { | ||||
| 	pte.pte_low |= _PAGE_ACCESSED; | ||||
| 	if (pte.pte_low & _PAGE_READ) { | ||||
| 		pte.pte_low  |= _PAGE_SILENT_READ; | ||||
| 	if (pte.pte_low & _PAGE_READ) | ||||
| 		pte.pte_high |= _PAGE_SILENT_READ; | ||||
| 	} | ||||
| 	return pte; | ||||
| } | ||||
| #else | ||||
|  | @ -391,10 +383,10 @@ static inline pgprot_t pgprot_writecombine(pgprot_t _prot) | |||
| #if defined(CONFIG_PHYS_ADDR_T_64BIT) && defined(CONFIG_CPU_MIPS32) | ||||
| static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) | ||||
| { | ||||
| 	pte.pte_low  &= _PAGE_CHG_MASK; | ||||
| 	pte.pte_low  &= (_PAGE_MODIFIED | _PAGE_ACCESSED | _PFNX_MASK); | ||||
| 	pte.pte_high &= (_PFN_MASK | _CACHE_MASK); | ||||
| 	pte.pte_low  |= pgprot_val(newprot); | ||||
| 	pte.pte_high |= pgprot_val(newprot) & ~(_PFN_MASK | _CACHE_MASK); | ||||
| 	pte.pte_low  |= pgprot_val(newprot) & ~_PFNX_MASK; | ||||
| 	pte.pte_high |= pgprot_val(newprot) & ~_PFN_MASK; | ||||
| 	return pte; | ||||
| } | ||||
| #else | ||||
|  |  | |||
|  | @ -516,6 +516,10 @@ static inline unsigned int decode_config5(struct cpuinfo_mips *c) | |||
| 		c->options |= MIPS_CPU_MAAR; | ||||
| 	if (config5 & MIPS_CONF5_LLB) | ||||
| 		c->options |= MIPS_CPU_RW_LLB; | ||||
| #ifdef CONFIG_XPA | ||||
| 	if (config5 & MIPS_CONF5_MVH) | ||||
| 		c->options |= MIPS_CPU_XPA; | ||||
| #endif | ||||
| 
 | ||||
| 	return config5 & MIPS_CONF_M; | ||||
| } | ||||
|  |  | |||
|  | @ -120,6 +120,7 @@ static int show_cpuinfo(struct seq_file *m, void *v) | |||
| 	if (cpu_has_msa)	seq_printf(m, "%s", " msa"); | ||||
| 	if (cpu_has_eva)	seq_printf(m, "%s", " eva"); | ||||
| 	if (cpu_has_htw)	seq_printf(m, "%s", " htw"); | ||||
| 	if (cpu_has_xpa)	seq_printf(m, "%s", " xpa"); | ||||
| 	seq_printf(m, "\n"); | ||||
| 
 | ||||
| 	if (cpu_has_mmips) { | ||||
|  |  | |||
|  | @ -96,7 +96,7 @@ static void *__kmap_pgprot(struct page *page, unsigned long addr, pgprot_t prot) | |||
| 	vaddr = __fix_to_virt(FIX_CMAP_END - idx); | ||||
| 	pte = mk_pte(page, prot); | ||||
| #if defined(CONFIG_PHYS_ADDR_T_64BIT) && defined(CONFIG_CPU_MIPS32) | ||||
| 	entrylo = pte.pte_high; | ||||
| 	entrylo = pte_to_entrylo(pte.pte_high); | ||||
| #else | ||||
| 	entrylo = pte_to_entrylo(pte_val(pte)); | ||||
| #endif | ||||
|  | @ -106,6 +106,11 @@ static void *__kmap_pgprot(struct page *page, unsigned long addr, pgprot_t prot) | |||
| 	write_c0_entryhi(vaddr & (PAGE_MASK << 1)); | ||||
| 	write_c0_entrylo0(entrylo); | ||||
| 	write_c0_entrylo1(entrylo); | ||||
| #ifdef CONFIG_XPA | ||||
| 	entrylo = (pte.pte_low & _PFNX_MASK); | ||||
| 	writex_c0_entrylo0(entrylo); | ||||
| 	writex_c0_entrylo1(entrylo); | ||||
| #endif | ||||
| 	tlbidx = read_c0_wired(); | ||||
| 	write_c0_wired(tlbidx + 1); | ||||
| 	write_c0_index(tlbidx); | ||||
|  |  | |||
|  | @ -333,9 +333,17 @@ void __update_tlb(struct vm_area_struct * vma, unsigned long address, pte_t pte) | |||
| 		ptep = pte_offset_map(pmdp, address); | ||||
| 
 | ||||
| #if defined(CONFIG_PHYS_ADDR_T_64BIT) && defined(CONFIG_CPU_MIPS32) | ||||
| #ifdef CONFIG_XPA | ||||
| 		write_c0_entrylo0(pte_to_entrylo(ptep->pte_high)); | ||||
| 		writex_c0_entrylo0(ptep->pte_low & _PFNX_MASK); | ||||
| 		ptep++; | ||||
| 		write_c0_entrylo1(pte_to_entrylo(ptep->pte_high)); | ||||
| 		writex_c0_entrylo1(ptep->pte_low & _PFNX_MASK); | ||||
| #else | ||||
| 		write_c0_entrylo0(ptep->pte_high); | ||||
| 		ptep++; | ||||
| 		write_c0_entrylo1(ptep->pte_high); | ||||
| #endif | ||||
| #else | ||||
| 		write_c0_entrylo0(pte_to_entrylo(pte_val(*ptep++))); | ||||
| 		write_c0_entrylo1(pte_to_entrylo(pte_val(*ptep))); | ||||
|  | @ -355,6 +363,9 @@ void __update_tlb(struct vm_area_struct * vma, unsigned long address, pte_t pte) | |||
| void add_wired_entry(unsigned long entrylo0, unsigned long entrylo1, | ||||
| 		     unsigned long entryhi, unsigned long pagemask) | ||||
| { | ||||
| #ifdef CONFIG_XPA | ||||
| 	panic("Broken for XPA kernels"); | ||||
| #else | ||||
| 	unsigned long flags; | ||||
| 	unsigned long wired; | ||||
| 	unsigned long old_pagemask; | ||||
|  | @ -383,6 +394,7 @@ void add_wired_entry(unsigned long entrylo0, unsigned long entrylo1, | |||
| 	write_c0_pagemask(old_pagemask); | ||||
| 	local_flush_tlb_all(); | ||||
| 	local_irq_restore(flags); | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| #ifdef CONFIG_TRANSPARENT_HUGEPAGE | ||||
|  |  | |||
|  | @ -35,6 +35,17 @@ | |||
| #include <asm/uasm.h> | ||||
| #include <asm/setup.h> | ||||
| 
 | ||||
| static int __cpuinitdata mips_xpa_disabled; | ||||
| 
 | ||||
| static int __init xpa_disable(char *s) | ||||
| { | ||||
| 	mips_xpa_disabled = 1; | ||||
| 
 | ||||
| 	return 1; | ||||
| } | ||||
| 
 | ||||
| __setup("noxpa", xpa_disable); | ||||
| 
 | ||||
| /*
 | ||||
|  * TLB load/store/modify handlers. | ||||
|  * | ||||
|  | @ -1027,12 +1038,27 @@ static void build_update_entries(u32 **p, unsigned int tmp, unsigned int ptep) | |||
| 	} else { | ||||
| 		int pte_off_even = sizeof(pte_t) / 2; | ||||
| 		int pte_off_odd = pte_off_even + sizeof(pte_t); | ||||
| #ifdef CONFIG_XPA | ||||
| 		const int scratch = 1; /* Our extra working register */ | ||||
| 
 | ||||
| 		/* The pte entries are pre-shifted */ | ||||
| 		uasm_i_lw(p, tmp, pte_off_even, ptep); /* get even pte */ | ||||
| 		UASM_i_MTC0(p, tmp, C0_ENTRYLO0); /* load it */ | ||||
| 		uasm_i_lw(p, ptep, pte_off_odd, ptep); /* get odd pte */ | ||||
| 		UASM_i_MTC0(p, ptep, C0_ENTRYLO1); /* load it */ | ||||
| 		uasm_i_addu(p, scratch, 0, ptep); | ||||
| #endif | ||||
| 		uasm_i_lw(p, tmp, pte_off_even, ptep); /* even pte */ | ||||
| 		uasm_i_lw(p, ptep, pte_off_odd, ptep); /* odd pte */ | ||||
| 		UASM_i_ROTR(p, tmp, tmp, ilog2(_PAGE_GLOBAL)); | ||||
| 		UASM_i_ROTR(p, ptep, ptep, ilog2(_PAGE_GLOBAL)); | ||||
| 		UASM_i_MTC0(p, tmp, C0_ENTRYLO0); | ||||
| 		UASM_i_MTC0(p, ptep, C0_ENTRYLO1); | ||||
| #ifdef CONFIG_XPA | ||||
| 		uasm_i_lw(p, tmp, 0, scratch); | ||||
| 		uasm_i_lw(p, ptep, sizeof(pte_t), scratch); | ||||
| 		uasm_i_lui(p, scratch, 0xff); | ||||
| 		uasm_i_ori(p, scratch, scratch, 0xffff); | ||||
| 		uasm_i_and(p, tmp, scratch, tmp); | ||||
| 		uasm_i_and(p, ptep, scratch, ptep); | ||||
| 		uasm_i_mthc0(p, tmp, C0_ENTRYLO0); | ||||
| 		uasm_i_mthc0(p, ptep, C0_ENTRYLO1); | ||||
| #endif | ||||
| 	} | ||||
| #else | ||||
| 	UASM_i_LW(p, tmp, 0, ptep); /* get even pte */ | ||||
|  | @ -1533,8 +1559,14 @@ iPTE_SW(u32 **p, struct uasm_reloc **r, unsigned int pte, unsigned int ptr, | |||
| { | ||||
| #ifdef CONFIG_PHYS_ADDR_T_64BIT | ||||
| 	unsigned int hwmode = mode & (_PAGE_VALID | _PAGE_DIRTY); | ||||
| #endif | ||||
| 
 | ||||
| 	if (!cpu_has_64bits) { | ||||
| 		const int scratch = 1; /* Our extra working register */ | ||||
| 
 | ||||
| 		uasm_i_lui(p, scratch, (mode >> 16)); | ||||
| 		uasm_i_or(p, pte, pte, scratch); | ||||
| 	} else | ||||
| #endif | ||||
| 	uasm_i_ori(p, pte, pte, mode); | ||||
| #ifdef CONFIG_SMP | ||||
| # ifdef CONFIG_PHYS_ADDR_T_64BIT | ||||
|  | @ -1598,15 +1630,17 @@ build_pte_present(u32 **p, struct uasm_reloc **r, | |||
| 			uasm_il_bbit0(p, r, pte, ilog2(_PAGE_PRESENT), lid); | ||||
| 			uasm_i_nop(p); | ||||
| 		} else { | ||||
| 			uasm_i_andi(p, t, pte, _PAGE_PRESENT); | ||||
| 			uasm_i_srl(p, t, pte, _PAGE_PRESENT_SHIFT); | ||||
| 			uasm_i_andi(p, t, t, 1); | ||||
| 			uasm_il_beqz(p, r, t, lid); | ||||
| 			if (pte == t) | ||||
| 				/* You lose the SMP race :-(*/ | ||||
| 				iPTE_LW(p, pte, ptr); | ||||
| 		} | ||||
| 	} else { | ||||
| 		uasm_i_andi(p, t, pte, _PAGE_PRESENT | _PAGE_READ); | ||||
| 		uasm_i_xori(p, t, t, _PAGE_PRESENT | _PAGE_READ); | ||||
| 		uasm_i_srl(p, t, pte, _PAGE_PRESENT_SHIFT); | ||||
| 		uasm_i_andi(p, t, t, 3); | ||||
| 		uasm_i_xori(p, t, t, 3); | ||||
| 		uasm_il_bnez(p, r, t, lid); | ||||
| 		if (pte == t) | ||||
| 			/* You lose the SMP race :-(*/ | ||||
|  | @ -1635,8 +1669,9 @@ build_pte_writable(u32 **p, struct uasm_reloc **r, | |||
| { | ||||
| 	int t = scratch >= 0 ? scratch : pte; | ||||
| 
 | ||||
| 	uasm_i_andi(p, t, pte, _PAGE_PRESENT | _PAGE_WRITE); | ||||
| 	uasm_i_xori(p, t, t, _PAGE_PRESENT | _PAGE_WRITE); | ||||
| 	uasm_i_srl(p, t, pte, _PAGE_PRESENT_SHIFT); | ||||
| 	uasm_i_andi(p, t, t, 5); | ||||
| 	uasm_i_xori(p, t, t, 5); | ||||
| 	uasm_il_bnez(p, r, t, lid); | ||||
| 	if (pte == t) | ||||
| 		/* You lose the SMP race :-(*/ | ||||
|  | @ -1672,7 +1707,8 @@ build_pte_modifiable(u32 **p, struct uasm_reloc **r, | |||
| 		uasm_i_nop(p); | ||||
| 	} else { | ||||
| 		int t = scratch >= 0 ? scratch : pte; | ||||
| 		uasm_i_andi(p, t, pte, _PAGE_WRITE); | ||||
| 		uasm_i_srl(p, t, pte, _PAGE_WRITE_SHIFT); | ||||
| 		uasm_i_andi(p, t, t, 1); | ||||
| 		uasm_il_beqz(p, r, t, lid); | ||||
| 		if (pte == t) | ||||
| 			/* You lose the SMP race :-(*/ | ||||
|  | @ -2285,6 +2321,11 @@ static void config_htw_params(void) | |||
| 
 | ||||
| 	pwsize = ilog2(PTRS_PER_PGD) << MIPS_PWSIZE_GDW_SHIFT; | ||||
| 	pwsize |= ilog2(PTRS_PER_PTE) << MIPS_PWSIZE_PTW_SHIFT; | ||||
| 
 | ||||
| 	/* If XPA has been enabled, PTEs are 64-bit in size. */ | ||||
| 	if (read_c0_pagegrain() & PG_ELPA) | ||||
| 		pwsize |= 1; | ||||
| 
 | ||||
| 	write_c0_pwsize(pwsize); | ||||
| 
 | ||||
| 	/* Make sure everything is set before we enable the HTW */ | ||||
|  | @ -2298,6 +2339,28 @@ static void config_htw_params(void) | |||
| 	print_htw_config(); | ||||
| } | ||||
| 
 | ||||
| static void config_xpa_params(void) | ||||
| { | ||||
| #ifdef CONFIG_XPA | ||||
| 	unsigned int pagegrain; | ||||
| 
 | ||||
| 	if (mips_xpa_disabled) { | ||||
| 		pr_info("Extended Physical Addressing (XPA) disabled\n"); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	pagegrain = read_c0_pagegrain(); | ||||
| 	write_c0_pagegrain(pagegrain | PG_ELPA); | ||||
| 	back_to_back_c0_hazard(); | ||||
| 	pagegrain = read_c0_pagegrain(); | ||||
| 
 | ||||
| 	if (pagegrain & PG_ELPA) | ||||
| 		pr_info("Extended Physical Addressing (XPA) enabled\n"); | ||||
| 	else | ||||
| 		panic("Extended Physical Addressing (XPA) disabled"); | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| void build_tlb_refill_handler(void) | ||||
| { | ||||
| 	/*
 | ||||
|  | @ -2362,8 +2425,9 @@ void build_tlb_refill_handler(void) | |||
| 		} | ||||
| 		if (cpu_has_local_ebase) | ||||
| 			build_r4000_tlb_refill_handler(); | ||||
| 		if (cpu_has_xpa) | ||||
| 			config_xpa_params(); | ||||
| 		if (cpu_has_htw) | ||||
| 			config_htw_params(); | ||||
| 
 | ||||
| 	} | ||||
| } | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Steven J. Hill
				Steven J. Hill