Skip to content

Commit c5b3678

Browse files
Steven J. Hillralfbaechle
authored andcommitted
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>
1 parent be0c37c commit c5b3678

File tree

11 files changed

+173
-44
lines changed

11 files changed

+173
-44
lines changed

arch/mips/Kconfig

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,7 @@ config MIPS_MALTA
377377
select SYS_HAS_CPU_MIPS32_R1
378378
select SYS_HAS_CPU_MIPS32_R2
379379
select SYS_HAS_CPU_MIPS32_R3_5
380+
select SYS_HAS_CPU_MIPS32_R5
380381
select SYS_HAS_CPU_MIPS32_R6
381382
select SYS_HAS_CPU_MIPS64_R1
382383
select SYS_HAS_CPU_MIPS64_R2
@@ -386,6 +387,7 @@ config MIPS_MALTA
386387
select SYS_SUPPORTS_32BIT_KERNEL
387388
select SYS_SUPPORTS_64BIT_KERNEL
388389
select SYS_SUPPORTS_BIG_ENDIAN
390+
select SYS_SUPPORTS_HIGHMEM
389391
select SYS_SUPPORTS_LITTLE_ENDIAN
390392
select SYS_SUPPORTS_MICROMIPS
391393
select SYS_SUPPORTS_MIPS_CMP
@@ -1596,6 +1598,33 @@ config CPU_MIPS32_3_5_EVA
15961598
One of its primary benefits is an increase in the maximum size
15971599
of lowmem (up to 3GB). If unsure, say 'N' here.
15981600

1601+
config CPU_MIPS32_R5_FEATURES
1602+
bool "MIPS32 Release 5 Features"
1603+
depends on SYS_HAS_CPU_MIPS32_R5
1604+
depends on CPU_MIPS32_R2
1605+
help
1606+
Choose this option to build a kernel for release 2 or later of the
1607+
MIPS32 architecture including features from release 5 such as
1608+
support for Extended Physical Addressing (XPA).
1609+
1610+
config CPU_MIPS32_R5_XPA
1611+
bool "Extended Physical Addressing (XPA)"
1612+
depends on CPU_MIPS32_R5_FEATURES
1613+
depends on !EVA
1614+
depends on !PAGE_SIZE_4KB
1615+
depends on SYS_SUPPORTS_HIGHMEM
1616+
select XPA
1617+
select HIGHMEM
1618+
select ARCH_PHYS_ADDR_T_64BIT
1619+
default n
1620+
help
1621+
Choose this option if you want to enable the Extended Physical
1622+
Addressing (XPA) on your MIPS32 core (such as P5600 series). The
1623+
benefit is to increase physical addressing equal to or greater
1624+
than 40 bits. Note that this has the side effect of turning on
1625+
64-bit addressing which in turn makes the PTEs 64-bit in size.
1626+
If unsure, say 'N' here.
1627+
15991628
if CPU_LOONGSON2F
16001629
config CPU_NOP_WORKAROUNDS
16011630
bool
@@ -1699,6 +1728,9 @@ config SYS_HAS_CPU_MIPS32_R2
16991728
config SYS_HAS_CPU_MIPS32_R3_5
17001729
bool
17011730

1731+
config SYS_HAS_CPU_MIPS32_R5
1732+
bool
1733+
17021734
config SYS_HAS_CPU_MIPS32_R6
17031735
bool
17041736

@@ -1836,6 +1868,9 @@ config CPU_MIPSR6
18361868
config EVA
18371869
bool
18381870

1871+
config XPA
1872+
bool
1873+
18391874
config SYS_SUPPORTS_32BIT_KERNEL
18401875
bool
18411876
config SYS_SUPPORTS_64BIT_KERNEL

arch/mips/include/asm/cpu-features.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,9 @@
139139
# endif
140140
#endif
141141

142+
#ifndef cpu_has_xpa
143+
#define cpu_has_xpa (cpu_data[0].options & MIPS_CPU_XPA)
144+
#endif
142145
#ifndef cpu_has_vtag_icache
143146
#define cpu_has_vtag_icache (cpu_data[0].icache.flags & MIPS_CACHE_VTAG)
144147
#endif

arch/mips/include/asm/cpu.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,7 @@ enum cpu_type_enum {
377377
#define MIPS_CPU_MAAR 0x400000000ull /* MAAR(I) registers are present */
378378
#define MIPS_CPU_FRE 0x800000000ull /* FRE & UFE bits implemented */
379379
#define MIPS_CPU_RW_LLB 0x1000000000ull /* LLADDR/LLB writes are allowed */
380+
#define MIPS_CPU_XPA 0x2000000000ull /* CPU supports Extended Physical Addressing */
380381

381382
/*
382383
* CPU ASE encodings

arch/mips/include/asm/pgtable-32.h

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -105,13 +105,16 @@ static inline void pmd_clear(pmd_t *pmdp)
105105

106106
#if defined(CONFIG_PHYS_ADDR_T_64BIT) && defined(CONFIG_CPU_MIPS32)
107107
#define pte_page(x) pfn_to_page(pte_pfn(x))
108-
#define pte_pfn(x) ((unsigned long)((x).pte_high >> 6))
108+
#define pte_pfn(x) (((unsigned long)((x).pte_high >> _PFN_SHIFT)) | (unsigned long)((x).pte_low << _PAGE_PRESENT_SHIFT))
109109
static inline pte_t
110110
pfn_pte(unsigned long pfn, pgprot_t prot)
111111
{
112112
pte_t pte;
113-
pte.pte_high = (pfn << 6) | (pgprot_val(prot) & 0x3f);
114-
pte.pte_low = pgprot_val(prot);
113+
114+
pte.pte_low = (pfn >> _PAGE_PRESENT_SHIFT) |
115+
(pgprot_val(prot) & ~_PFNX_MASK);
116+
pte.pte_high = (pfn << _PFN_SHIFT) |
117+
(pgprot_val(prot) & ~_PFN_MASK);
115118
return pte;
116119
}
117120

@@ -166,9 +169,9 @@ pfn_pte(unsigned long pfn, pgprot_t prot)
166169
#if defined(CONFIG_PHYS_ADDR_T_64BIT) && defined(CONFIG_CPU_MIPS32)
167170

168171
/* Swap entries must have VALID and GLOBAL bits cleared. */
169-
#define __swp_type(x) (((x).val >> 2) & 0x1f)
170-
#define __swp_offset(x) ((x).val >> 7)
171-
#define __swp_entry(type,offset) ((swp_entry_t) { ((type) << 2) | ((offset) << 7) })
172+
#define __swp_type(x) (((x).val >> 4) & 0x1f)
173+
#define __swp_offset(x) ((x).val >> 9)
174+
#define __swp_entry(type,offset) ((swp_entry_t) { ((type) << 4) | ((offset) << 9) })
172175
#define __pte_to_swp_entry(pte) ((swp_entry_t) { (pte).pte_high })
173176
#define __swp_entry_to_pte(x) ((pte_t) { 0, (x).val })
174177

arch/mips/include/asm/pgtable-bits.h

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,11 @@
3737
/*
3838
* The following bits are implemented by the TLB hardware
3939
*/
40-
#define _PAGE_GLOBAL_SHIFT 0
40+
#define _PAGE_NO_EXEC_SHIFT 0
41+
#define _PAGE_NO_EXEC (1 << _PAGE_NO_EXEC_SHIFT)
42+
#define _PAGE_NO_READ_SHIFT (_PAGE_NO_EXEC_SHIFT + 1)
43+
#define _PAGE_NO_READ (1 << _PAGE_NO_READ_SHIFT)
44+
#define _PAGE_GLOBAL_SHIFT (_PAGE_NO_READ_SHIFT + 1)
4145
#define _PAGE_GLOBAL (1 << _PAGE_GLOBAL_SHIFT)
4246
#define _PAGE_VALID_SHIFT (_PAGE_GLOBAL_SHIFT + 1)
4347
#define _PAGE_VALID (1 << _PAGE_VALID_SHIFT)
@@ -49,7 +53,7 @@
4953
/*
5054
* The following bits are implemented in software
5155
*/
52-
#define _PAGE_PRESENT_SHIFT (_CACHE_SHIFT + 3)
56+
#define _PAGE_PRESENT_SHIFT (24)
5357
#define _PAGE_PRESENT (1 << _PAGE_PRESENT_SHIFT)
5458
#define _PAGE_READ_SHIFT (_PAGE_PRESENT_SHIFT + 1)
5559
#define _PAGE_READ (1 << _PAGE_READ_SHIFT)
@@ -62,6 +66,11 @@
6266

6367
#define _PFN_SHIFT (PAGE_SHIFT - 12 + _CACHE_SHIFT + 3)
6468

69+
/*
70+
* Bits for extended EntryLo0/EntryLo1 registers
71+
*/
72+
#define _PFNX_MASK 0xffffff
73+
6574
#elif defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_TX39XX)
6675

6776
/*

arch/mips/include/asm/pgtable.h

Lines changed: 14 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ extern void set_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *ptep,
133133

134134
#if defined(CONFIG_PHYS_ADDR_T_64BIT) && defined(CONFIG_CPU_MIPS32)
135135

136-
#define pte_none(pte) (!(((pte).pte_low | (pte).pte_high) & ~_PAGE_GLOBAL))
136+
#define pte_none(pte) (!(((pte).pte_high) & ~_PAGE_GLOBAL))
137137
#define pte_present(pte) ((pte).pte_low & _PAGE_PRESENT)
138138

139139
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)
142142
smp_wmb();
143143
ptep->pte_low = pte.pte_low;
144144

145-
if (pte.pte_low & _PAGE_GLOBAL) {
145+
if (pte.pte_high & _PAGE_GLOBAL) {
146146
pte_t *buddy = ptep_buddy(ptep);
147147
/*
148148
* Make sure the buddy is global too (if it's !none,
149149
* it better already be global)
150150
*/
151-
if (pte_none(*buddy)) {
152-
buddy->pte_low |= _PAGE_GLOBAL;
151+
if (pte_none(*buddy))
153152
buddy->pte_high |= _PAGE_GLOBAL;
154-
}
155153
}
156154
}
157155

@@ -161,8 +159,8 @@ static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *pt
161159

162160
htw_stop();
163161
/* Preserve global status for the pair */
164-
if (ptep_buddy(ptep)->pte_low & _PAGE_GLOBAL)
165-
null.pte_low = null.pte_high = _PAGE_GLOBAL;
162+
if (ptep_buddy(ptep)->pte_high & _PAGE_GLOBAL)
163+
null.pte_high = _PAGE_GLOBAL;
166164

167165
set_pte_at(mm, addr, ptep, null);
168166
htw_start();
@@ -242,52 +240,46 @@ static inline int pte_young(pte_t pte) { return pte.pte_low & _PAGE_ACCESSED; }
242240

243241
static inline pte_t pte_wrprotect(pte_t pte)
244242
{
245-
pte.pte_low &= ~(_PAGE_WRITE | _PAGE_SILENT_WRITE);
243+
pte.pte_low &= ~_PAGE_WRITE;
246244
pte.pte_high &= ~_PAGE_SILENT_WRITE;
247245
return pte;
248246
}
249247

250248
static inline pte_t pte_mkclean(pte_t pte)
251249
{
252-
pte.pte_low &= ~(_PAGE_MODIFIED | _PAGE_SILENT_WRITE);
250+
pte.pte_low &= ~_PAGE_MODIFIED;
253251
pte.pte_high &= ~_PAGE_SILENT_WRITE;
254252
return pte;
255253
}
256254

257255
static inline pte_t pte_mkold(pte_t pte)
258256
{
259-
pte.pte_low &= ~(_PAGE_ACCESSED | _PAGE_SILENT_READ);
257+
pte.pte_low &= ~_PAGE_ACCESSED;
260258
pte.pte_high &= ~_PAGE_SILENT_READ;
261259
return pte;
262260
}
263261

264262
static inline pte_t pte_mkwrite(pte_t pte)
265263
{
266264
pte.pte_low |= _PAGE_WRITE;
267-
if (pte.pte_low & _PAGE_MODIFIED) {
268-
pte.pte_low |= _PAGE_SILENT_WRITE;
265+
if (pte.pte_low & _PAGE_MODIFIED)
269266
pte.pte_high |= _PAGE_SILENT_WRITE;
270-
}
271267
return pte;
272268
}
273269

274270
static inline pte_t pte_mkdirty(pte_t pte)
275271
{
276272
pte.pte_low |= _PAGE_MODIFIED;
277-
if (pte.pte_low & _PAGE_WRITE) {
278-
pte.pte_low |= _PAGE_SILENT_WRITE;
273+
if (pte.pte_low & _PAGE_WRITE)
279274
pte.pte_high |= _PAGE_SILENT_WRITE;
280-
}
281275
return pte;
282276
}
283277

284278
static inline pte_t pte_mkyoung(pte_t pte)
285279
{
286280
pte.pte_low |= _PAGE_ACCESSED;
287-
if (pte.pte_low & _PAGE_READ) {
288-
pte.pte_low |= _PAGE_SILENT_READ;
281+
if (pte.pte_low & _PAGE_READ)
289282
pte.pte_high |= _PAGE_SILENT_READ;
290-
}
291283
return pte;
292284
}
293285
#else
@@ -391,10 +383,10 @@ static inline pgprot_t pgprot_writecombine(pgprot_t _prot)
391383
#if defined(CONFIG_PHYS_ADDR_T_64BIT) && defined(CONFIG_CPU_MIPS32)
392384
static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
393385
{
394-
pte.pte_low &= _PAGE_CHG_MASK;
386+
pte.pte_low &= (_PAGE_MODIFIED | _PAGE_ACCESSED | _PFNX_MASK);
395387
pte.pte_high &= (_PFN_MASK | _CACHE_MASK);
396-
pte.pte_low |= pgprot_val(newprot);
397-
pte.pte_high |= pgprot_val(newprot) & ~(_PFN_MASK | _CACHE_MASK);
388+
pte.pte_low |= pgprot_val(newprot) & ~_PFNX_MASK;
389+
pte.pte_high |= pgprot_val(newprot) & ~_PFN_MASK;
398390
return pte;
399391
}
400392
#else

arch/mips/kernel/cpu-probe.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -516,6 +516,10 @@ static inline unsigned int decode_config5(struct cpuinfo_mips *c)
516516
c->options |= MIPS_CPU_MAAR;
517517
if (config5 & MIPS_CONF5_LLB)
518518
c->options |= MIPS_CPU_RW_LLB;
519+
#ifdef CONFIG_XPA
520+
if (config5 & MIPS_CONF5_MVH)
521+
c->options |= MIPS_CPU_XPA;
522+
#endif
519523

520524
return config5 & MIPS_CONF_M;
521525
}

arch/mips/kernel/proc.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ static int show_cpuinfo(struct seq_file *m, void *v)
120120
if (cpu_has_msa) seq_printf(m, "%s", " msa");
121121
if (cpu_has_eva) seq_printf(m, "%s", " eva");
122122
if (cpu_has_htw) seq_printf(m, "%s", " htw");
123+
if (cpu_has_xpa) seq_printf(m, "%s", " xpa");
123124
seq_printf(m, "\n");
124125

125126
if (cpu_has_mmips) {

arch/mips/mm/init.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ static void *__kmap_pgprot(struct page *page, unsigned long addr, pgprot_t prot)
9696
vaddr = __fix_to_virt(FIX_CMAP_END - idx);
9797
pte = mk_pte(page, prot);
9898
#if defined(CONFIG_PHYS_ADDR_T_64BIT) && defined(CONFIG_CPU_MIPS32)
99-
entrylo = pte.pte_high;
99+
entrylo = pte_to_entrylo(pte.pte_high);
100100
#else
101101
entrylo = pte_to_entrylo(pte_val(pte));
102102
#endif
@@ -106,6 +106,11 @@ static void *__kmap_pgprot(struct page *page, unsigned long addr, pgprot_t prot)
106106
write_c0_entryhi(vaddr & (PAGE_MASK << 1));
107107
write_c0_entrylo0(entrylo);
108108
write_c0_entrylo1(entrylo);
109+
#ifdef CONFIG_XPA
110+
entrylo = (pte.pte_low & _PFNX_MASK);
111+
writex_c0_entrylo0(entrylo);
112+
writex_c0_entrylo1(entrylo);
113+
#endif
109114
tlbidx = read_c0_wired();
110115
write_c0_wired(tlbidx + 1);
111116
write_c0_index(tlbidx);

arch/mips/mm/tlb-r4k.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -333,9 +333,17 @@ void __update_tlb(struct vm_area_struct * vma, unsigned long address, pte_t pte)
333333
ptep = pte_offset_map(pmdp, address);
334334

335335
#if defined(CONFIG_PHYS_ADDR_T_64BIT) && defined(CONFIG_CPU_MIPS32)
336+
#ifdef CONFIG_XPA
337+
write_c0_entrylo0(pte_to_entrylo(ptep->pte_high));
338+
writex_c0_entrylo0(ptep->pte_low & _PFNX_MASK);
339+
ptep++;
340+
write_c0_entrylo1(pte_to_entrylo(ptep->pte_high));
341+
writex_c0_entrylo1(ptep->pte_low & _PFNX_MASK);
342+
#else
336343
write_c0_entrylo0(ptep->pte_high);
337344
ptep++;
338345
write_c0_entrylo1(ptep->pte_high);
346+
#endif
339347
#else
340348
write_c0_entrylo0(pte_to_entrylo(pte_val(*ptep++)));
341349
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)
355363
void add_wired_entry(unsigned long entrylo0, unsigned long entrylo1,
356364
unsigned long entryhi, unsigned long pagemask)
357365
{
366+
#ifdef CONFIG_XPA
367+
panic("Broken for XPA kernels");
368+
#else
358369
unsigned long flags;
359370
unsigned long wired;
360371
unsigned long old_pagemask;
@@ -383,6 +394,7 @@ void add_wired_entry(unsigned long entrylo0, unsigned long entrylo1,
383394
write_c0_pagemask(old_pagemask);
384395
local_flush_tlb_all();
385396
local_irq_restore(flags);
397+
#endif
386398
}
387399

388400
#ifdef CONFIG_TRANSPARENT_HUGEPAGE

0 commit comments

Comments
 (0)