mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-11-01 17:08:10 +00: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:
parent
47d632f9f8
commit
d5d14ed6f2
20 changed files with 345 additions and 197 deletions
|
@ -139,6 +139,31 @@ config NR_CPUS
|
||||||
smaller kernel memory footprint results from using a smaller
|
smaller kernel memory footprint results from using a smaller
|
||||||
value on chips with fewer tiles.
|
value on chips with fewer tiles.
|
||||||
|
|
||||||
|
if TILEGX
|
||||||
|
|
||||||
|
choice
|
||||||
|
prompt "Kernel page size"
|
||||||
|
default PAGE_SIZE_64KB
|
||||||
|
help
|
||||||
|
This lets you select the page size of the kernel. For best
|
||||||
|
performance on memory-intensive applications, a page size of 64KB
|
||||||
|
is recommended. For workloads involving many small files, many
|
||||||
|
connections, etc., it may be better to select 16KB, which uses
|
||||||
|
memory more efficiently at some cost in TLB performance.
|
||||||
|
|
||||||
|
Note that this option is TILE-Gx specific; currently
|
||||||
|
TILEPro page size is set by rebuilding the hypervisor.
|
||||||
|
|
||||||
|
config PAGE_SIZE_16KB
|
||||||
|
bool "16KB"
|
||||||
|
|
||||||
|
config PAGE_SIZE_64KB
|
||||||
|
bool "64KB"
|
||||||
|
|
||||||
|
endchoice
|
||||||
|
|
||||||
|
endif
|
||||||
|
|
||||||
source "kernel/time/Kconfig"
|
source "kernel/time/Kconfig"
|
||||||
|
|
||||||
source "kernel/Kconfig.hz"
|
source "kernel/Kconfig.hz"
|
||||||
|
|
|
@ -21,7 +21,6 @@ generic-y += ipcbuf.h
|
||||||
generic-y += irq_regs.h
|
generic-y += irq_regs.h
|
||||||
generic-y += kdebug.h
|
generic-y += kdebug.h
|
||||||
generic-y += local.h
|
generic-y += local.h
|
||||||
generic-y += module.h
|
|
||||||
generic-y += msgbuf.h
|
generic-y += msgbuf.h
|
||||||
generic-y += mutex.h
|
generic-y += mutex.h
|
||||||
generic-y += param.h
|
generic-y += param.h
|
||||||
|
|
|
@ -21,7 +21,7 @@ struct mm_context {
|
||||||
* Written under the mmap_sem semaphore; read without the
|
* Written under the mmap_sem semaphore; read without the
|
||||||
* semaphore but atomically, but it is conservatively set.
|
* semaphore but atomically, but it is conservatively set.
|
||||||
*/
|
*/
|
||||||
unsigned int priority_cached;
|
unsigned long priority_cached;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct mm_context mm_context_t;
|
typedef struct mm_context mm_context_t;
|
||||||
|
|
|
@ -30,11 +30,15 @@ init_new_context(struct task_struct *tsk, struct mm_struct *mm)
|
||||||
return 0;
|
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)
|
static inline void __install_page_table(pgd_t *pgdir, int asid, pgprot_t prot)
|
||||||
{
|
{
|
||||||
/* FIXME: DIRECTIO should not always be set. FIXME. */
|
/* 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)
|
if (rc < 0)
|
||||||
panic("hv_install_context failed: %d", rc);
|
panic("hv_install_context failed: %d", rc);
|
||||||
}
|
}
|
||||||
|
|
40
arch/tile/include/asm/module.h
Normal file
40
arch/tile/include/asm/module.h
Normal file
|
@ -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>
|
#include <arch/chip.h>
|
||||||
|
|
||||||
/* PAGE_SHIFT and HPAGE_SHIFT determine the page sizes. */
|
/* PAGE_SHIFT and HPAGE_SHIFT determine the page sizes. */
|
||||||
#define PAGE_SHIFT HV_LOG2_PAGE_SIZE_SMALL
|
#if defined(CONFIG_PAGE_SIZE_16KB)
|
||||||
#define HPAGE_SHIFT HV_LOG2_PAGE_SIZE_LARGE
|
#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 PAGE_SIZE (_AC(1, UL) << PAGE_SHIFT)
|
||||||
#define HPAGE_SIZE (_AC(1, UL) << HPAGE_SHIFT)
|
#define HPAGE_SIZE (_AC(1, UL) << HPAGE_SHIFT)
|
||||||
|
|
|
@ -19,24 +19,24 @@
|
||||||
#include <linux/mm.h>
|
#include <linux/mm.h>
|
||||||
#include <linux/mmzone.h>
|
#include <linux/mmzone.h>
|
||||||
#include <asm/fixmap.h>
|
#include <asm/fixmap.h>
|
||||||
|
#include <asm/page.h>
|
||||||
#include <hv/hypervisor.h>
|
#include <hv/hypervisor.h>
|
||||||
|
|
||||||
/* Bits for the size of the second-level page table. */
|
/* Bits for the size of the second-level page table. */
|
||||||
#define L2_KERNEL_PGTABLE_SHIFT \
|
#define L2_KERNEL_PGTABLE_SHIFT _HV_LOG2_L2_SIZE(HPAGE_SHIFT, PAGE_SHIFT)
|
||||||
(HV_LOG2_PAGE_SIZE_LARGE - HV_LOG2_PAGE_SIZE_SMALL + HV_LOG2_PTE_SIZE)
|
|
||||||
|
/* 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). */
|
/* We currently allocate user L2 page tables by page (unlike kernel L2s). */
|
||||||
#if L2_KERNEL_PGTABLE_SHIFT < HV_LOG2_PAGE_SIZE_SMALL
|
#if L2_KERNEL_PGTABLE_SHIFT < PAGE_SHIFT
|
||||||
#define L2_USER_PGTABLE_SHIFT HV_LOG2_PAGE_SIZE_SMALL
|
#define L2_USER_PGTABLE_SHIFT PAGE_SHIFT
|
||||||
#else
|
#else
|
||||||
#define L2_USER_PGTABLE_SHIFT L2_KERNEL_PGTABLE_SHIFT
|
#define L2_USER_PGTABLE_SHIFT L2_KERNEL_PGTABLE_SHIFT
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* How many pages do we need, as an "order", for a user L2 page table? */
|
/* 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)
|
#define L2_USER_PGTABLE_ORDER (L2_USER_PGTABLE_SHIFT - PAGE_SHIFT)
|
||||||
|
|
||||||
/* How big is a kernel L2 page table? */
|
|
||||||
#define L2_KERNEL_PGTABLE_SIZE (1 << L2_KERNEL_PGTABLE_SHIFT)
|
|
||||||
|
|
||||||
static inline void set_pmd(pmd_t *pmdp, pmd_t pmd)
|
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,
|
static inline void pmd_populate_kernel(struct mm_struct *mm,
|
||||||
pmd_t *pmd, pte_t *ptep)
|
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)));
|
__pgprot(_PAGE_PRESENT)));
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd,
|
static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd,
|
||||||
pgtable_t page)
|
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)));
|
__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 pgd_t *pgd_alloc(struct mm_struct *mm);
|
||||||
extern void pgd_free(struct mm_struct *mm, pgd_t *pgd);
|
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 pgtable_t pgtable_alloc_one(struct mm_struct *mm, unsigned long address,
|
||||||
extern void pte_free(struct mm_struct *mm, struct page *pte);
|
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)
|
#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));
|
pte_free(mm, virt_to_page(pte));
|
||||||
}
|
}
|
||||||
|
|
||||||
extern void __pte_free_tlb(struct mmu_gather *tlb, struct page *pte,
|
extern void __pgtable_free_tlb(struct mmu_gather *tlb, struct page *pte,
|
||||||
unsigned long address);
|
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)
|
#define check_pgt_cache() do { } while (0)
|
||||||
|
|
||||||
|
@ -104,19 +121,44 @@ void shatter_pmd(pmd_t *pmd);
|
||||||
void shatter_huge_page(unsigned long addr);
|
void shatter_huge_page(unsigned long addr);
|
||||||
|
|
||||||
#ifdef __tilegx__
|
#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) \
|
#define pud_populate(mm, pud, pmd) \
|
||||||
pmd_populate_kernel((mm), (pmd_t *)(pud), (pte_t *)(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))))
|
/* Bits for the size of the L1 (intermediate) page table. */
|
||||||
#define pmd_free(mm, pmdp) \
|
#define L1_KERNEL_PGTABLE_SHIFT _HV_LOG2_L1_SIZE(HPAGE_SHIFT)
|
||||||
pte_free((mm), virt_to_page(pmdp))
|
|
||||||
#define __pmd_free_tlb(tlb, pmdp, address) \
|
/* How big is a kernel L2 page table? */
|
||||||
__pte_free_tlb((tlb), virt_to_page(pmdp), (address))
|
#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
|
#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 */
|
#endif /* _ASM_TILE_PGALLOC_H */
|
||||||
|
|
|
@ -27,8 +27,10 @@
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/list.h>
|
#include <linux/list.h>
|
||||||
#include <linux/spinlock.h>
|
#include <linux/spinlock.h>
|
||||||
|
#include <linux/pfn.h>
|
||||||
#include <asm/processor.h>
|
#include <asm/processor.h>
|
||||||
#include <asm/fixmap.h>
|
#include <asm/fixmap.h>
|
||||||
|
#include <asm/page.h>
|
||||||
|
|
||||||
struct mm_struct;
|
struct mm_struct;
|
||||||
struct vm_area_struct;
|
struct vm_area_struct;
|
||||||
|
@ -162,7 +164,7 @@ extern void set_page_homes(void);
|
||||||
(pgprot_t) { ((oldprot).val & ~_PAGE_ALL) | (newprot).val }
|
(pgprot_t) { ((oldprot).val & ~_PAGE_ALL) | (newprot).val }
|
||||||
|
|
||||||
/* Just setting the PFN to zero suffices. */
|
/* 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
|
* 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)
|
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. */
|
/* 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)
|
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. */
|
/* 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
|
* OK for pte_lockptr(), since we just end up with potentially one
|
||||||
* lock being used for several pte_t arrays.
|
* 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)
|
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
|
* 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.
|
* 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_SHIFT HPAGE_SHIFT
|
||||||
#define PGDIR_SIZE HV_PAGE_SIZE_LARGE
|
#define PGDIR_SIZE HPAGE_SIZE
|
||||||
#define PGDIR_MASK (~(PGDIR_SIZE-1))
|
#define PGDIR_MASK (~(PGDIR_SIZE-1))
|
||||||
#define PTRS_PER_PGD (1 << (32 - PGDIR_SHIFT))
|
#define PTRS_PER_PGD _HV_L1_ENTRIES(HPAGE_SHIFT)
|
||||||
#define SIZEOF_PGD (PTRS_PER_PGD * sizeof(pgd_t))
|
#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
|
* 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
|
* Note that the hypervisor docs use PTE for what we call pte_t, so
|
||||||
* this nomenclature is somewhat confusing.
|
* this nomenclature is somewhat confusing.
|
||||||
*/
|
*/
|
||||||
#define PTRS_PER_PTE (1 << (HV_LOG2_PAGE_SIZE_LARGE - HV_LOG2_PAGE_SIZE_SMALL))
|
#define PTRS_PER_PTE _HV_L2_ENTRIES(HPAGE_SHIFT, PAGE_SHIFT)
|
||||||
#define SIZEOF_PTE (PTRS_PER_PTE * sizeof(pte_t))
|
#define PTE_INDEX(va) _HV_L2_INDEX(va, HPAGE_SHIFT, PAGE_SHIFT)
|
||||||
|
#define SIZEOF_PTE _HV_L2_SIZE(HPAGE_SHIFT, PAGE_SHIFT)
|
||||||
|
|
||||||
#ifndef __ASSEMBLY__
|
#ifndef __ASSEMBLY__
|
||||||
|
|
||||||
|
|
|
@ -21,17 +21,19 @@
|
||||||
#define PGDIR_SIZE HV_L1_SPAN
|
#define PGDIR_SIZE HV_L1_SPAN
|
||||||
#define PGDIR_MASK (~(PGDIR_SIZE-1))
|
#define PGDIR_MASK (~(PGDIR_SIZE-1))
|
||||||
#define PTRS_PER_PGD HV_L0_ENTRIES
|
#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
|
* 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.
|
* 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_SHIFT HPAGE_SHIFT
|
||||||
#define PMD_SIZE HV_PAGE_SIZE_LARGE
|
#define PMD_SIZE HPAGE_SIZE
|
||||||
#define PMD_MASK (~(PMD_SIZE-1))
|
#define PMD_MASK (~(PMD_SIZE-1))
|
||||||
#define PTRS_PER_PMD (1 << (PGDIR_SHIFT - PMD_SHIFT))
|
#define PTRS_PER_PMD _HV_L1_ENTRIES(HPAGE_SHIFT)
|
||||||
#define SIZEOF_PMD (PTRS_PER_PMD * sizeof(pmd_t))
|
#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
|
* 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
|
* Note that the hypervisor docs use PTE for what we call pte_t, so
|
||||||
* this nomenclature is somewhat confusing.
|
* this nomenclature is somewhat confusing.
|
||||||
*/
|
*/
|
||||||
#define PTRS_PER_PTE (1 << (HV_LOG2_PAGE_SIZE_LARGE - HV_LOG2_PAGE_SIZE_SMALL))
|
#define PTRS_PER_PTE _HV_L2_ENTRIES(HPAGE_SHIFT, PAGE_SHIFT)
|
||||||
#define SIZEOF_PTE (PTRS_PER_PTE * sizeof(pte_t))
|
#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
|
* Align the vmalloc area to an L2 page table. Omit guard pages at
|
||||||
* at the beginning and end. The vmalloc code also puts in an internal
|
* 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.
|
* guard page between each allocation.
|
||||||
*/
|
*/
|
||||||
#define _VMALLOC_END HUGE_VMAP_BASE
|
#define _VMALLOC_END HUGE_VMAP_BASE
|
||||||
#define VMALLOC_END (_VMALLOC_END - PAGE_SIZE)
|
#define VMALLOC_END _VMALLOC_END
|
||||||
#define VMALLOC_START (_VMALLOC_START + PAGE_SIZE)
|
#define VMALLOC_START _VMALLOC_START
|
||||||
|
|
||||||
#define HUGE_VMAP_END (HUGE_VMAP_BASE + PGDIR_SIZE)
|
#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
|
* 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.
|
* 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)
|
static inline unsigned long pud_index(unsigned long address)
|
||||||
{
|
{
|
||||||
|
|
|
@ -460,7 +460,7 @@ typedef void* lepp_comp_t;
|
||||||
* linux's "MAX_SKB_FRAGS", and presumably over-estimates by one, for
|
* linux's "MAX_SKB_FRAGS", and presumably over-estimates by one, for
|
||||||
* our page size of exactly 65536. We add one for a "body" fragment.
|
* our page size of exactly 65536. We add one for a "body" fragment.
|
||||||
*/
|
*/
|
||||||
#define LEPP_MAX_FRAGS (65536 / HV_PAGE_SIZE_SMALL + 2 + 1)
|
#define LEPP_MAX_FRAGS (65536 / HV_DEFAULT_PAGE_SIZE_SMALL + 2 + 1)
|
||||||
|
|
||||||
/** Total number of bytes needed for an lepp_tso_cmd_t. */
|
/** Total number of bytes needed for an lepp_tso_cmd_t. */
|
||||||
#define LEPP_TSO_CMD_SIZE(num_frags, header_size) \
|
#define LEPP_TSO_CMD_SIZE(num_frags, header_size) \
|
||||||
|
|
|
@ -17,8 +17,8 @@
|
||||||
* The hypervisor's public API.
|
* The hypervisor's public API.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _TILE_HV_H
|
#ifndef _HV_HV_H
|
||||||
#define _TILE_HV_H
|
#define _HV_HV_H
|
||||||
|
|
||||||
#include <arch/chip.h>
|
#include <arch/chip.h>
|
||||||
|
|
||||||
|
@ -42,25 +42,29 @@
|
||||||
*/
|
*/
|
||||||
#define HV_L1_SPAN (__HV_SIZE_ONE << HV_LOG2_L1_SPAN)
|
#define HV_L1_SPAN (__HV_SIZE_ONE << HV_LOG2_L1_SPAN)
|
||||||
|
|
||||||
/** The log2 of the size of small pages, in bytes. This value should
|
/** The log2 of the initial size of small pages, in bytes.
|
||||||
* be verified at runtime by calling hv_sysconf(HV_SYSCONF_PAGE_SIZE_SMALL).
|
* See HV_DEFAULT_PAGE_SIZE_SMALL.
|
||||||
*/
|
*/
|
||||||
#define HV_LOG2_PAGE_SIZE_SMALL 16
|
#define HV_LOG2_DEFAULT_PAGE_SIZE_SMALL 16
|
||||||
|
|
||||||
/** The size of small pages, in bytes. This value should be verified
|
/** The initial size of small pages, in bytes. This value should be verified
|
||||||
* at runtime by calling hv_sysconf(HV_SYSCONF_PAGE_SIZE_SMALL).
|
* at runtime by calling hv_sysconf(HV_SYSCONF_PAGE_SIZE_SMALL).
|
||||||
|
* It may also be modified when installing a new context.
|
||||||
*/
|
*/
|
||||||
#define HV_PAGE_SIZE_SMALL (__HV_SIZE_ONE << HV_LOG2_PAGE_SIZE_SMALL)
|
#define HV_DEFAULT_PAGE_SIZE_SMALL \
|
||||||
|
(__HV_SIZE_ONE << HV_LOG2_DEFAULT_PAGE_SIZE_SMALL)
|
||||||
|
|
||||||
/** The log2 of the size of large pages, in bytes. This value should be
|
/** The log2 of the initial size of large pages, in bytes.
|
||||||
* verified at runtime by calling hv_sysconf(HV_SYSCONF_PAGE_SIZE_LARGE).
|
* See HV_DEFAULT_PAGE_SIZE_LARGE.
|
||||||
*/
|
*/
|
||||||
#define HV_LOG2_PAGE_SIZE_LARGE 24
|
#define HV_LOG2_DEFAULT_PAGE_SIZE_LARGE 24
|
||||||
|
|
||||||
/** The size of large pages, in bytes. This value should be verified
|
/** The initial size of large pages, in bytes. This value should be verified
|
||||||
* at runtime by calling hv_sysconf(HV_SYSCONF_PAGE_SIZE_LARGE).
|
* at runtime by calling hv_sysconf(HV_SYSCONF_PAGE_SIZE_LARGE).
|
||||||
|
* It may also be modified when installing a new context.
|
||||||
*/
|
*/
|
||||||
#define HV_PAGE_SIZE_LARGE (__HV_SIZE_ONE << HV_LOG2_PAGE_SIZE_LARGE)
|
#define HV_DEFAULT_PAGE_SIZE_LARGE \
|
||||||
|
(__HV_SIZE_ONE << HV_LOG2_DEFAULT_PAGE_SIZE_LARGE)
|
||||||
|
|
||||||
/** The log2 of the granularity at which page tables must be aligned;
|
/** The log2 of the granularity at which page tables must be aligned;
|
||||||
* in other words, the CPA for a page table must have this many zero
|
* in other words, the CPA for a page table must have this many zero
|
||||||
|
@ -401,7 +405,13 @@ typedef enum {
|
||||||
* that the temperature has hit an upper limit and is no longer being
|
* that the temperature has hit an upper limit and is no longer being
|
||||||
* accurately tracked.
|
* accurately tracked.
|
||||||
*/
|
*/
|
||||||
HV_SYSCONF_BOARD_TEMP = 6
|
HV_SYSCONF_BOARD_TEMP = 6,
|
||||||
|
|
||||||
|
/** Legal page size bitmask for hv_install_context().
|
||||||
|
* For example, if 16KB and 64KB small pages are supported,
|
||||||
|
* it would return "HV_CTX_PG_SM_16K | HV_CTX_PG_SM_64K".
|
||||||
|
*/
|
||||||
|
HV_SYSCONF_VALID_PAGE_SIZES = 7,
|
||||||
|
|
||||||
} HV_SysconfQuery;
|
} HV_SysconfQuery;
|
||||||
|
|
||||||
|
@ -654,6 +664,12 @@ void hv_set_rtc(HV_RTCTime time);
|
||||||
* new page table does not need to contain any mapping for the
|
* new page table does not need to contain any mapping for the
|
||||||
* hv_install_context address itself.
|
* hv_install_context address itself.
|
||||||
*
|
*
|
||||||
|
* At most one HV_CTX_PG_SM_* flag may be specified in "flags";
|
||||||
|
* if multiple flags are specified, HV_EINVAL is returned.
|
||||||
|
* Specifying none of the flags results in using the default page size.
|
||||||
|
* All cores participating in a given client must request the same
|
||||||
|
* page size, or the results are undefined.
|
||||||
|
*
|
||||||
* @param page_table Root of the page table.
|
* @param page_table Root of the page table.
|
||||||
* @param access PTE providing info on how to read the page table. This
|
* @param access PTE providing info on how to read the page table. This
|
||||||
* value must be consistent between multiple tiles sharing a page table,
|
* value must be consistent between multiple tiles sharing a page table,
|
||||||
|
@ -672,6 +688,11 @@ int hv_install_context(HV_PhysAddr page_table, HV_PTE access, HV_ASID asid,
|
||||||
#define HV_CTX_DIRECTIO 0x1 /**< Direct I/O requests are accepted from
|
#define HV_CTX_DIRECTIO 0x1 /**< Direct I/O requests are accepted from
|
||||||
PL0. */
|
PL0. */
|
||||||
|
|
||||||
|
#define HV_CTX_PG_SM_4K 0x10 /**< Use 4K small pages, if available. */
|
||||||
|
#define HV_CTX_PG_SM_16K 0x20 /**< Use 16K small pages, if available. */
|
||||||
|
#define HV_CTX_PG_SM_64K 0x40 /**< Use 64K small pages, if available. */
|
||||||
|
#define HV_CTX_PG_SM_MASK 0xf0 /**< Mask of all possible small pages. */
|
||||||
|
|
||||||
#ifndef __ASSEMBLER__
|
#ifndef __ASSEMBLER__
|
||||||
|
|
||||||
/** Value returned from hv_inquire_context(). */
|
/** Value returned from hv_inquire_context(). */
|
||||||
|
@ -1248,11 +1269,14 @@ HV_Errno hv_set_command_line(HV_VirtAddr buf, int length);
|
||||||
* with the existing priority pages) or "red/black" (if they don't).
|
* with the existing priority pages) or "red/black" (if they don't).
|
||||||
* The bitmask provides information on which parts of the cache
|
* The bitmask provides information on which parts of the cache
|
||||||
* have been used for pinned pages so far on this tile; if (1 << N)
|
* have been used for pinned pages so far on this tile; if (1 << N)
|
||||||
* appears in the bitmask, that indicates that a page has been marked
|
* appears in the bitmask, that indicates that a 4KB region of the
|
||||||
* "priority" whose PFN equals N, mod 8.
|
* cache starting at (N * 4KB) is in use by a "priority" page.
|
||||||
|
* The portion of cache used by a particular page can be computed
|
||||||
|
* by taking the page's PA, modulo CHIP_L2_CACHE_SIZE(), and setting
|
||||||
|
* all the "4KB" bits corresponding to the actual page size.
|
||||||
* @param bitmask A bitmap of priority page set values
|
* @param bitmask A bitmap of priority page set values
|
||||||
*/
|
*/
|
||||||
void hv_set_caching(unsigned int bitmask);
|
void hv_set_caching(unsigned long bitmask);
|
||||||
|
|
||||||
|
|
||||||
/** Zero out a specified number of pages.
|
/** Zero out a specified number of pages.
|
||||||
|
@ -1884,15 +1908,6 @@ int hv_flush_remote(HV_PhysAddr cache_pa, unsigned long cache_control,
|
||||||
of word */
|
of word */
|
||||||
#define HV_PTE_PTFN_BITS 29 /**< Number of bits in a PTFN */
|
#define HV_PTE_PTFN_BITS 29 /**< Number of bits in a PTFN */
|
||||||
|
|
||||||
/** Position of the PFN field within the PTE (subset of the PTFN). */
|
|
||||||
#define HV_PTE_INDEX_PFN (HV_PTE_INDEX_PTFN + (HV_LOG2_PAGE_SIZE_SMALL - \
|
|
||||||
HV_LOG2_PAGE_TABLE_ALIGN))
|
|
||||||
|
|
||||||
/** Length of the PFN field within the PTE (subset of the PTFN). */
|
|
||||||
#define HV_PTE_INDEX_PFN_BITS (HV_PTE_INDEX_PTFN_BITS - \
|
|
||||||
(HV_LOG2_PAGE_SIZE_SMALL - \
|
|
||||||
HV_LOG2_PAGE_TABLE_ALIGN))
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Legal values for the PTE's mode field
|
* Legal values for the PTE's mode field
|
||||||
*/
|
*/
|
||||||
|
@ -2245,40 +2260,11 @@ hv_pte_set_mode(HV_PTE pte, unsigned int val)
|
||||||
*
|
*
|
||||||
* This field contains the upper bits of the CPA (client physical
|
* This field contains the upper bits of the CPA (client physical
|
||||||
* address) of the target page; the complete CPA is this field with
|
* address) of the target page; the complete CPA is this field with
|
||||||
* HV_LOG2_PAGE_SIZE_SMALL zero bits appended to it.
|
* HV_LOG2_PAGE_TABLE_ALIGN zero bits appended to it.
|
||||||
*
|
*
|
||||||
* For PTEs in a level-1 page table where the Page bit is set, the
|
* For all PTEs in the lowest-level page table, and for all PTEs with
|
||||||
* CPA must be aligned modulo the large page size.
|
* the Page bit set in all page tables, the CPA must be aligned modulo
|
||||||
*/
|
* the relevant page size.
|
||||||
static __inline unsigned int
|
|
||||||
hv_pte_get_pfn(const HV_PTE pte)
|
|
||||||
{
|
|
||||||
return pte.val >> HV_PTE_INDEX_PFN;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** Set the page frame number into a PTE. See hv_pte_get_pfn. */
|
|
||||||
static __inline HV_PTE
|
|
||||||
hv_pte_set_pfn(HV_PTE pte, unsigned int val)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Note that the use of "PTFN" in the next line is intentional; we
|
|
||||||
* don't want any garbage lower bits left in that field.
|
|
||||||
*/
|
|
||||||
pte.val &= ~(((1ULL << HV_PTE_PTFN_BITS) - 1) << HV_PTE_INDEX_PTFN);
|
|
||||||
pte.val |= (__hv64) val << HV_PTE_INDEX_PFN;
|
|
||||||
return pte;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get the page table frame number from the PTE.
|
|
||||||
*
|
|
||||||
* This field contains the upper bits of the CPA (client physical
|
|
||||||
* address) of the target page table; the complete CPA is this field with
|
|
||||||
* with HV_PAGE_TABLE_ALIGN zero bits appended to it.
|
|
||||||
*
|
|
||||||
* For PTEs in a level-1 page table when the Page bit is not set, the
|
|
||||||
* CPA must be aligned modulo the sticter of HV_PAGE_TABLE_ALIGN and
|
|
||||||
* the level-2 page table size.
|
|
||||||
*/
|
*/
|
||||||
static __inline unsigned long
|
static __inline unsigned long
|
||||||
hv_pte_get_ptfn(const HV_PTE pte)
|
hv_pte_get_ptfn(const HV_PTE pte)
|
||||||
|
@ -2286,7 +2272,6 @@ hv_pte_get_ptfn(const HV_PTE pte)
|
||||||
return pte.val >> HV_PTE_INDEX_PTFN;
|
return pte.val >> HV_PTE_INDEX_PTFN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/** Set the page table frame number into a PTE. See hv_pte_get_ptfn. */
|
/** Set the page table frame number into a PTE. See hv_pte_get_ptfn. */
|
||||||
static __inline HV_PTE
|
static __inline HV_PTE
|
||||||
hv_pte_set_ptfn(HV_PTE pte, unsigned long val)
|
hv_pte_set_ptfn(HV_PTE pte, unsigned long val)
|
||||||
|
@ -2296,6 +2281,20 @@ hv_pte_set_ptfn(HV_PTE pte, unsigned long val)
|
||||||
return pte;
|
return pte;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Get the client physical address from the PTE. See hv_pte_set_ptfn. */
|
||||||
|
static __inline HV_PhysAddr
|
||||||
|
hv_pte_get_pa(const HV_PTE pte)
|
||||||
|
{
|
||||||
|
return (__hv64) hv_pte_get_ptfn(pte) << HV_LOG2_PAGE_TABLE_ALIGN;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Set the client physical address into a PTE. See hv_pte_get_ptfn. */
|
||||||
|
static __inline HV_PTE
|
||||||
|
hv_pte_set_pa(HV_PTE pte, HV_PhysAddr pa)
|
||||||
|
{
|
||||||
|
return hv_pte_set_ptfn(pte, pa >> HV_LOG2_PAGE_TABLE_ALIGN);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/** Get the remote tile caching this page.
|
/** Get the remote tile caching this page.
|
||||||
*
|
*
|
||||||
|
@ -2331,28 +2330,20 @@ hv_pte_set_lotar(HV_PTE pte, unsigned int val)
|
||||||
|
|
||||||
#endif /* !__ASSEMBLER__ */
|
#endif /* !__ASSEMBLER__ */
|
||||||
|
|
||||||
/** Converts a client physical address to a pfn. */
|
|
||||||
#define HV_CPA_TO_PFN(p) ((p) >> HV_LOG2_PAGE_SIZE_SMALL)
|
|
||||||
|
|
||||||
/** Converts a pfn to a client physical address. */
|
|
||||||
#define HV_PFN_TO_CPA(p) (((HV_PhysAddr)(p)) << HV_LOG2_PAGE_SIZE_SMALL)
|
|
||||||
|
|
||||||
/** Converts a client physical address to a ptfn. */
|
/** Converts a client physical address to a ptfn. */
|
||||||
#define HV_CPA_TO_PTFN(p) ((p) >> HV_LOG2_PAGE_TABLE_ALIGN)
|
#define HV_CPA_TO_PTFN(p) ((p) >> HV_LOG2_PAGE_TABLE_ALIGN)
|
||||||
|
|
||||||
/** Converts a ptfn to a client physical address. */
|
/** Converts a ptfn to a client physical address. */
|
||||||
#define HV_PTFN_TO_CPA(p) (((HV_PhysAddr)(p)) << HV_LOG2_PAGE_TABLE_ALIGN)
|
#define HV_PTFN_TO_CPA(p) (((HV_PhysAddr)(p)) << HV_LOG2_PAGE_TABLE_ALIGN)
|
||||||
|
|
||||||
/** Converts a ptfn to a pfn. */
|
|
||||||
#define HV_PTFN_TO_PFN(p) \
|
|
||||||
((p) >> (HV_LOG2_PAGE_SIZE_SMALL - HV_LOG2_PAGE_TABLE_ALIGN))
|
|
||||||
|
|
||||||
/** Converts a pfn to a ptfn. */
|
|
||||||
#define HV_PFN_TO_PTFN(p) \
|
|
||||||
((p) << (HV_LOG2_PAGE_SIZE_SMALL - HV_LOG2_PAGE_TABLE_ALIGN))
|
|
||||||
|
|
||||||
#if CHIP_VA_WIDTH() > 32
|
#if CHIP_VA_WIDTH() > 32
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Note that we currently do not allow customizing the page size
|
||||||
|
* of the L0 pages, but fix them at 4GB, so we do not use the
|
||||||
|
* "_HV_xxx" nomenclature for the L0 macros.
|
||||||
|
*/
|
||||||
|
|
||||||
/** Log number of HV_PTE entries in L0 page table */
|
/** Log number of HV_PTE entries in L0 page table */
|
||||||
#define HV_LOG2_L0_ENTRIES (CHIP_VA_WIDTH() - HV_LOG2_L1_SPAN)
|
#define HV_LOG2_L0_ENTRIES (CHIP_VA_WIDTH() - HV_LOG2_L1_SPAN)
|
||||||
|
|
||||||
|
@ -2382,69 +2373,104 @@ hv_pte_set_lotar(HV_PTE pte, unsigned int val)
|
||||||
#endif /* CHIP_VA_WIDTH() > 32 */
|
#endif /* CHIP_VA_WIDTH() > 32 */
|
||||||
|
|
||||||
/** Log number of HV_PTE entries in L1 page table */
|
/** Log number of HV_PTE entries in L1 page table */
|
||||||
#define HV_LOG2_L1_ENTRIES (HV_LOG2_L1_SPAN - HV_LOG2_PAGE_SIZE_LARGE)
|
#define _HV_LOG2_L1_ENTRIES(log2_page_size_large) \
|
||||||
|
(HV_LOG2_L1_SPAN - log2_page_size_large)
|
||||||
|
|
||||||
/** Number of HV_PTE entries in L1 page table */
|
/** Number of HV_PTE entries in L1 page table */
|
||||||
#define HV_L1_ENTRIES (1 << HV_LOG2_L1_ENTRIES)
|
#define _HV_L1_ENTRIES(log2_page_size_large) \
|
||||||
|
(1 << _HV_LOG2_L1_ENTRIES(log2_page_size_large))
|
||||||
|
|
||||||
/** Log size of L1 page table in bytes */
|
/** Log size of L1 page table in bytes */
|
||||||
#define HV_LOG2_L1_SIZE (HV_LOG2_PTE_SIZE + HV_LOG2_L1_ENTRIES)
|
#define _HV_LOG2_L1_SIZE(log2_page_size_large) \
|
||||||
|
(HV_LOG2_PTE_SIZE + _HV_LOG2_L1_ENTRIES(log2_page_size_large))
|
||||||
|
|
||||||
/** Size of L1 page table in bytes */
|
/** Size of L1 page table in bytes */
|
||||||
#define HV_L1_SIZE (1 << HV_LOG2_L1_SIZE)
|
#define _HV_L1_SIZE(log2_page_size_large) \
|
||||||
|
(1 << _HV_LOG2_L1_SIZE(log2_page_size_large))
|
||||||
|
|
||||||
/** Log number of HV_PTE entries in level-2 page table */
|
/** Log number of HV_PTE entries in level-2 page table */
|
||||||
#define HV_LOG2_L2_ENTRIES (HV_LOG2_PAGE_SIZE_LARGE - HV_LOG2_PAGE_SIZE_SMALL)
|
#define _HV_LOG2_L2_ENTRIES(log2_page_size_large, log2_page_size_small) \
|
||||||
|
(log2_page_size_large - log2_page_size_small)
|
||||||
|
|
||||||
/** Number of HV_PTE entries in level-2 page table */
|
/** Number of HV_PTE entries in level-2 page table */
|
||||||
#define HV_L2_ENTRIES (1 << HV_LOG2_L2_ENTRIES)
|
#define _HV_L2_ENTRIES(log2_page_size_large, log2_page_size_small) \
|
||||||
|
(1 << _HV_LOG2_L2_ENTRIES(log2_page_size_large, log2_page_size_small))
|
||||||
|
|
||||||
/** Log size of level-2 page table in bytes */
|
/** Log size of level-2 page table in bytes */
|
||||||
#define HV_LOG2_L2_SIZE (HV_LOG2_PTE_SIZE + HV_LOG2_L2_ENTRIES)
|
#define _HV_LOG2_L2_SIZE(log2_page_size_large, log2_page_size_small) \
|
||||||
|
(HV_LOG2_PTE_SIZE + \
|
||||||
|
_HV_LOG2_L2_ENTRIES(log2_page_size_large, log2_page_size_small))
|
||||||
|
|
||||||
/** Size of level-2 page table in bytes */
|
/** Size of level-2 page table in bytes */
|
||||||
#define HV_L2_SIZE (1 << HV_LOG2_L2_SIZE)
|
#define _HV_L2_SIZE(log2_page_size_large, log2_page_size_small) \
|
||||||
|
(1 << _HV_LOG2_L2_SIZE(log2_page_size_large, log2_page_size_small))
|
||||||
|
|
||||||
#ifdef __ASSEMBLER__
|
#ifdef __ASSEMBLER__
|
||||||
|
|
||||||
#if CHIP_VA_WIDTH() > 32
|
#if CHIP_VA_WIDTH() > 32
|
||||||
|
|
||||||
/** Index in L1 for a specific VA */
|
/** Index in L1 for a specific VA */
|
||||||
#define HV_L1_INDEX(va) \
|
#define _HV_L1_INDEX(va, log2_page_size_large) \
|
||||||
(((va) >> HV_LOG2_PAGE_SIZE_LARGE) & (HV_L1_ENTRIES - 1))
|
(((va) >> log2_page_size_large) & (_HV_L1_ENTRIES(log2_page_size_large) - 1))
|
||||||
|
|
||||||
#else /* CHIP_VA_WIDTH() > 32 */
|
#else /* CHIP_VA_WIDTH() > 32 */
|
||||||
|
|
||||||
/** Index in L1 for a specific VA */
|
/** Index in L1 for a specific VA */
|
||||||
#define HV_L1_INDEX(va) \
|
#define _HV_L1_INDEX(va, log2_page_size_large) \
|
||||||
(((va) >> HV_LOG2_PAGE_SIZE_LARGE))
|
(((va) >> log2_page_size_large))
|
||||||
|
|
||||||
#endif /* CHIP_VA_WIDTH() > 32 */
|
#endif /* CHIP_VA_WIDTH() > 32 */
|
||||||
|
|
||||||
/** Index in level-2 page table for a specific VA */
|
/** Index in level-2 page table for a specific VA */
|
||||||
#define HV_L2_INDEX(va) \
|
#define _HV_L2_INDEX(va, log2_page_size_large, log2_page_size_small) \
|
||||||
(((va) >> HV_LOG2_PAGE_SIZE_SMALL) & (HV_L2_ENTRIES - 1))
|
(((va) >> log2_page_size_small) & \
|
||||||
|
(_HV_L2_ENTRIES(log2_page_size_large, log2_page_size_small) - 1))
|
||||||
|
|
||||||
#else /* __ASSEMBLER __ */
|
#else /* __ASSEMBLER __ */
|
||||||
|
|
||||||
#if CHIP_VA_WIDTH() > 32
|
#if CHIP_VA_WIDTH() > 32
|
||||||
|
|
||||||
/** Index in L1 for a specific VA */
|
/** Index in L1 for a specific VA */
|
||||||
#define HV_L1_INDEX(va) \
|
#define _HV_L1_INDEX(va, log2_page_size_large) \
|
||||||
(((HV_VirtAddr)(va) >> HV_LOG2_PAGE_SIZE_LARGE) & (HV_L1_ENTRIES - 1))
|
(((HV_VirtAddr)(va) >> log2_page_size_large) & \
|
||||||
|
(_HV_L1_ENTRIES(log2_page_size_large) - 1))
|
||||||
|
|
||||||
#else /* CHIP_VA_WIDTH() > 32 */
|
#else /* CHIP_VA_WIDTH() > 32 */
|
||||||
|
|
||||||
/** Index in L1 for a specific VA */
|
/** Index in L1 for a specific VA */
|
||||||
#define HV_L1_INDEX(va) \
|
#define _HV_L1_INDEX(va, log2_page_size_large) \
|
||||||
(((HV_VirtAddr)(va) >> HV_LOG2_PAGE_SIZE_LARGE))
|
(((HV_VirtAddr)(va) >> log2_page_size_large))
|
||||||
|
|
||||||
#endif /* CHIP_VA_WIDTH() > 32 */
|
#endif /* CHIP_VA_WIDTH() > 32 */
|
||||||
|
|
||||||
/** Index in level-2 page table for a specific VA */
|
/** Index in level-2 page table for a specific VA */
|
||||||
#define HV_L2_INDEX(va) \
|
#define _HV_L2_INDEX(va, log2_page_size_large, log2_page_size_small) \
|
||||||
(((HV_VirtAddr)(va) >> HV_LOG2_PAGE_SIZE_SMALL) & (HV_L2_ENTRIES - 1))
|
(((HV_VirtAddr)(va) >> log2_page_size_small) & \
|
||||||
|
(_HV_L2_ENTRIES(log2_page_size_large, log2_page_size_small) - 1))
|
||||||
|
|
||||||
#endif /* __ASSEMBLER __ */
|
#endif /* __ASSEMBLER __ */
|
||||||
|
|
||||||
#endif /* _TILE_HV_H */
|
/** Position of the PFN field within the PTE (subset of the PTFN). */
|
||||||
|
#define _HV_PTE_INDEX_PFN(log2_page_size) \
|
||||||
|
(HV_PTE_INDEX_PTFN + (log2_page_size - HV_LOG2_PAGE_TABLE_ALIGN))
|
||||||
|
|
||||||
|
/** Length of the PFN field within the PTE (subset of the PTFN). */
|
||||||
|
#define _HV_PTE_INDEX_PFN_BITS(log2_page_size) \
|
||||||
|
(HV_PTE_INDEX_PTFN_BITS - (log2_page_size - HV_LOG2_PAGE_TABLE_ALIGN))
|
||||||
|
|
||||||
|
/** Converts a client physical address to a pfn. */
|
||||||
|
#define _HV_CPA_TO_PFN(p, log2_page_size) ((p) >> log2_page_size)
|
||||||
|
|
||||||
|
/** Converts a pfn to a client physical address. */
|
||||||
|
#define _HV_PFN_TO_CPA(p, log2_page_size) \
|
||||||
|
(((HV_PhysAddr)(p)) << log2_page_size)
|
||||||
|
|
||||||
|
/** Converts a ptfn to a pfn. */
|
||||||
|
#define _HV_PTFN_TO_PFN(p, log2_page_size) \
|
||||||
|
((p) >> (log2_page_size - HV_LOG2_PAGE_TABLE_ALIGN))
|
||||||
|
|
||||||
|
/** Converts a pfn to a ptfn. */
|
||||||
|
#define _HV_PFN_TO_PTFN(p, log2_page_size) \
|
||||||
|
((p) << (log2_page_size - HV_LOG2_PAGE_TABLE_ALIGN))
|
||||||
|
|
||||||
|
#endif /* _HV_HV_H */
|
||||||
|
|
|
@ -69,7 +69,7 @@ ENTRY(_start)
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
moveli lr, lo16(1f)
|
moveli lr, lo16(1f)
|
||||||
move r5, zero
|
moveli r5, CTX_PAGE_FLAG
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
auli lr, lr, ha16(1f)
|
auli lr, lr, ha16(1f)
|
||||||
|
@ -141,11 +141,11 @@ ENTRY(empty_zero_page)
|
||||||
|
|
||||||
.macro PTE va, cpa, bits1, no_org=0
|
.macro PTE va, cpa, bits1, no_org=0
|
||||||
.ifeq \no_org
|
.ifeq \no_org
|
||||||
.org swapper_pg_dir + HV_L1_INDEX(\va) * HV_PTE_SIZE
|
.org swapper_pg_dir + PGD_INDEX(\va) * HV_PTE_SIZE
|
||||||
.endif
|
.endif
|
||||||
.word HV_PTE_PAGE | HV_PTE_DIRTY | HV_PTE_PRESENT | HV_PTE_ACCESSED | \
|
.word HV_PTE_PAGE | HV_PTE_DIRTY | HV_PTE_PRESENT | HV_PTE_ACCESSED | \
|
||||||
(HV_PTE_MODE_CACHE_NO_L3 << HV_PTE_INDEX_MODE)
|
(HV_PTE_MODE_CACHE_NO_L3 << HV_PTE_INDEX_MODE)
|
||||||
.word (\bits1) | (HV_CPA_TO_PFN(\cpa) << (HV_PTE_INDEX_PFN - 32))
|
.word (\bits1) | (HV_CPA_TO_PTFN(\cpa) << (HV_PTE_INDEX_PTFN - 32))
|
||||||
.endm
|
.endm
|
||||||
|
|
||||||
__PAGE_ALIGNED_DATA
|
__PAGE_ALIGNED_DATA
|
||||||
|
@ -166,7 +166,7 @@ ENTRY(swapper_pg_dir)
|
||||||
/* The true text VAs are mapped as VA = PA + MEM_SV_INTRPT */
|
/* The true text VAs are mapped as VA = PA + MEM_SV_INTRPT */
|
||||||
PTE MEM_SV_INTRPT, 0, (1 << (HV_PTE_INDEX_READABLE - 32)) | \
|
PTE MEM_SV_INTRPT, 0, (1 << (HV_PTE_INDEX_READABLE - 32)) | \
|
||||||
(1 << (HV_PTE_INDEX_EXECUTABLE - 32))
|
(1 << (HV_PTE_INDEX_EXECUTABLE - 32))
|
||||||
.org swapper_pg_dir + HV_L1_SIZE
|
.org swapper_pg_dir + PGDIR_SIZE
|
||||||
END(swapper_pg_dir)
|
END(swapper_pg_dir)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -114,7 +114,7 @@ ENTRY(_start)
|
||||||
shl16insli r0, r0, hw0(swapper_pg_dir - PAGE_OFFSET)
|
shl16insli r0, r0, hw0(swapper_pg_dir - PAGE_OFFSET)
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
move r3, zero
|
moveli r3, CTX_PAGE_FLAG
|
||||||
j hv_install_context
|
j hv_install_context
|
||||||
}
|
}
|
||||||
1:
|
1:
|
||||||
|
@ -210,19 +210,19 @@ ENTRY(empty_zero_page)
|
||||||
.macro PTE cpa, bits1
|
.macro PTE cpa, bits1
|
||||||
.quad HV_PTE_PAGE | HV_PTE_DIRTY | HV_PTE_PRESENT | HV_PTE_ACCESSED |\
|
.quad HV_PTE_PAGE | HV_PTE_DIRTY | HV_PTE_PRESENT | HV_PTE_ACCESSED |\
|
||||||
HV_PTE_GLOBAL | (HV_PTE_MODE_CACHE_NO_L3 << HV_PTE_INDEX_MODE) |\
|
HV_PTE_GLOBAL | (HV_PTE_MODE_CACHE_NO_L3 << HV_PTE_INDEX_MODE) |\
|
||||||
(\bits1) | (HV_CPA_TO_PFN(\cpa) << HV_PTE_INDEX_PFN)
|
(\bits1) | (HV_CPA_TO_PTFN(\cpa) << HV_PTE_INDEX_PTFN)
|
||||||
.endm
|
.endm
|
||||||
|
|
||||||
__PAGE_ALIGNED_DATA
|
__PAGE_ALIGNED_DATA
|
||||||
.align PAGE_SIZE
|
.align PAGE_SIZE
|
||||||
ENTRY(swapper_pg_dir)
|
ENTRY(swapper_pg_dir)
|
||||||
.org swapper_pg_dir + HV_L0_INDEX(PAGE_OFFSET) * HV_PTE_SIZE
|
.org swapper_pg_dir + PGD_INDEX(PAGE_OFFSET) * HV_PTE_SIZE
|
||||||
.Lsv_data_pmd:
|
.Lsv_data_pmd:
|
||||||
.quad 0 /* PTE temp_data_pmd - PAGE_OFFSET, 0 */
|
.quad 0 /* PTE temp_data_pmd - PAGE_OFFSET, 0 */
|
||||||
.org swapper_pg_dir + HV_L0_INDEX(MEM_SV_START) * HV_PTE_SIZE
|
.org swapper_pg_dir + PGD_INDEX(MEM_SV_START) * HV_PTE_SIZE
|
||||||
.Lsv_code_pmd:
|
.Lsv_code_pmd:
|
||||||
.quad 0 /* PTE temp_code_pmd - PAGE_OFFSET, 0 */
|
.quad 0 /* PTE temp_code_pmd - PAGE_OFFSET, 0 */
|
||||||
.org swapper_pg_dir + HV_L0_SIZE
|
.org swapper_pg_dir + SIZEOF_PGD
|
||||||
END(swapper_pg_dir)
|
END(swapper_pg_dir)
|
||||||
|
|
||||||
.align HV_PAGE_TABLE_ALIGN
|
.align HV_PAGE_TABLE_ALIGN
|
||||||
|
@ -233,11 +233,11 @@ ENTRY(temp_data_pmd)
|
||||||
* permissions later.
|
* permissions later.
|
||||||
*/
|
*/
|
||||||
.set addr, 0
|
.set addr, 0
|
||||||
.rept HV_L1_ENTRIES
|
.rept PTRS_PER_PMD
|
||||||
PTE addr, HV_PTE_READABLE | HV_PTE_WRITABLE
|
PTE addr, HV_PTE_READABLE | HV_PTE_WRITABLE
|
||||||
.set addr, addr + HV_PAGE_SIZE_LARGE
|
.set addr, addr + HPAGE_SIZE
|
||||||
.endr
|
.endr
|
||||||
.org temp_data_pmd + HV_L1_SIZE
|
.org temp_data_pmd + SIZEOF_PMD
|
||||||
END(temp_data_pmd)
|
END(temp_data_pmd)
|
||||||
|
|
||||||
.align HV_PAGE_TABLE_ALIGN
|
.align HV_PAGE_TABLE_ALIGN
|
||||||
|
@ -248,11 +248,11 @@ ENTRY(temp_code_pmd)
|
||||||
* permissions later.
|
* permissions later.
|
||||||
*/
|
*/
|
||||||
.set addr, 0
|
.set addr, 0
|
||||||
.rept HV_L1_ENTRIES
|
.rept PTRS_PER_PMD
|
||||||
PTE addr, HV_PTE_READABLE | HV_PTE_EXECUTABLE
|
PTE addr, HV_PTE_READABLE | HV_PTE_EXECUTABLE
|
||||||
.set addr, addr + HV_PAGE_SIZE_LARGE
|
.set addr, addr + HPAGE_SIZE
|
||||||
.endr
|
.endr
|
||||||
.org temp_code_pmd + HV_L1_SIZE
|
.org temp_code_pmd + SIZEOF_PMD
|
||||||
END(temp_code_pmd)
|
END(temp_code_pmd)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -251,6 +251,7 @@ static void setup_quasi_va_is_pa(void)
|
||||||
void machine_kexec(struct kimage *image)
|
void machine_kexec(struct kimage *image)
|
||||||
{
|
{
|
||||||
void *reboot_code_buffer;
|
void *reboot_code_buffer;
|
||||||
|
pte_t *ptep;
|
||||||
void (*rnk)(unsigned long, void *, unsigned long)
|
void (*rnk)(unsigned long, void *, unsigned long)
|
||||||
__noreturn;
|
__noreturn;
|
||||||
|
|
||||||
|
@ -266,8 +267,10 @@ void machine_kexec(struct kimage *image)
|
||||||
*/
|
*/
|
||||||
homecache_change_page_home(image->control_code_page, 0,
|
homecache_change_page_home(image->control_code_page, 0,
|
||||||
smp_processor_id());
|
smp_processor_id());
|
||||||
reboot_code_buffer = vmap(&image->control_code_page, 1, 0,
|
reboot_code_buffer = page_address(image->control_code_page);
|
||||||
__pgprot(_PAGE_KERNEL | _PAGE_EXECUTABLE));
|
BUG_ON(reboot_code_buffer == NULL);
|
||||||
|
ptep = virt_to_pte(NULL, (unsigned long)reboot_code_buffer);
|
||||||
|
__set_pte(ptep, pte_mkexec(*ptep));
|
||||||
memcpy(reboot_code_buffer, relocate_new_kernel,
|
memcpy(reboot_code_buffer, relocate_new_kernel,
|
||||||
relocate_new_kernel_size);
|
relocate_new_kernel_size);
|
||||||
__flush_icache_range(
|
__flush_icache_range(
|
||||||
|
|
|
@ -1396,13 +1396,13 @@ void __init setup_per_cpu_areas(void)
|
||||||
for (i = 0; i < size; i += PAGE_SIZE, ++pfn, ++pg) {
|
for (i = 0; i < size; i += PAGE_SIZE, ++pfn, ++pg) {
|
||||||
|
|
||||||
/* Update the vmalloc mapping and page home. */
|
/* Update the vmalloc mapping and page home. */
|
||||||
pte_t *ptep =
|
unsigned long addr = (unsigned long)ptr + i;
|
||||||
virt_to_pte(NULL, (unsigned long)ptr + i);
|
pte_t *ptep = virt_to_pte(NULL, addr);
|
||||||
pte_t pte = *ptep;
|
pte_t pte = *ptep;
|
||||||
BUG_ON(pfn != pte_pfn(pte));
|
BUG_ON(pfn != pte_pfn(pte));
|
||||||
pte = hv_pte_set_mode(pte, HV_PTE_MODE_CACHE_TILE_L3);
|
pte = hv_pte_set_mode(pte, HV_PTE_MODE_CACHE_TILE_L3);
|
||||||
pte = set_remote_cache_cpu(pte, cpu);
|
pte = set_remote_cache_cpu(pte, cpu);
|
||||||
set_pte(ptep, pte);
|
set_pte_at(&init_mm, addr, ptep, pte);
|
||||||
|
|
||||||
/* Update the lowmem mapping for consistency. */
|
/* Update the lowmem mapping for consistency. */
|
||||||
lowmem_va = (unsigned long)pfn_to_kaddr(pfn);
|
lowmem_va = (unsigned long)pfn_to_kaddr(pfn);
|
||||||
|
@ -1415,7 +1415,7 @@ void __init setup_per_cpu_areas(void)
|
||||||
BUG_ON(pte_huge(*ptep));
|
BUG_ON(pte_huge(*ptep));
|
||||||
}
|
}
|
||||||
BUG_ON(pfn != pte_pfn(*ptep));
|
BUG_ON(pfn != pte_pfn(*ptep));
|
||||||
set_pte(ptep, pte);
|
set_pte_at(&init_mm, lowmem_va, ptep, pte);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -203,7 +203,7 @@ void __init ipi_init(void)
|
||||||
if (hv_get_ipi_pte(tile, KERNEL_PL, &pte) != 0)
|
if (hv_get_ipi_pte(tile, KERNEL_PL, &pte) != 0)
|
||||||
panic("Failed to initialize IPI for cpu %d\n", cpu);
|
panic("Failed to initialize IPI for cpu %d\n", cpu);
|
||||||
|
|
||||||
offset = hv_pte_get_pfn(pte) << PAGE_SHIFT;
|
offset = PFN_PHYS(pte_pfn(pte));
|
||||||
ipi_mappings[cpu] = ioremap_prot(offset, PAGE_SIZE, pte);
|
ipi_mappings[cpu] = ioremap_prot(offset, PAGE_SIZE, pte);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -160,7 +160,7 @@ static unsigned long fast_copy(void *dest, const void *source, int len,
|
||||||
break;
|
break;
|
||||||
if (get_remote_cache_cpu(src_pte) == smp_processor_id())
|
if (get_remote_cache_cpu(src_pte) == smp_processor_id())
|
||||||
break;
|
break;
|
||||||
src_page = pfn_to_page(hv_pte_get_pfn(src_pte));
|
src_page = pfn_to_page(pte_pfn(src_pte));
|
||||||
get_page(src_page);
|
get_page(src_page);
|
||||||
if (pte_val(src_pte) != pte_val(*src_ptep)) {
|
if (pte_val(src_pte) != pte_val(*src_ptep)) {
|
||||||
put_page(src_page);
|
put_page(src_page);
|
||||||
|
@ -168,7 +168,7 @@ static unsigned long fast_copy(void *dest, const void *source, int len,
|
||||||
}
|
}
|
||||||
if (pte_huge(src_pte)) {
|
if (pte_huge(src_pte)) {
|
||||||
/* Adjust the PTE to correspond to a small page */
|
/* Adjust the PTE to correspond to a small page */
|
||||||
int pfn = hv_pte_get_pfn(src_pte);
|
int pfn = pte_pfn(src_pte);
|
||||||
pfn += (((unsigned long)source & (HPAGE_SIZE-1))
|
pfn += (((unsigned long)source & (HPAGE_SIZE-1))
|
||||||
>> PAGE_SHIFT);
|
>> PAGE_SHIFT);
|
||||||
src_pte = pfn_pte(pfn, src_pte);
|
src_pte = pfn_pte(pfn, src_pte);
|
||||||
|
@ -188,7 +188,7 @@ static unsigned long fast_copy(void *dest, const void *source, int len,
|
||||||
put_page(src_page);
|
put_page(src_page);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
dst_page = pfn_to_page(hv_pte_get_pfn(dst_pte));
|
dst_page = pfn_to_page(pte_pfn(dst_pte));
|
||||||
if (dst_page == src_page) {
|
if (dst_page == src_page) {
|
||||||
/*
|
/*
|
||||||
* Source and dest are on the same page; this
|
* Source and dest are on the same page; this
|
||||||
|
@ -206,7 +206,7 @@ static unsigned long fast_copy(void *dest, const void *source, int len,
|
||||||
}
|
}
|
||||||
if (pte_huge(dst_pte)) {
|
if (pte_huge(dst_pte)) {
|
||||||
/* Adjust the PTE to correspond to a small page */
|
/* Adjust the PTE to correspond to a small page */
|
||||||
int pfn = hv_pte_get_pfn(dst_pte);
|
int pfn = pte_pfn(dst_pte);
|
||||||
pfn += (((unsigned long)dest & (HPAGE_SIZE-1))
|
pfn += (((unsigned long)dest & (HPAGE_SIZE-1))
|
||||||
>> PAGE_SHIFT);
|
>> PAGE_SHIFT);
|
||||||
dst_pte = pfn_pte(pfn, dst_pte);
|
dst_pte = pfn_pte(pfn, dst_pte);
|
||||||
|
|
|
@ -82,7 +82,7 @@ static int num_l2_ptes[MAX_NUMNODES];
|
||||||
|
|
||||||
static void init_prealloc_ptes(int node, int pages)
|
static void init_prealloc_ptes(int node, int pages)
|
||||||
{
|
{
|
||||||
BUG_ON(pages & (HV_L2_ENTRIES-1));
|
BUG_ON(pages & (PTRS_PER_PTE - 1));
|
||||||
if (pages) {
|
if (pages) {
|
||||||
num_l2_ptes[node] = pages;
|
num_l2_ptes[node] = pages;
|
||||||
l2_ptes[node] = __alloc_bootmem(pages * sizeof(pte_t),
|
l2_ptes[node] = __alloc_bootmem(pages * sizeof(pte_t),
|
||||||
|
@ -131,14 +131,9 @@ static void __init assign_pte(pmd_t *pmd, pte_t *page_table)
|
||||||
|
|
||||||
#ifdef __tilegx__
|
#ifdef __tilegx__
|
||||||
|
|
||||||
#if HV_L1_SIZE != HV_L2_SIZE
|
|
||||||
# error Rework assumption that L1 and L2 page tables are same size.
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Since pmd_t arrays and pte_t arrays are the same size, just use casts. */
|
|
||||||
static inline pmd_t *alloc_pmd(void)
|
static inline pmd_t *alloc_pmd(void)
|
||||||
{
|
{
|
||||||
return (pmd_t *)alloc_pte();
|
return __alloc_bootmem(L1_KERNEL_PGTABLE_SIZE, HV_PAGE_TABLE_ALIGN, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void assign_pmd(pud_t *pud, pmd_t *pmd)
|
static inline void assign_pmd(pud_t *pud, pmd_t *pmd)
|
||||||
|
@ -811,7 +806,7 @@ void __init paging_init(void)
|
||||||
* changing init_mm once we get up and running, and there's no
|
* changing init_mm once we get up and running, and there's no
|
||||||
* need for e.g. vmalloc_sync_all().
|
* need for e.g. vmalloc_sync_all().
|
||||||
*/
|
*/
|
||||||
BUILD_BUG_ON(pgd_index(VMALLOC_START) != pgd_index(VMALLOC_END));
|
BUILD_BUG_ON(pgd_index(VMALLOC_START) != pgd_index(VMALLOC_END - 1));
|
||||||
pud = pud_offset(pgd_base + pgd_index(VMALLOC_START), VMALLOC_START);
|
pud = pud_offset(pgd_base + pgd_index(VMALLOC_START), VMALLOC_START);
|
||||||
assign_pmd(pud, alloc_pmd());
|
assign_pmd(pud, alloc_pmd());
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -289,13 +289,12 @@ void pgd_free(struct mm_struct *mm, pgd_t *pgd)
|
||||||
|
|
||||||
#define L2_USER_PGTABLE_PAGES (1 << L2_USER_PGTABLE_ORDER)
|
#define L2_USER_PGTABLE_PAGES (1 << L2_USER_PGTABLE_ORDER)
|
||||||
|
|
||||||
struct page *pte_alloc_one(struct mm_struct *mm, unsigned long address)
|
struct page *pgtable_alloc_one(struct mm_struct *mm, unsigned long address,
|
||||||
|
int order)
|
||||||
{
|
{
|
||||||
gfp_t flags = GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO;
|
gfp_t flags = GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO;
|
||||||
struct page *p;
|
struct page *p;
|
||||||
#if L2_USER_PGTABLE_ORDER > 0
|
|
||||||
int i;
|
int i;
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef CONFIG_HIGHPTE
|
#ifdef CONFIG_HIGHPTE
|
||||||
flags |= __GFP_HIGHMEM;
|
flags |= __GFP_HIGHMEM;
|
||||||
|
@ -305,17 +304,15 @@ struct page *pte_alloc_one(struct mm_struct *mm, unsigned long address)
|
||||||
if (p == NULL)
|
if (p == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
#if L2_USER_PGTABLE_ORDER > 0
|
|
||||||
/*
|
/*
|
||||||
* Make every page have a page_count() of one, not just the first.
|
* Make every page have a page_count() of one, not just the first.
|
||||||
* We don't use __GFP_COMP since it doesn't look like it works
|
* We don't use __GFP_COMP since it doesn't look like it works
|
||||||
* correctly with tlb_remove_page().
|
* correctly with tlb_remove_page().
|
||||||
*/
|
*/
|
||||||
for (i = 1; i < L2_USER_PGTABLE_PAGES; ++i) {
|
for (i = 1; i < order; ++i) {
|
||||||
init_page_count(p+i);
|
init_page_count(p+i);
|
||||||
inc_zone_page_state(p+i, NR_PAGETABLE);
|
inc_zone_page_state(p+i, NR_PAGETABLE);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
pgtable_page_ctor(p);
|
pgtable_page_ctor(p);
|
||||||
return p;
|
return p;
|
||||||
|
@ -326,28 +323,28 @@ struct page *pte_alloc_one(struct mm_struct *mm, unsigned long address)
|
||||||
* process). We have to correct whatever pte_alloc_one() did before
|
* process). We have to correct whatever pte_alloc_one() did before
|
||||||
* returning the pages to the allocator.
|
* returning the pages to the allocator.
|
||||||
*/
|
*/
|
||||||
void pte_free(struct mm_struct *mm, struct page *p)
|
void pgtable_free(struct mm_struct *mm, struct page *p, int order)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
pgtable_page_dtor(p);
|
pgtable_page_dtor(p);
|
||||||
__free_page(p);
|
__free_page(p);
|
||||||
|
|
||||||
for (i = 1; i < L2_USER_PGTABLE_PAGES; ++i) {
|
for (i = 1; i < order; ++i) {
|
||||||
__free_page(p+i);
|
__free_page(p+i);
|
||||||
dec_zone_page_state(p+i, NR_PAGETABLE);
|
dec_zone_page_state(p+i, NR_PAGETABLE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void __pte_free_tlb(struct mmu_gather *tlb, struct page *pte,
|
void __pgtable_free_tlb(struct mmu_gather *tlb, struct page *pte,
|
||||||
unsigned long address)
|
unsigned long address, int order)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
pgtable_page_dtor(pte);
|
pgtable_page_dtor(pte);
|
||||||
tlb_remove_page(tlb, pte);
|
tlb_remove_page(tlb, pte);
|
||||||
|
|
||||||
for (i = 1; i < L2_USER_PGTABLE_PAGES; ++i) {
|
for (i = 1; i < order; ++i) {
|
||||||
tlb_remove_page(tlb, pte + i);
|
tlb_remove_page(tlb, pte + i);
|
||||||
dec_zone_page_state(pte + i, NR_PAGETABLE);
|
dec_zone_page_state(pte + i, NR_PAGETABLE);
|
||||||
}
|
}
|
||||||
|
@ -490,7 +487,7 @@ void set_pte(pte_t *ptep, pte_t pte)
|
||||||
/* Can this mm load a PTE with cached_priority set? */
|
/* Can this mm load a PTE with cached_priority set? */
|
||||||
static inline int mm_is_priority_cached(struct mm_struct *mm)
|
static inline int mm_is_priority_cached(struct mm_struct *mm)
|
||||||
{
|
{
|
||||||
return mm->context.priority_cached;
|
return mm->context.priority_cached != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -500,8 +497,8 @@ static inline int mm_is_priority_cached(struct mm_struct *mm)
|
||||||
void start_mm_caching(struct mm_struct *mm)
|
void start_mm_caching(struct mm_struct *mm)
|
||||||
{
|
{
|
||||||
if (!mm_is_priority_cached(mm)) {
|
if (!mm_is_priority_cached(mm)) {
|
||||||
mm->context.priority_cached = -1U;
|
mm->context.priority_cached = -1UL;
|
||||||
hv_set_caching(-1U);
|
hv_set_caching(-1UL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -516,7 +513,7 @@ void start_mm_caching(struct mm_struct *mm)
|
||||||
* Presumably we'll come back later and have more luck and clear
|
* Presumably we'll come back later and have more luck and clear
|
||||||
* the value then; for now we'll just keep the cache marked for priority.
|
* the value then; for now we'll just keep the cache marked for priority.
|
||||||
*/
|
*/
|
||||||
static unsigned int update_priority_cached(struct mm_struct *mm)
|
static unsigned long update_priority_cached(struct mm_struct *mm)
|
||||||
{
|
{
|
||||||
if (mm->context.priority_cached && down_write_trylock(&mm->mmap_sem)) {
|
if (mm->context.priority_cached && down_write_trylock(&mm->mmap_sem)) {
|
||||||
struct vm_area_struct *vm;
|
struct vm_area_struct *vm;
|
||||||
|
|
Loading…
Reference in a new issue