aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2013-09-21 00:50:41 -0400
committerDavid S. Miller <davem@davemloft.net>2013-11-12 18:22:34 -0500
commitb2d438348024b75a1ee8b66b85d77f569a5dfed8 (patch)
tree057c725d9d058d326533d0947aedd226adb57540 /arch/sparc
parentf998c9c0d663b013e3aa3ba78908396c8c497218 (diff)
sparc64: Make PAGE_OFFSET variable.
Choose PAGE_OFFSET dynamically based upon cpu type. Original UltraSPARC-I (spitfire) chips only supported a 44-bit virtual address space. Newer chips (T4 and later) support 52-bit virtual addresses and up to 47-bits of physical memory space. Therefore we have to adjust PAGE_SIZE dynamically based upon the capabilities of the chip. Note that this change alone does not allow us to support > 43-bit physical memory, to do that we need to re-arrange our page table support. The current encodings of the pmd_t and pgd_t pointers restricts us to "32 + 11" == 43 bits. This change can waste quite a bit of memory for the various tables. In particular, a future change should work to size and allocate kern_linear_bitmap[] and sparc64_valid_addr_bitmap[] dynamically. This isn't easy as we really cannot take a TLB miss when accessing kern_linear_bitmap[]. We'd have to lock it into the TLB or similar. Signed-off-by: David S. Miller <davem@davemloft.net> Acked-by: Bob Picco <bob.picco@oracle.com>
Diffstat (limited to 'arch/sparc')
-rw-r--r--arch/sparc/include/asm/page_64.h20
-rw-r--r--arch/sparc/kernel/ktlb.S30
-rw-r--r--arch/sparc/kernel/vmlinux.lds.S5
-rw-r--r--arch/sparc/lib/clear_page.S4
-rw-r--r--arch/sparc/lib/copy_page.S4
-rw-r--r--arch/sparc/mm/init_64.c92
-rw-r--r--arch/sparc/mm/ultra.S12
7 files changed, 138 insertions, 29 deletions
diff --git a/arch/sparc/include/asm/page_64.h b/arch/sparc/include/asm/page_64.h
index 978ea6d022e9..89e07fd0ac88 100644
--- a/arch/sparc/include/asm/page_64.h
+++ b/arch/sparc/include/asm/page_64.h
@@ -112,24 +112,16 @@ typedef pte_t *pgtable_t;
112 112
113#include <asm-generic/memory_model.h> 113#include <asm-generic/memory_model.h>
114 114
115#endif /* !(__ASSEMBLY__) */
116
117/* We used to stick this into a hard-coded global register (%g4)
118 * but that does not make sense anymore.
119 */
120#define MAX_SUPPORTED_PA_BITS 43
121#define PAGE_OFFSET_BY_BITS(X) (-(_AC(1,UL) << (X))) 115#define PAGE_OFFSET_BY_BITS(X) (-(_AC(1,UL) << (X)))
122#define PAGE_OFFSET PAGE_OFFSET_BY_BITS(MAX_SUPPORTED_PA_BITS) 116extern unsigned long PAGE_OFFSET;
123 117
124/* The "virtual" portion of PAGE_OFFSET, used to clip off the non-physical 118#endif /* !(__ASSEMBLY__) */
125 * bits of a linear kernel address.
126 */
127#define PAGE_OFFSET_VA_BITS (64 - MAX_SUPPORTED_PA_BITS)
128 119
129/* The actual number of physical memory address bits we support, this is 120/* The maximum number of physical memory address bits we support, this
130 * used to size various tables used to manage kernel TLB misses. 121 * is used to size various tables used to manage kernel TLB misses and
122 * also the sparsemem code.
131 */ 123 */
132#define MAX_PHYS_ADDRESS_BITS 41 124#define MAX_PHYS_ADDRESS_BITS 47
133 125
134/* These two shift counts are used when indexing sparc64_valid_addr_bitmap 126/* These two shift counts are used when indexing sparc64_valid_addr_bitmap
135 * and kpte_linear_bitmap. 127 * and kpte_linear_bitmap.
diff --git a/arch/sparc/kernel/ktlb.S b/arch/sparc/kernel/ktlb.S
index 7ad46bc0c698..542e96ac4d39 100644
--- a/arch/sparc/kernel/ktlb.S
+++ b/arch/sparc/kernel/ktlb.S
@@ -153,12 +153,19 @@ kvmap_dtlb_tsb4m_miss:
153 /* Clear the PAGE_OFFSET top virtual bits, shift 153 /* Clear the PAGE_OFFSET top virtual bits, shift
154 * down to get PFN, and make sure PFN is in range. 154 * down to get PFN, and make sure PFN is in range.
155 */ 155 */
156 sllx %g4, PAGE_OFFSET_VA_BITS, %g5 156661: sllx %g4, 0, %g5
157 .section .page_offset_shift_patch, "ax"
158 .word 661b
159 .previous
157 160
158 /* Check to see if we know about valid memory at the 4MB 161 /* Check to see if we know about valid memory at the 4MB
159 * chunk this physical address will reside within. 162 * chunk this physical address will reside within.
160 */ 163 */
161 srlx %g5, PAGE_OFFSET_VA_BITS + MAX_PHYS_ADDRESS_BITS, %g2 164661: srlx %g5, MAX_PHYS_ADDRESS_BITS, %g2
165 .section .page_offset_shift_patch, "ax"
166 .word 661b
167 .previous
168
162 brnz,pn %g2, kvmap_dtlb_longpath 169 brnz,pn %g2, kvmap_dtlb_longpath
163 nop 170 nop
164 171
@@ -176,7 +183,11 @@ valid_addr_bitmap_patch:
176 or %g7, %lo(sparc64_valid_addr_bitmap), %g7 183 or %g7, %lo(sparc64_valid_addr_bitmap), %g7
177 .previous 184 .previous
178 185
179 srlx %g5, PAGE_OFFSET_VA_BITS + ILOG2_4MB, %g2 186661: srlx %g5, ILOG2_4MB, %g2
187 .section .page_offset_shift_patch, "ax"
188 .word 661b
189 .previous
190
180 srlx %g2, 6, %g5 191 srlx %g2, 6, %g5
181 and %g2, 63, %g2 192 and %g2, 63, %g2
182 sllx %g5, 3, %g5 193 sllx %g5, 3, %g5
@@ -189,9 +200,18 @@ valid_addr_bitmap_patch:
1892: sethi %hi(kpte_linear_bitmap), %g2 2002: sethi %hi(kpte_linear_bitmap), %g2
190 201
191 /* Get the 256MB physical address index. */ 202 /* Get the 256MB physical address index. */
192 sllx %g4, PAGE_OFFSET_VA_BITS, %g5 203661: sllx %g4, 0, %g5
204 .section .page_offset_shift_patch, "ax"
205 .word 661b
206 .previous
207
193 or %g2, %lo(kpte_linear_bitmap), %g2 208 or %g2, %lo(kpte_linear_bitmap), %g2
194 srlx %g5, PAGE_OFFSET_VA_BITS + ILOG2_256MB, %g5 209
210661: srlx %g5, ILOG2_256MB, %g5
211 .section .page_offset_shift_patch, "ax"
212 .word 661b
213 .previous
214
195 and %g5, (32 - 1), %g7 215 and %g5, (32 - 1), %g7
196 216
197 /* Divide by 32 to get the offset into the bitmask. */ 217 /* Divide by 32 to get the offset into the bitmask. */
diff --git a/arch/sparc/kernel/vmlinux.lds.S b/arch/sparc/kernel/vmlinux.lds.S
index 0bacceb19150..932ff90fd760 100644
--- a/arch/sparc/kernel/vmlinux.lds.S
+++ b/arch/sparc/kernel/vmlinux.lds.S
@@ -122,6 +122,11 @@ SECTIONS
122 *(.swapper_4m_tsb_phys_patch) 122 *(.swapper_4m_tsb_phys_patch)
123 __swapper_4m_tsb_phys_patch_end = .; 123 __swapper_4m_tsb_phys_patch_end = .;
124 } 124 }
125 .page_offset_shift_patch : {
126 __page_offset_shift_patch = .;
127 *(.page_offset_shift_patch)
128 __page_offset_shift_patch_end = .;
129 }
125 .popc_3insn_patch : { 130 .popc_3insn_patch : {
126 __popc_3insn_patch = .; 131 __popc_3insn_patch = .;
127 *(.popc_3insn_patch) 132 *(.popc_3insn_patch)
diff --git a/arch/sparc/lib/clear_page.S b/arch/sparc/lib/clear_page.S
index 77e531f6c2a7..46272dfc26e8 100644
--- a/arch/sparc/lib/clear_page.S
+++ b/arch/sparc/lib/clear_page.S
@@ -37,10 +37,10 @@ _clear_page: /* %o0=dest */
37 .globl clear_user_page 37 .globl clear_user_page
38clear_user_page: /* %o0=dest, %o1=vaddr */ 38clear_user_page: /* %o0=dest, %o1=vaddr */
39 lduw [%g6 + TI_PRE_COUNT], %o2 39 lduw [%g6 + TI_PRE_COUNT], %o2
40 sethi %uhi(PAGE_OFFSET), %g2 40 sethi %hi(PAGE_OFFSET), %g2
41 sethi %hi(PAGE_SIZE), %o4 41 sethi %hi(PAGE_SIZE), %o4
42 42
43 sllx %g2, 32, %g2 43 ldx [%g2 + %lo(PAGE_OFFSET)], %g2
44 sethi %hi(PAGE_KERNEL_LOCKED), %g3 44 sethi %hi(PAGE_KERNEL_LOCKED), %g3
45 45
46 ldx [%g3 + %lo(PAGE_KERNEL_LOCKED)], %g3 46 ldx [%g3 + %lo(PAGE_KERNEL_LOCKED)], %g3
diff --git a/arch/sparc/lib/copy_page.S b/arch/sparc/lib/copy_page.S
index 4d2df328e514..dd16c61f3263 100644
--- a/arch/sparc/lib/copy_page.S
+++ b/arch/sparc/lib/copy_page.S
@@ -46,10 +46,10 @@
46 .type copy_user_page,#function 46 .type copy_user_page,#function
47copy_user_page: /* %o0=dest, %o1=src, %o2=vaddr */ 47copy_user_page: /* %o0=dest, %o1=src, %o2=vaddr */
48 lduw [%g6 + TI_PRE_COUNT], %o4 48 lduw [%g6 + TI_PRE_COUNT], %o4
49 sethi %uhi(PAGE_OFFSET), %g2 49 sethi %hi(PAGE_OFFSET), %g2
50 sethi %hi(PAGE_SIZE), %o3 50 sethi %hi(PAGE_SIZE), %o3
51 51
52 sllx %g2, 32, %g2 52 ldx [%g2 + %lo(PAGE_OFFSET)], %g2
53 sethi %hi(PAGE_KERNEL_LOCKED), %g3 53 sethi %hi(PAGE_KERNEL_LOCKED), %g3
54 54
55 ldx [%g3 + %lo(PAGE_KERNEL_LOCKED)], %g3 55 ldx [%g3 + %lo(PAGE_KERNEL_LOCKED)], %g3
diff --git a/arch/sparc/mm/init_64.c b/arch/sparc/mm/init_64.c
index e295a5b30ac9..7a97b5a28b4b 100644
--- a/arch/sparc/mm/init_64.c
+++ b/arch/sparc/mm/init_64.c
@@ -1557,6 +1557,96 @@ unsigned long __init find_ecache_flush_span(unsigned long size)
1557 return ~0UL; 1557 return ~0UL;
1558} 1558}
1559 1559
1560unsigned long PAGE_OFFSET;
1561EXPORT_SYMBOL(PAGE_OFFSET);
1562
1563static void __init page_offset_shift_patch_one(unsigned int *insn, unsigned long phys_bits)
1564{
1565 unsigned long final_shift;
1566 unsigned int val = *insn;
1567 unsigned int cnt;
1568
1569 /* We are patching in ilog2(max_supported_phys_address), and
1570 * we are doing so in a manner similar to a relocation addend.
1571 * That is, we are adding the shift value to whatever value
1572 * is in the shift instruction count field already.
1573 */
1574 cnt = (val & 0x3f);
1575 val &= ~0x3f;
1576
1577 /* If we are trying to shift >= 64 bits, clear the destination
1578 * register. This can happen when phys_bits ends up being equal
1579 * to MAX_PHYS_ADDRESS_BITS.
1580 */
1581 final_shift = (cnt + (64 - phys_bits));
1582 if (final_shift >= 64) {
1583 unsigned int rd = (val >> 25) & 0x1f;
1584
1585 val = 0x80100000 | (rd << 25);
1586 } else {
1587 val |= final_shift;
1588 }
1589 *insn = val;
1590
1591 __asm__ __volatile__("flush %0"
1592 : /* no outputs */
1593 : "r" (insn));
1594}
1595
1596static void __init page_offset_shift_patch(unsigned long phys_bits)
1597{
1598 extern unsigned int __page_offset_shift_patch;
1599 extern unsigned int __page_offset_shift_patch_end;
1600 unsigned int *p;
1601
1602 p = &__page_offset_shift_patch;
1603 while (p < &__page_offset_shift_patch_end) {
1604 unsigned int *insn = (unsigned int *)(unsigned long)*p;
1605
1606 page_offset_shift_patch_one(insn, phys_bits);
1607
1608 p++;
1609 }
1610}
1611
1612static void __init setup_page_offset(void)
1613{
1614 unsigned long max_phys_bits = 40;
1615
1616 if (tlb_type == cheetah || tlb_type == cheetah_plus) {
1617 max_phys_bits = 42;
1618 } else if (tlb_type == hypervisor) {
1619 switch (sun4v_chip_type) {
1620 case SUN4V_CHIP_NIAGARA1:
1621 case SUN4V_CHIP_NIAGARA2:
1622 max_phys_bits = 39;
1623 break;
1624 case SUN4V_CHIP_NIAGARA3:
1625 max_phys_bits = 43;
1626 break;
1627 case SUN4V_CHIP_NIAGARA4:
1628 case SUN4V_CHIP_NIAGARA5:
1629 case SUN4V_CHIP_SPARC64X:
1630 default:
1631 max_phys_bits = 47;
1632 break;
1633 }
1634 }
1635
1636 if (max_phys_bits > MAX_PHYS_ADDRESS_BITS) {
1637 prom_printf("MAX_PHYS_ADDRESS_BITS is too small, need %lu\n",
1638 max_phys_bits);
1639 prom_halt();
1640 }
1641
1642 PAGE_OFFSET = PAGE_OFFSET_BY_BITS(max_phys_bits);
1643
1644 pr_info("PAGE_OFFSET is 0x%016lx (max_phys_bits == %lu)\n",
1645 PAGE_OFFSET, max_phys_bits);
1646
1647 page_offset_shift_patch(max_phys_bits);
1648}
1649
1560static void __init tsb_phys_patch(void) 1650static void __init tsb_phys_patch(void)
1561{ 1651{
1562 struct tsb_ldquad_phys_patch_entry *pquad; 1652 struct tsb_ldquad_phys_patch_entry *pquad;
@@ -1763,6 +1853,8 @@ void __init paging_init(void)
1763 unsigned long real_end, i; 1853 unsigned long real_end, i;
1764 int node; 1854 int node;
1765 1855
1856 setup_page_offset();
1857
1766 /* These build time checkes make sure that the dcache_dirty_cpu() 1858 /* These build time checkes make sure that the dcache_dirty_cpu()
1767 * page->flags usage will work. 1859 * page->flags usage will work.
1768 * 1860 *
diff --git a/arch/sparc/mm/ultra.S b/arch/sparc/mm/ultra.S
index 432aa0cb1b38..b4f4733abc6e 100644
--- a/arch/sparc/mm/ultra.S
+++ b/arch/sparc/mm/ultra.S
@@ -153,10 +153,10 @@ __spitfire_flush_tlb_mm_slow:
153 .globl __flush_icache_page 153 .globl __flush_icache_page
154__flush_icache_page: /* %o0 = phys_page */ 154__flush_icache_page: /* %o0 = phys_page */
155 srlx %o0, PAGE_SHIFT, %o0 155 srlx %o0, PAGE_SHIFT, %o0
156 sethi %uhi(PAGE_OFFSET), %g1 156 sethi %hi(PAGE_OFFSET), %g1
157 sllx %o0, PAGE_SHIFT, %o0 157 sllx %o0, PAGE_SHIFT, %o0
158 sethi %hi(PAGE_SIZE), %g2 158 sethi %hi(PAGE_SIZE), %g2
159 sllx %g1, 32, %g1 159 ldx [%g1 + %lo(PAGE_OFFSET)], %g1
160 add %o0, %g1, %o0 160 add %o0, %g1, %o0
1611: subcc %g2, 32, %g2 1611: subcc %g2, 32, %g2
162 bne,pt %icc, 1b 162 bne,pt %icc, 1b
@@ -178,8 +178,8 @@ __flush_icache_page: /* %o0 = phys_page */
178 .align 64 178 .align 64
179 .globl __flush_dcache_page 179 .globl __flush_dcache_page
180__flush_dcache_page: /* %o0=kaddr, %o1=flush_icache */ 180__flush_dcache_page: /* %o0=kaddr, %o1=flush_icache */
181 sethi %uhi(PAGE_OFFSET), %g1 181 sethi %hi(PAGE_OFFSET), %g1
182 sllx %g1, 32, %g1 182 ldx [%g1 + %lo(PAGE_OFFSET)], %g1
183 sub %o0, %g1, %o0 ! physical address 183 sub %o0, %g1, %o0 ! physical address
184 srlx %o0, 11, %o0 ! make D-cache TAG 184 srlx %o0, 11, %o0 ! make D-cache TAG
185 sethi %hi(1 << 14), %o2 ! D-cache size 185 sethi %hi(1 << 14), %o2 ! D-cache size
@@ -287,8 +287,8 @@ __cheetah_flush_tlb_pending: /* 27 insns */
287 287
288#ifdef DCACHE_ALIASING_POSSIBLE 288#ifdef DCACHE_ALIASING_POSSIBLE
289__cheetah_flush_dcache_page: /* 11 insns */ 289__cheetah_flush_dcache_page: /* 11 insns */
290 sethi %uhi(PAGE_OFFSET), %g1 290 sethi %hi(PAGE_OFFSET), %g1
291 sllx %g1, 32, %g1 291 ldx [%g1 + %lo(PAGE_OFFSET)], %g1
292 sub %o0, %g1, %o0 292 sub %o0, %g1, %o0
293 sethi %hi(PAGE_SIZE), %o4 293 sethi %hi(PAGE_SIZE), %o4
2941: subcc %o4, (1 << 5), %o4 2941: subcc %o4, (1 << 5), %o4