diff options
author | David S. Miller <davem@davemloft.net> | 2013-09-21 00:50:41 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-11-12 18:22:34 -0500 |
commit | b2d438348024b75a1ee8b66b85d77f569a5dfed8 (patch) | |
tree | 057c725d9d058d326533d0947aedd226adb57540 /arch/sparc/mm/init_64.c | |
parent | f998c9c0d663b013e3aa3ba78908396c8c497218 (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.c | 92 |
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 | ||
1560 | unsigned long PAGE_OFFSET; | ||
1561 | EXPORT_SYMBOL(PAGE_OFFSET); | ||
1562 | |||
1563 | static 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 | |||
1596 | static 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 | |||
1612 | static 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 | |||
1560 | static void __init tsb_phys_patch(void) | 1650 | static 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 | * |