mirror of
https://github.com/torvalds/linux.git
synced 2026-04-18 14:53:58 -04:00
powerpc/e500: use contiguous PMD instead of hugepd
e500 supports many page sizes among which the following size are implemented in the kernel at the time being: 4M, 16M, 64M, 256M, 1G. On e500, TLB miss for hugepages is exclusively handled by SW even on e6500 which has HW assistance for 4k pages, so there are no constraints like on the 8xx. On e500/32, all are at PGD/PMD level and can be handled as cont-PMD. On e500/64, smaller ones are on PMD while bigger ones are on PUD. Again, they can easily be handled as cont-PMD and cont-PUD instead of hugepd. On e500/32, use the pagesize bits in PTE to know if it is a PMD or a leaf entry. This works because the pagesize bits are in the last 12 bits and page tables are 4k aligned. On e500/64, use highest bit which is always 1 on PxD (Because PxD contains virtual address of a kernel memory) and always 0 on PTEs because not all bits of RPN are used/possible. Link: https://lkml.kernel.org/r/dd085987816ed2a0c70adb7e34966cb833fc03e1.1719928057.git.christophe.leroy@csgroup.eu Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu> Cc: Jason Gunthorpe <jgg@nvidia.com> Cc: Michael Ellerman <mpe@ellerman.id.au> Cc: Nicholas Piggin <npiggin@gmail.com> Cc: Oscar Salvador <osalvador@suse.de> Cc: Peter Xu <peterx@redhat.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
This commit is contained in:
committed by
Andrew Morton
parent
dc0aa538a9
commit
7c44202e36
@@ -31,6 +31,13 @@ static inline pte_basic_t pte_update(struct mm_struct *mm, unsigned long addr, p
|
||||
|
||||
extern int icache_44x_need_flush;
|
||||
|
||||
#ifndef pte_huge_size
|
||||
static inline unsigned long pte_huge_size(pte_t pte)
|
||||
{
|
||||
return PAGE_SIZE;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* PTE updates. This function is called whenever an existing
|
||||
* valid PTE is updated. This does -not- include set_pte_at()
|
||||
@@ -52,11 +59,34 @@ static inline pte_basic_t pte_update(struct mm_struct *mm, unsigned long addr, p
|
||||
{
|
||||
pte_basic_t old = pte_val(*p);
|
||||
pte_basic_t new = (old & ~(pte_basic_t)clr) | set;
|
||||
unsigned long sz;
|
||||
unsigned long pdsize;
|
||||
int i;
|
||||
|
||||
if (new == old)
|
||||
return old;
|
||||
|
||||
*p = __pte(new);
|
||||
if (huge)
|
||||
sz = pte_huge_size(__pte(old));
|
||||
else
|
||||
sz = PAGE_SIZE;
|
||||
|
||||
if (sz < PMD_SIZE)
|
||||
pdsize = PAGE_SIZE;
|
||||
else if (sz < PUD_SIZE)
|
||||
pdsize = PMD_SIZE;
|
||||
else if (sz < P4D_SIZE)
|
||||
pdsize = PUD_SIZE;
|
||||
else if (sz < PGDIR_SIZE)
|
||||
pdsize = P4D_SIZE;
|
||||
else
|
||||
pdsize = PGDIR_SIZE;
|
||||
|
||||
for (i = 0; i < sz / pdsize; i++, p++) {
|
||||
*p = __pte(new);
|
||||
if (new)
|
||||
new += (unsigned long long)(pdsize / PAGE_SIZE) << PTE_RPN_SHIFT;
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_44x) && !is_kernel_addr(addr) && (old & _PAGE_EXEC))
|
||||
icache_44x_need_flush = 1;
|
||||
@@ -340,16 +370,6 @@ static inline void __set_pte_at(struct mm_struct *mm, unsigned long addr,
|
||||
|
||||
#define pgprot_writecombine pgprot_noncached_wc
|
||||
|
||||
#ifdef CONFIG_ARCH_HAS_HUGEPD
|
||||
static inline int hugepd_ok(hugepd_t hpd)
|
||||
{
|
||||
/* We clear the top bit to indicate hugepd */
|
||||
return (hpd_val(hpd) && (hpd_val(hpd) & PD_HUGE) == 0);
|
||||
}
|
||||
|
||||
#define is_hugepd(hpd) (hugepd_ok(hpd))
|
||||
#endif
|
||||
|
||||
int map_kernel_page(unsigned long va, phys_addr_t pa, pgprot_t prot);
|
||||
void unmap_kernel_page(unsigned long va);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user