aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc/mm/init_64.c
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/mm/init_64.c
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/mm/init_64.c')
-rw-r--r--arch/sparc/mm/init_64.c92
1 files changed, 92 insertions, 0 deletions
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 *