mirror of
https://github.com/Dasharo/linux.git
synced 2026-03-06 15:25:10 -08:00
arch/tile: Allow tilegx to build with either 16K or 64K page size
This change introduces new flags for the hv_install_context() API that passes a page table pointer to the hypervisor. Clients can explicitly request 4K, 16K, or 64K small pages when they install a new context. In practice, the page size is fixed at kernel compile time and the same size is always requested every time a new page table is installed. The <hv/hypervisor.h> header changes so that it provides more abstract macros for managing "page" things like PFNs and page tables. For example there is now a HV_DEFAULT_PAGE_SIZE_SMALL instead of the old HV_PAGE_SIZE_SMALL. The various PFN routines have been eliminated and only PA- or PTFN-based ones remain (since PTFNs are always expressed in fixed 2KB "page" size). The page-table management macros are renamed with a leading underscore and take page-size arguments with the presumption that clients will use those macros in some single place to provide the "real" macros they will use themselves. I happened to notice the old hv_set_caching() API was totally broken (it assumed 4KB pages) so I changed it so it would nominally work correctly with other page sizes. Tag modules with the page size so you can't load a module built with a conflicting page size. (And add a test for SMP while we're at it.) Signed-off-by: Chris Metcalf <cmetcalf@tilera.com>
This commit is contained in:
@@ -21,7 +21,6 @@ generic-y += ipcbuf.h
|
||||
generic-y += irq_regs.h
|
||||
generic-y += kdebug.h
|
||||
generic-y += local.h
|
||||
generic-y += module.h
|
||||
generic-y += msgbuf.h
|
||||
generic-y += mutex.h
|
||||
generic-y += param.h
|
||||
|
||||
@@ -21,7 +21,7 @@ struct mm_context {
|
||||
* Written under the mmap_sem semaphore; read without the
|
||||
* semaphore but atomically, but it is conservatively set.
|
||||
*/
|
||||
unsigned int priority_cached;
|
||||
unsigned long priority_cached;
|
||||
};
|
||||
|
||||
typedef struct mm_context mm_context_t;
|
||||
|
||||
@@ -30,11 +30,15 @@ init_new_context(struct task_struct *tsk, struct mm_struct *mm)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Note that arch/tile/kernel/head.S also calls hv_install_context() */
|
||||
/*
|
||||
* Note that arch/tile/kernel/head_NN.S and arch/tile/mm/migrate_NN.S
|
||||
* also call hv_install_context().
|
||||
*/
|
||||
static inline void __install_page_table(pgd_t *pgdir, int asid, pgprot_t prot)
|
||||
{
|
||||
/* FIXME: DIRECTIO should not always be set. FIXME. */
|
||||
int rc = hv_install_context(__pa(pgdir), prot, asid, HV_CTX_DIRECTIO);
|
||||
int rc = hv_install_context(__pa(pgdir), prot, asid,
|
||||
HV_CTX_DIRECTIO | CTX_PAGE_FLAG);
|
||||
if (rc < 0)
|
||||
panic("hv_install_context failed: %d", rc);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2011 Tilera Corporation. All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, version 2.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
|
||||
* NON INFRINGEMENT. See the GNU General Public License for
|
||||
* more details.
|
||||
*/
|
||||
|
||||
#ifndef _ASM_TILE_MODULE_H
|
||||
#define _ASM_TILE_MODULE_H
|
||||
|
||||
#include <arch/chip.h>
|
||||
|
||||
#include <asm-generic/module.h>
|
||||
|
||||
/* We can't use modules built with different page sizes. */
|
||||
#if defined(CONFIG_PAGE_SIZE_16KB)
|
||||
# define MODULE_PGSZ " 16KB"
|
||||
#elif defined(CONFIG_PAGE_SIZE_64KB)
|
||||
# define MODULE_PGSZ " 64KB"
|
||||
#else
|
||||
# define MODULE_PGSZ ""
|
||||
#endif
|
||||
|
||||
/* We don't really support no-SMP so tag if someone tries. */
|
||||
#ifdef CONFIG_SMP
|
||||
#define MODULE_NOSMP ""
|
||||
#else
|
||||
#define MODULE_NOSMP " nosmp"
|
||||
#endif
|
||||
|
||||
#define MODULE_ARCH_VERMAGIC CHIP_ARCH_NAME MODULE_PGSZ MODULE_NOSMP
|
||||
|
||||
#endif /* _ASM_TILE_MODULE_H */
|
||||
@@ -20,8 +20,17 @@
|
||||
#include <arch/chip.h>
|
||||
|
||||
/* PAGE_SHIFT and HPAGE_SHIFT determine the page sizes. */
|
||||
#define PAGE_SHIFT HV_LOG2_PAGE_SIZE_SMALL
|
||||
#define HPAGE_SHIFT HV_LOG2_PAGE_SIZE_LARGE
|
||||
#if defined(CONFIG_PAGE_SIZE_16KB)
|
||||
#define PAGE_SHIFT 14
|
||||
#define CTX_PAGE_FLAG HV_CTX_PG_SM_16K
|
||||
#elif defined(CONFIG_PAGE_SIZE_64KB)
|
||||
#define PAGE_SHIFT 16
|
||||
#define CTX_PAGE_FLAG HV_CTX_PG_SM_64K
|
||||
#else
|
||||
#define PAGE_SHIFT HV_LOG2_DEFAULT_PAGE_SIZE_SMALL
|
||||
#define CTX_PAGE_FLAG 0
|
||||
#endif
|
||||
#define HPAGE_SHIFT HV_LOG2_DEFAULT_PAGE_SIZE_LARGE
|
||||
|
||||
#define PAGE_SIZE (_AC(1, UL) << PAGE_SHIFT)
|
||||
#define HPAGE_SIZE (_AC(1, UL) << HPAGE_SHIFT)
|
||||
|
||||
@@ -19,24 +19,24 @@
|
||||
#include <linux/mm.h>
|
||||
#include <linux/mmzone.h>
|
||||
#include <asm/fixmap.h>
|
||||
#include <asm/page.h>
|
||||
#include <hv/hypervisor.h>
|
||||
|
||||
/* Bits for the size of the second-level page table. */
|
||||
#define L2_KERNEL_PGTABLE_SHIFT \
|
||||
(HV_LOG2_PAGE_SIZE_LARGE - HV_LOG2_PAGE_SIZE_SMALL + HV_LOG2_PTE_SIZE)
|
||||
#define L2_KERNEL_PGTABLE_SHIFT _HV_LOG2_L2_SIZE(HPAGE_SHIFT, PAGE_SHIFT)
|
||||
|
||||
/* How big is a kernel L2 page table? */
|
||||
#define L2_KERNEL_PGTABLE_SIZE (1UL << L2_KERNEL_PGTABLE_SHIFT)
|
||||
|
||||
/* We currently allocate user L2 page tables by page (unlike kernel L2s). */
|
||||
#if L2_KERNEL_PGTABLE_SHIFT < HV_LOG2_PAGE_SIZE_SMALL
|
||||
#define L2_USER_PGTABLE_SHIFT HV_LOG2_PAGE_SIZE_SMALL
|
||||
#if L2_KERNEL_PGTABLE_SHIFT < PAGE_SHIFT
|
||||
#define L2_USER_PGTABLE_SHIFT PAGE_SHIFT
|
||||
#else
|
||||
#define L2_USER_PGTABLE_SHIFT L2_KERNEL_PGTABLE_SHIFT
|
||||
#endif
|
||||
|
||||
/* How many pages do we need, as an "order", for a user L2 page table? */
|
||||
#define L2_USER_PGTABLE_ORDER (L2_USER_PGTABLE_SHIFT - HV_LOG2_PAGE_SIZE_SMALL)
|
||||
|
||||
/* How big is a kernel L2 page table? */
|
||||
#define L2_KERNEL_PGTABLE_SIZE (1 << L2_KERNEL_PGTABLE_SHIFT)
|
||||
#define L2_USER_PGTABLE_ORDER (L2_USER_PGTABLE_SHIFT - PAGE_SHIFT)
|
||||
|
||||
static inline void set_pmd(pmd_t *pmdp, pmd_t pmd)
|
||||
{
|
||||
@@ -50,14 +50,14 @@ static inline void set_pmd(pmd_t *pmdp, pmd_t pmd)
|
||||
static inline void pmd_populate_kernel(struct mm_struct *mm,
|
||||
pmd_t *pmd, pte_t *ptep)
|
||||
{
|
||||
set_pmd(pmd, ptfn_pmd(__pa(ptep) >> HV_LOG2_PAGE_TABLE_ALIGN,
|
||||
set_pmd(pmd, ptfn_pmd(HV_CPA_TO_PTFN(__pa(ptep)),
|
||||
__pgprot(_PAGE_PRESENT)));
|
||||
}
|
||||
|
||||
static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd,
|
||||
pgtable_t page)
|
||||
{
|
||||
set_pmd(pmd, ptfn_pmd(HV_PFN_TO_PTFN(page_to_pfn(page)),
|
||||
set_pmd(pmd, ptfn_pmd(HV_CPA_TO_PTFN(PFN_PHYS(page_to_pfn(page))),
|
||||
__pgprot(_PAGE_PRESENT)));
|
||||
}
|
||||
|
||||
@@ -68,8 +68,20 @@ static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd,
|
||||
extern pgd_t *pgd_alloc(struct mm_struct *mm);
|
||||
extern void pgd_free(struct mm_struct *mm, pgd_t *pgd);
|
||||
|
||||
extern pgtable_t pte_alloc_one(struct mm_struct *mm, unsigned long address);
|
||||
extern void pte_free(struct mm_struct *mm, struct page *pte);
|
||||
extern pgtable_t pgtable_alloc_one(struct mm_struct *mm, unsigned long address,
|
||||
int order);
|
||||
extern void pgtable_free(struct mm_struct *mm, struct page *pte, int order);
|
||||
|
||||
static inline pgtable_t pte_alloc_one(struct mm_struct *mm,
|
||||
unsigned long address)
|
||||
{
|
||||
return pgtable_alloc_one(mm, address, L2_USER_PGTABLE_ORDER);
|
||||
}
|
||||
|
||||
static inline void pte_free(struct mm_struct *mm, struct page *pte)
|
||||
{
|
||||
pgtable_free(mm, pte, L2_USER_PGTABLE_ORDER);
|
||||
}
|
||||
|
||||
#define pmd_pgtable(pmd) pmd_page(pmd)
|
||||
|
||||
@@ -85,8 +97,13 @@ static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte)
|
||||
pte_free(mm, virt_to_page(pte));
|
||||
}
|
||||
|
||||
extern void __pte_free_tlb(struct mmu_gather *tlb, struct page *pte,
|
||||
unsigned long address);
|
||||
extern void __pgtable_free_tlb(struct mmu_gather *tlb, struct page *pte,
|
||||
unsigned long address, int order);
|
||||
static inline void __pte_free_tlb(struct mmu_gather *tlb, struct page *pte,
|
||||
unsigned long address)
|
||||
{
|
||||
__pgtable_free_tlb(tlb, pte, address, L2_USER_PGTABLE_ORDER);
|
||||
}
|
||||
|
||||
#define check_pgt_cache() do { } while (0)
|
||||
|
||||
@@ -104,19 +121,44 @@ void shatter_pmd(pmd_t *pmd);
|
||||
void shatter_huge_page(unsigned long addr);
|
||||
|
||||
#ifdef __tilegx__
|
||||
/* We share a single page allocator for both L1 and L2 page tables. */
|
||||
#if HV_L1_SIZE != HV_L2_SIZE
|
||||
# error Rework assumption that L1 and L2 page tables are same size.
|
||||
#endif
|
||||
#define L1_USER_PGTABLE_ORDER L2_USER_PGTABLE_ORDER
|
||||
|
||||
#define pud_populate(mm, pud, pmd) \
|
||||
pmd_populate_kernel((mm), (pmd_t *)(pud), (pte_t *)(pmd))
|
||||
#define pmd_alloc_one(mm, addr) \
|
||||
((pmd_t *)page_to_virt(pte_alloc_one((mm), (addr))))
|
||||
#define pmd_free(mm, pmdp) \
|
||||
pte_free((mm), virt_to_page(pmdp))
|
||||
#define __pmd_free_tlb(tlb, pmdp, address) \
|
||||
__pte_free_tlb((tlb), virt_to_page(pmdp), (address))
|
||||
|
||||
/* Bits for the size of the L1 (intermediate) page table. */
|
||||
#define L1_KERNEL_PGTABLE_SHIFT _HV_LOG2_L1_SIZE(HPAGE_SHIFT)
|
||||
|
||||
/* How big is a kernel L2 page table? */
|
||||
#define L1_KERNEL_PGTABLE_SIZE (1UL << L1_KERNEL_PGTABLE_SHIFT)
|
||||
|
||||
/* We currently allocate L1 page tables by page. */
|
||||
#if L1_KERNEL_PGTABLE_SHIFT < PAGE_SHIFT
|
||||
#define L1_USER_PGTABLE_SHIFT PAGE_SHIFT
|
||||
#else
|
||||
#define L1_USER_PGTABLE_SHIFT L1_KERNEL_PGTABLE_SHIFT
|
||||
#endif
|
||||
|
||||
/* How many pages do we need, as an "order", for an L1 page table? */
|
||||
#define L1_USER_PGTABLE_ORDER (L1_USER_PGTABLE_SHIFT - PAGE_SHIFT)
|
||||
|
||||
static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long address)
|
||||
{
|
||||
struct page *p = pgtable_alloc_one(mm, address, L1_USER_PGTABLE_ORDER);
|
||||
return (pmd_t *)page_to_virt(p);
|
||||
}
|
||||
|
||||
static inline void pmd_free(struct mm_struct *mm, pmd_t *pmdp)
|
||||
{
|
||||
pgtable_free(mm, virt_to_page(pmdp), L1_USER_PGTABLE_ORDER);
|
||||
}
|
||||
|
||||
static inline void __pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmdp,
|
||||
unsigned long address)
|
||||
{
|
||||
__pgtable_free_tlb(tlb, virt_to_page(pmdp), address,
|
||||
L1_USER_PGTABLE_ORDER);
|
||||
}
|
||||
|
||||
#endif /* __tilegx__ */
|
||||
|
||||
#endif /* _ASM_TILE_PGALLOC_H */
|
||||
|
||||
@@ -27,8 +27,10 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/pfn.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/fixmap.h>
|
||||
#include <asm/page.h>
|
||||
|
||||
struct mm_struct;
|
||||
struct vm_area_struct;
|
||||
@@ -162,7 +164,7 @@ extern void set_page_homes(void);
|
||||
(pgprot_t) { ((oldprot).val & ~_PAGE_ALL) | (newprot).val }
|
||||
|
||||
/* Just setting the PFN to zero suffices. */
|
||||
#define pte_pgprot(x) hv_pte_set_pfn((x), 0)
|
||||
#define pte_pgprot(x) hv_pte_set_pa((x), 0)
|
||||
|
||||
/*
|
||||
* For PTEs and PDEs, we must clear the Present bit first when
|
||||
@@ -262,7 +264,7 @@ static inline int pte_none(pte_t pte)
|
||||
|
||||
static inline unsigned long pte_pfn(pte_t pte)
|
||||
{
|
||||
return hv_pte_get_pfn(pte);
|
||||
return PFN_DOWN(hv_pte_get_pa(pte));
|
||||
}
|
||||
|
||||
/* Set or get the remote cache cpu in a pgprot with remote caching. */
|
||||
@@ -271,7 +273,7 @@ extern int get_remote_cache_cpu(pgprot_t prot);
|
||||
|
||||
static inline pte_t pfn_pte(unsigned long pfn, pgprot_t prot)
|
||||
{
|
||||
return hv_pte_set_pfn(prot, pfn);
|
||||
return hv_pte_set_pa(prot, PFN_PHYS(pfn));
|
||||
}
|
||||
|
||||
/* Support for priority mappings. */
|
||||
@@ -471,7 +473,7 @@ static inline unsigned long pmd_page_vaddr(pmd_t pmd)
|
||||
* OK for pte_lockptr(), since we just end up with potentially one
|
||||
* lock being used for several pte_t arrays.
|
||||
*/
|
||||
#define pmd_page(pmd) pfn_to_page(HV_PTFN_TO_PFN(pmd_ptfn(pmd)))
|
||||
#define pmd_page(pmd) pfn_to_page(PFN_DOWN(HV_PTFN_TO_CPA(pmd_ptfn(pmd))))
|
||||
|
||||
static inline void pmd_clear(pmd_t *pmdp)
|
||||
{
|
||||
|
||||
@@ -20,11 +20,12 @@
|
||||
* The level-1 index is defined by the huge page size. A PGD is composed
|
||||
* of PTRS_PER_PGD pgd_t's and is the top level of the page table.
|
||||
*/
|
||||
#define PGDIR_SHIFT HV_LOG2_PAGE_SIZE_LARGE
|
||||
#define PGDIR_SIZE HV_PAGE_SIZE_LARGE
|
||||
#define PGDIR_SHIFT HPAGE_SHIFT
|
||||
#define PGDIR_SIZE HPAGE_SIZE
|
||||
#define PGDIR_MASK (~(PGDIR_SIZE-1))
|
||||
#define PTRS_PER_PGD (1 << (32 - PGDIR_SHIFT))
|
||||
#define SIZEOF_PGD (PTRS_PER_PGD * sizeof(pgd_t))
|
||||
#define PTRS_PER_PGD _HV_L1_ENTRIES(HPAGE_SHIFT)
|
||||
#define PGD_INDEX(va) _HV_L1_INDEX(va, HPAGE_SHIFT)
|
||||
#define SIZEOF_PGD _HV_L1_SIZE(HPAGE_SHIFT)
|
||||
|
||||
/*
|
||||
* The level-2 index is defined by the difference between the huge
|
||||
@@ -33,8 +34,9 @@
|
||||
* Note that the hypervisor docs use PTE for what we call pte_t, so
|
||||
* this nomenclature is somewhat confusing.
|
||||
*/
|
||||
#define PTRS_PER_PTE (1 << (HV_LOG2_PAGE_SIZE_LARGE - HV_LOG2_PAGE_SIZE_SMALL))
|
||||
#define SIZEOF_PTE (PTRS_PER_PTE * sizeof(pte_t))
|
||||
#define PTRS_PER_PTE _HV_L2_ENTRIES(HPAGE_SHIFT, PAGE_SHIFT)
|
||||
#define PTE_INDEX(va) _HV_L2_INDEX(va, HPAGE_SHIFT, PAGE_SHIFT)
|
||||
#define SIZEOF_PTE _HV_L2_SIZE(HPAGE_SHIFT, PAGE_SHIFT)
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
|
||||
@@ -21,17 +21,19 @@
|
||||
#define PGDIR_SIZE HV_L1_SPAN
|
||||
#define PGDIR_MASK (~(PGDIR_SIZE-1))
|
||||
#define PTRS_PER_PGD HV_L0_ENTRIES
|
||||
#define SIZEOF_PGD (PTRS_PER_PGD * sizeof(pgd_t))
|
||||
#define PGD_INDEX(va) HV_L0_INDEX(va)
|
||||
#define SIZEOF_PGD HV_L0_SIZE
|
||||
|
||||
/*
|
||||
* The level-1 index is defined by the huge page size. A PMD is composed
|
||||
* of PTRS_PER_PMD pgd_t's and is the middle level of the page table.
|
||||
*/
|
||||
#define PMD_SHIFT HV_LOG2_PAGE_SIZE_LARGE
|
||||
#define PMD_SIZE HV_PAGE_SIZE_LARGE
|
||||
#define PMD_SHIFT HPAGE_SHIFT
|
||||
#define PMD_SIZE HPAGE_SIZE
|
||||
#define PMD_MASK (~(PMD_SIZE-1))
|
||||
#define PTRS_PER_PMD (1 << (PGDIR_SHIFT - PMD_SHIFT))
|
||||
#define SIZEOF_PMD (PTRS_PER_PMD * sizeof(pmd_t))
|
||||
#define PTRS_PER_PMD _HV_L1_ENTRIES(HPAGE_SHIFT)
|
||||
#define PMD_INDEX(va) _HV_L1_INDEX(va, HPAGE_SHIFT)
|
||||
#define SIZEOF_PMD _HV_L1_SIZE(HPAGE_SHIFT)
|
||||
|
||||
/*
|
||||
* The level-2 index is defined by the difference between the huge
|
||||
@@ -40,17 +42,19 @@
|
||||
* Note that the hypervisor docs use PTE for what we call pte_t, so
|
||||
* this nomenclature is somewhat confusing.
|
||||
*/
|
||||
#define PTRS_PER_PTE (1 << (HV_LOG2_PAGE_SIZE_LARGE - HV_LOG2_PAGE_SIZE_SMALL))
|
||||
#define SIZEOF_PTE (PTRS_PER_PTE * sizeof(pte_t))
|
||||
#define PTRS_PER_PTE _HV_L2_ENTRIES(HPAGE_SHIFT, PAGE_SHIFT)
|
||||
#define PTE_INDEX(va) _HV_L2_INDEX(va, HPAGE_SHIFT, PAGE_SHIFT)
|
||||
#define SIZEOF_PTE _HV_L2_SIZE(HPAGE_SHIFT, PAGE_SHIFT)
|
||||
|
||||
/*
|
||||
* Align the vmalloc area to an L2 page table, and leave a guard page
|
||||
* at the beginning and end. The vmalloc code also puts in an internal
|
||||
* Align the vmalloc area to an L2 page table. Omit guard pages at
|
||||
* the beginning and end for simplicity (particularly in the per-cpu
|
||||
* memory allocation code). The vmalloc code puts in an internal
|
||||
* guard page between each allocation.
|
||||
*/
|
||||
#define _VMALLOC_END HUGE_VMAP_BASE
|
||||
#define VMALLOC_END (_VMALLOC_END - PAGE_SIZE)
|
||||
#define VMALLOC_START (_VMALLOC_START + PAGE_SIZE)
|
||||
#define VMALLOC_END _VMALLOC_END
|
||||
#define VMALLOC_START _VMALLOC_START
|
||||
|
||||
#define HUGE_VMAP_END (HUGE_VMAP_BASE + PGDIR_SIZE)
|
||||
|
||||
@@ -98,7 +102,7 @@ static inline int pud_bad(pud_t pud)
|
||||
* A pud_t points to a pmd_t array. Since we can have multiple per
|
||||
* page, we don't have a one-to-one mapping of pud_t's to pages.
|
||||
*/
|
||||
#define pud_page(pud) pfn_to_page(HV_PTFN_TO_PFN(pud_ptfn(pud)))
|
||||
#define pud_page(pud) pfn_to_page(PFN_DOWN(HV_PTFN_TO_CPA(pud_ptfn(pud))))
|
||||
|
||||
static inline unsigned long pud_index(unsigned long address)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user