Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[RFC] [FOR TESTING] MIPS 32-bit huge page support (moved,updated, and rebased) #3

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions arch/mips/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ config MIPS
select HAVE_ARCH_MMAP_RND_COMPAT_BITS if MMU && COMPAT
select HAVE_ARCH_SECCOMP_FILTER
select HAVE_ARCH_TRACEHOOK
select HAVE_ARCH_TRANSPARENT_HUGEPAGE if CPU_SUPPORTS_HUGEPAGES && 64BIT
select HAVE_ARCH_TRANSPARENT_HUGEPAGE if CPU_SUPPORTS_HUGEPAGES
select HAVE_CBPF_JIT if (!64BIT && !CPU_MICROMIPS)
select HAVE_EBPF_JIT if (64BIT && !CPU_MICROMIPS)
select HAVE_CONTEXT_TRACKING
Expand Down Expand Up @@ -384,6 +384,7 @@ config MACH_INGENIC
select SYS_SUPPORTS_32BIT_KERNEL
select SYS_SUPPORTS_LITTLE_ENDIAN
select SYS_SUPPORTS_ZBOOT_UART16550
select CPU_SUPPORTS_HUGEPAGES
select DMA_NONCOHERENT
select IRQ_MIPS_CPU
select PINCTRL
Expand Down Expand Up @@ -1227,7 +1228,7 @@ config SYS_SUPPORTS_LITTLE_ENDIAN

config SYS_SUPPORTS_HUGETLBFS
bool
depends on CPU_SUPPORTS_HUGEPAGES && 64BIT
depends on CPU_SUPPORTS_HUGEPAGES
default y

config MIPS_HUGE_TLB_SUPPORT
Expand Down Expand Up @@ -2111,6 +2112,7 @@ config CPU_SUPPORTS_ADDRWINCFG
bool
config CPU_SUPPORTS_HUGEPAGES
bool
depends on !(32BIT && (ARCH_PHYS_ADDR_T_64BIT || EVA))
config CPU_SUPPORTS_UNCACHED_ACCELERATED
bool
config MIPS_PGD_C0_CONTEXT
Expand Down
58 changes: 52 additions & 6 deletions arch/mips/include/asm/pgtable-32.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,24 @@
#include <asm/highmem.h>
#endif

/*
* Regarding 32-bit MIPS huge page support (and the tradeoff it entails):
*
* We use the same huge page sizes as 64-bit MIPS. Assuming a 4KB page size,
* our 2-level table layout would normally have a PGD entry cover a contiguous
* 4MB virtual address region (pointing to a 4KB PTE page of 1,024 32-bit pte_t
* pointers, each pointing to a 4KB physical page). The problem is that 4MB,
* spanning both halves of a TLB EntryLo0,1 pair, requires 2MB hardware page
* support, not one of the standard supported sizes (1MB,4MB,16MB,...).
* To correct for this, when huge pages are enabled, we halve the number of
* pointers a PTE page holds, making its last half go to waste. Correspondingly,
* we double the number of PGD pages. Overall, page table memory overhead
* increases to match 64-bit MIPS, but PTE lookups remain CPU cache-friendly.
*
* NOTE: We don't yet support huge pages if extended-addressing is enabled
* (i.e. EVA, XPA, 36-bit Alchemy/Netlogic).
*/

extern int temp_tlb_entry;

/*
Expand All @@ -44,22 +62,36 @@ extern int add_temporary_entry(unsigned long entrylo0, unsigned long entrylo1,
*/

/* PGDIR_SHIFT determines what a third-level page table entry can map */
#define PGDIR_SHIFT (2 * PAGE_SHIFT + PTE_ORDER - PTE_T_LOG2)
#if defined(CONFIG_MIPS_HUGE_TLB_SUPPORT) && !defined(CONFIG_PHYS_ADDR_T_64BIT)
# define PGDIR_SHIFT (2 * PAGE_SHIFT + PTE_ORDER - PTE_T_LOG2 - 1)
#else
# define PGDIR_SHIFT (2 * PAGE_SHIFT + PTE_ORDER - PTE_T_LOG2)
#endif

#define PGDIR_SIZE (1UL << PGDIR_SHIFT)
#define PGDIR_MASK (~(PGDIR_SIZE-1))

/*
* Entries per page directory level: we use two-level, so
* we don't really have any PUD/PMD directory physically.
*/
#define __PGD_ORDER (32 - 3 * PAGE_SHIFT + PGD_T_LOG2 + PTE_T_LOG2)
#if defined(CONFIG_MIPS_HUGE_TLB_SUPPORT) && !defined(CONFIG_PHYS_ADDR_T_64BIT)
# define __PGD_ORDER (32 - 3 * PAGE_SHIFT + PGD_T_LOG2 + PTE_T_LOG2 + 1)
#else
# define __PGD_ORDER (32 - 3 * PAGE_SHIFT + PGD_T_LOG2 + PTE_T_LOG2)
#endif

#define PGD_ORDER (__PGD_ORDER >= 0 ? __PGD_ORDER : 0)
#define PUD_ORDER aieeee_attempt_to_allocate_pud
#define PMD_ORDER 1
#define PMD_ORDER aieeee_attempt_to_allocate_pmd
#define PTE_ORDER 0

#define PTRS_PER_PGD (USER_PTRS_PER_PGD * 2)
#define PTRS_PER_PTE ((PAGE_SIZE << PTE_ORDER) / sizeof(pte_t))
#if defined(CONFIG_MIPS_HUGE_TLB_SUPPORT) && !defined(CONFIG_PHYS_ADDR_T_64BIT)
# define PTRS_PER_PTE ((PAGE_SIZE << PTE_ORDER) / sizeof(pte_t) / 2)
#else
# define PTRS_PER_PTE ((PAGE_SIZE << PTE_ORDER) / sizeof(pte_t))
#endif

#define USER_PTRS_PER_PGD (0x80000000UL/PGDIR_SIZE)
#define FIRST_USER_ADDRESS 0UL
Expand Down Expand Up @@ -87,7 +119,7 @@ extern int add_temporary_entry(unsigned long entrylo0, unsigned long entrylo1,

extern void load_pgd(unsigned long pg_dir);

extern pte_t invalid_pte_table[PAGE_SIZE/sizeof(pte_t)];
extern pte_t invalid_pte_table[PTRS_PER_PTE];

/*
* Empty pgd/pmd entries point to the invalid_pte_table.
Expand All @@ -97,7 +129,19 @@ static inline int pmd_none(pmd_t pmd)
return pmd_val(pmd) == (unsigned long) invalid_pte_table;
}

#define pmd_bad(pmd) (pmd_val(pmd) & ~PAGE_MASK)
static inline int pmd_bad(pmd_t pmd)
{
#ifdef CONFIG_MIPS_HUGE_TLB_SUPPORT
/* pmd_huge(pmd) but inline */
if (unlikely(pmd_val(pmd) & _PAGE_HUGE))
return 0;
#endif

if (unlikely(pmd_val(pmd) & ~PAGE_MASK))
return 1;

return 0;
}

static inline int pmd_present(pmd_t pmd)
{
Expand Down Expand Up @@ -146,6 +190,7 @@ static inline pte_t pfn_pte(unsigned long pfn, pgprot_t prot)
#else
#define pte_pfn(x) ((unsigned long)((x).pte >> _PFN_SHIFT))
#define pfn_pte(pfn, prot) __pte(((unsigned long long)(pfn) << _PFN_SHIFT) | pgprot_val(prot))
#define pfn_pmd(pfn, prot) __pmd(((unsigned long long)(pfn) << _PFN_SHIFT) | pgprot_val(prot))
#endif
#endif /* defined(CONFIG_PHYS_ADDR_T_64BIT) && defined(CONFIG_CPU_MIPS32) */

Expand All @@ -159,6 +204,7 @@ static inline pte_t pfn_pte(unsigned long pfn, pgprot_t prot)
#define pgd_offset_k(address) pgd_offset(&init_mm, address)

#define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD-1))
#define pmd_index(address) (((address) >> PMD_SHIFT) & (PTRS_PER_PMD-1))

/* to find an entry in a page-table-directory */
#define pgd_offset(mm, addr) ((mm)->pgd + pgd_index(addr))
Expand Down
4 changes: 2 additions & 2 deletions arch/mips/include/asm/pgtable-bits.h
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ enum pgtable_bits {
_PAGE_WRITE_SHIFT,
_PAGE_ACCESSED_SHIFT,
_PAGE_MODIFIED_SHIFT,
#if defined(CONFIG_64BIT) && defined(CONFIG_MIPS_HUGE_TLB_SUPPORT)
#if defined(CONFIG_MIPS_HUGE_TLB_SUPPORT)
_PAGE_HUGE_SHIFT,
#endif

Expand All @@ -132,7 +132,7 @@ enum pgtable_bits {
#define _PAGE_WRITE (1 << _PAGE_WRITE_SHIFT)
#define _PAGE_ACCESSED (1 << _PAGE_ACCESSED_SHIFT)
#define _PAGE_MODIFIED (1 << _PAGE_MODIFIED_SHIFT)
#if defined(CONFIG_64BIT) && defined(CONFIG_MIPS_HUGE_TLB_SUPPORT)
#if defined(CONFIG_MIPS_HUGE_TLB_SUPPORT)
# define _PAGE_HUGE (1 << _PAGE_HUGE_SHIFT)
#endif

Expand Down
20 changes: 20 additions & 0 deletions arch/mips/mm/pgtable-32.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <asm/fixmap.h>
#include <asm/pgtable.h>
#include <asm/pgalloc.h>
#include <asm/tlbflush.h>

void pgd_init(unsigned long page)
{
Expand All @@ -30,6 +31,25 @@ void pgd_init(unsigned long page)
}
}

#if defined(CONFIG_TRANSPARENT_HUGEPAGE)
pmd_t mk_pmd(struct page *page, pgprot_t prot)
{
pmd_t pmd;

pmd_val(pmd) = (page_to_pfn(page) << _PFN_SHIFT) | pgprot_val(prot);

return pmd;
}


void set_pmd_at(struct mm_struct *mm, unsigned long addr,
pmd_t *pmdp, pmd_t pmd)
{
*pmdp = pmd;
flush_tlb_all();
}
#endif /* defined(CONFIG_TRANSPARENT_HUGEPAGE) */

void __init pagetable_init(void)
{
unsigned long vaddr;
Expand Down