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