162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * include/asm-xtensa/page.h
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * This program is free software; you can redistribute it and/or modify
562306a36Sopenharmony_ci * it under the terms of the GNU General Public License version2 as
662306a36Sopenharmony_ci * published by the Free Software Foundation.
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * Copyright (C) 2001 - 2007 Tensilica Inc.
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#ifndef _XTENSA_PAGE_H
1262306a36Sopenharmony_ci#define _XTENSA_PAGE_H
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#include <linux/const.h>
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci#include <asm/processor.h>
1762306a36Sopenharmony_ci#include <asm/types.h>
1862306a36Sopenharmony_ci#include <asm/cache.h>
1962306a36Sopenharmony_ci#include <asm/kmem_layout.h>
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci/*
2262306a36Sopenharmony_ci * PAGE_SHIFT determines the page size
2362306a36Sopenharmony_ci */
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci#define PAGE_SHIFT	12
2662306a36Sopenharmony_ci#define PAGE_SIZE	(__XTENSA_UL_CONST(1) << PAGE_SHIFT)
2762306a36Sopenharmony_ci#define PAGE_MASK	(~(PAGE_SIZE-1))
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci#ifdef CONFIG_MMU
3062306a36Sopenharmony_ci#define PAGE_OFFSET	XCHAL_KSEG_CACHED_VADDR
3162306a36Sopenharmony_ci#define PHYS_OFFSET	XCHAL_KSEG_PADDR
3262306a36Sopenharmony_ci#define MAX_LOW_PFN	(PHYS_PFN(XCHAL_KSEG_PADDR) + \
3362306a36Sopenharmony_ci			 PHYS_PFN(XCHAL_KSEG_SIZE))
3462306a36Sopenharmony_ci#else
3562306a36Sopenharmony_ci#define PAGE_OFFSET	_AC(CONFIG_DEFAULT_MEM_START, UL)
3662306a36Sopenharmony_ci#define PHYS_OFFSET	_AC(CONFIG_DEFAULT_MEM_START, UL)
3762306a36Sopenharmony_ci#define MAX_LOW_PFN	PHYS_PFN(0xfffffffful)
3862306a36Sopenharmony_ci#endif
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci/*
4162306a36Sopenharmony_ci * Cache aliasing:
4262306a36Sopenharmony_ci *
4362306a36Sopenharmony_ci * If the cache size for one way is greater than the page size, we have to
4462306a36Sopenharmony_ci * deal with cache aliasing. The cache index is wider than the page size:
4562306a36Sopenharmony_ci *
4662306a36Sopenharmony_ci * |    |cache| cache index
4762306a36Sopenharmony_ci * | pfn  |off|	virtual address
4862306a36Sopenharmony_ci * |xxxx:X|zzz|
4962306a36Sopenharmony_ci * |    : |   |
5062306a36Sopenharmony_ci * | \  / |   |
5162306a36Sopenharmony_ci * |trans.|   |
5262306a36Sopenharmony_ci * | /  \ |   |
5362306a36Sopenharmony_ci * |yyyy:Y|zzz|	physical address
5462306a36Sopenharmony_ci *
5562306a36Sopenharmony_ci * When the page number is translated to the physical page address, the lowest
5662306a36Sopenharmony_ci * bit(s) (X) that are part of the cache index are also translated (Y).
5762306a36Sopenharmony_ci * If this translation changes bit(s) (X), the cache index is also afected,
5862306a36Sopenharmony_ci * thus resulting in a different cache line than before.
5962306a36Sopenharmony_ci * The kernel does not provide a mechanism to ensure that the page color
6062306a36Sopenharmony_ci * (represented by this bit) remains the same when allocated or when pages
6162306a36Sopenharmony_ci * are remapped. When user pages are mapped into kernel space, the color of
6262306a36Sopenharmony_ci * the page might also change.
6362306a36Sopenharmony_ci *
6462306a36Sopenharmony_ci * We use the address space VMALLOC_END ... VMALLOC_END + DCACHE_WAY_SIZE * 2
6562306a36Sopenharmony_ci * to temporarily map a patch so we can match the color.
6662306a36Sopenharmony_ci */
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci#if DCACHE_WAY_SIZE > PAGE_SIZE
6962306a36Sopenharmony_ci# define DCACHE_ALIAS_ORDER	(DCACHE_WAY_SHIFT - PAGE_SHIFT)
7062306a36Sopenharmony_ci# define DCACHE_ALIAS_MASK	(PAGE_MASK & (DCACHE_WAY_SIZE - 1))
7162306a36Sopenharmony_ci# define DCACHE_ALIAS(a)	(((a) & DCACHE_ALIAS_MASK) >> PAGE_SHIFT)
7262306a36Sopenharmony_ci# define DCACHE_ALIAS_EQ(a,b)	((((a) ^ (b)) & DCACHE_ALIAS_MASK) == 0)
7362306a36Sopenharmony_ci#else
7462306a36Sopenharmony_ci# define DCACHE_ALIAS_ORDER	0
7562306a36Sopenharmony_ci# define DCACHE_ALIAS(a)	((void)(a), 0)
7662306a36Sopenharmony_ci#endif
7762306a36Sopenharmony_ci#define DCACHE_N_COLORS		(1 << DCACHE_ALIAS_ORDER)
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci#if ICACHE_WAY_SIZE > PAGE_SIZE
8062306a36Sopenharmony_ci# define ICACHE_ALIAS_ORDER	(ICACHE_WAY_SHIFT - PAGE_SHIFT)
8162306a36Sopenharmony_ci# define ICACHE_ALIAS_MASK	(PAGE_MASK & (ICACHE_WAY_SIZE - 1))
8262306a36Sopenharmony_ci# define ICACHE_ALIAS(a)	(((a) & ICACHE_ALIAS_MASK) >> PAGE_SHIFT)
8362306a36Sopenharmony_ci# define ICACHE_ALIAS_EQ(a,b)	((((a) ^ (b)) & ICACHE_ALIAS_MASK) == 0)
8462306a36Sopenharmony_ci#else
8562306a36Sopenharmony_ci# define ICACHE_ALIAS_ORDER	0
8662306a36Sopenharmony_ci#endif
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci#ifdef __ASSEMBLY__
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci#define __pgprot(x)	(x)
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci#else
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci/*
9662306a36Sopenharmony_ci * These are used to make use of C type-checking..
9762306a36Sopenharmony_ci */
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_citypedef struct { unsigned long pte; } pte_t;		/* page table entry */
10062306a36Sopenharmony_citypedef struct { unsigned long pgd; } pgd_t;		/* PGD table entry */
10162306a36Sopenharmony_citypedef struct { unsigned long pgprot; } pgprot_t;
10262306a36Sopenharmony_citypedef struct page *pgtable_t;
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci#define pte_val(x)	((x).pte)
10562306a36Sopenharmony_ci#define pgd_val(x)	((x).pgd)
10662306a36Sopenharmony_ci#define pgprot_val(x)	((x).pgprot)
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci#define __pte(x)	((pte_t) { (x) } )
10962306a36Sopenharmony_ci#define __pgd(x)	((pgd_t) { (x) } )
11062306a36Sopenharmony_ci#define __pgprot(x)	((pgprot_t) { (x) } )
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci/*
11362306a36Sopenharmony_ci * Pure 2^n version of get_order
11462306a36Sopenharmony_ci * Use 'nsau' instructions if supported by the processor or the generic version.
11562306a36Sopenharmony_ci */
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci#if XCHAL_HAVE_NSA
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_cistatic inline __attribute_const__ int get_order(unsigned long size)
12062306a36Sopenharmony_ci{
12162306a36Sopenharmony_ci	int lz;
12262306a36Sopenharmony_ci	asm ("nsau %0, %1" : "=r" (lz) : "r" ((size - 1) >> PAGE_SHIFT));
12362306a36Sopenharmony_ci	return 32 - lz;
12462306a36Sopenharmony_ci}
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci#else
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci# include <asm-generic/getorder.h>
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci#endif
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_cistruct page;
13362306a36Sopenharmony_cistruct vm_area_struct;
13462306a36Sopenharmony_ciextern void clear_page(void *page);
13562306a36Sopenharmony_ciextern void copy_page(void *to, void *from);
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci/*
13862306a36Sopenharmony_ci * If we have cache aliasing and writeback caches, we might have to do
13962306a36Sopenharmony_ci * some extra work
14062306a36Sopenharmony_ci */
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci#if defined(CONFIG_MMU) && DCACHE_WAY_SIZE > PAGE_SIZE
14362306a36Sopenharmony_ciextern void clear_page_alias(void *vaddr, unsigned long paddr);
14462306a36Sopenharmony_ciextern void copy_page_alias(void *to, void *from,
14562306a36Sopenharmony_ci			    unsigned long to_paddr, unsigned long from_paddr);
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci#define clear_user_highpage clear_user_highpage
14862306a36Sopenharmony_civoid clear_user_highpage(struct page *page, unsigned long vaddr);
14962306a36Sopenharmony_ci#define __HAVE_ARCH_COPY_USER_HIGHPAGE
15062306a36Sopenharmony_civoid copy_user_highpage(struct page *to, struct page *from,
15162306a36Sopenharmony_ci			unsigned long vaddr, struct vm_area_struct *vma);
15262306a36Sopenharmony_ci#else
15362306a36Sopenharmony_ci# define clear_user_page(page, vaddr, pg)	clear_page(page)
15462306a36Sopenharmony_ci# define copy_user_page(to, from, vaddr, pg)	copy_page(to, from)
15562306a36Sopenharmony_ci#endif
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci/*
15862306a36Sopenharmony_ci * This handles the memory map.  We handle pages at
15962306a36Sopenharmony_ci * XCHAL_KSEG_CACHED_VADDR for kernels with 32 bit address space.
16062306a36Sopenharmony_ci * These macros are for conversion of kernel address, not user
16162306a36Sopenharmony_ci * addresses.
16262306a36Sopenharmony_ci */
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci#define ARCH_PFN_OFFSET		(PHYS_OFFSET >> PAGE_SHIFT)
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci#ifdef CONFIG_MMU
16762306a36Sopenharmony_cistatic inline unsigned long ___pa(unsigned long va)
16862306a36Sopenharmony_ci{
16962306a36Sopenharmony_ci	unsigned long off = va - PAGE_OFFSET;
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	if (off >= XCHAL_KSEG_SIZE)
17262306a36Sopenharmony_ci		off -= XCHAL_KSEG_SIZE;
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci#ifndef CONFIG_XIP_KERNEL
17562306a36Sopenharmony_ci	return off + PHYS_OFFSET;
17662306a36Sopenharmony_ci#else
17762306a36Sopenharmony_ci	if (off < XCHAL_KSEG_SIZE)
17862306a36Sopenharmony_ci		return off + PHYS_OFFSET;
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci	off -= XCHAL_KSEG_SIZE;
18162306a36Sopenharmony_ci	if (off >= XCHAL_KIO_SIZE)
18262306a36Sopenharmony_ci		off -= XCHAL_KIO_SIZE;
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	return off + XCHAL_KIO_PADDR;
18562306a36Sopenharmony_ci#endif
18662306a36Sopenharmony_ci}
18762306a36Sopenharmony_ci#define __pa(x)	___pa((unsigned long)(x))
18862306a36Sopenharmony_ci#else
18962306a36Sopenharmony_ci#define __pa(x)	\
19062306a36Sopenharmony_ci	((unsigned long) (x) - PAGE_OFFSET + PHYS_OFFSET)
19162306a36Sopenharmony_ci#endif
19262306a36Sopenharmony_ci#define __va(x)	\
19362306a36Sopenharmony_ci	((void *)((unsigned long) (x) - PHYS_OFFSET + PAGE_OFFSET))
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci#define virt_to_page(kaddr)	pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)
19662306a36Sopenharmony_ci#define page_to_virt(page)	__va(page_to_pfn(page) << PAGE_SHIFT)
19762306a36Sopenharmony_ci#define virt_addr_valid(kaddr)	pfn_valid(__pa(kaddr) >> PAGE_SHIFT)
19862306a36Sopenharmony_ci#define page_to_phys(page)	(page_to_pfn(page) << PAGE_SHIFT)
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci#endif /* __ASSEMBLY__ */
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci#include <asm-generic/memory_model.h>
20362306a36Sopenharmony_ci#endif /* _XTENSA_PAGE_H */
204