pgalloc.h
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:9k
- #ifndef _ASM_PGALLOC_H
- #define _ASM_PGALLOC_H
- /* The usual comment is "Caches aren't brain-dead on the <architecture>".
- * Unfortunately, that doesn't apply to PA-RISC. */
- #include <asm/processor.h>
- #include <asm/fixmap.h>
- #include <linux/threads.h>
- #include <asm/pgtable.h>
- #include <asm/cache.h>
- /* Internal use D/I cache flushing routines... */
- /* XXX: these functions must not access memory between f[di]ce instructions. */
- static inline void __flush_dcache_range(unsigned long start, unsigned long size)
- {
- #if 0
- register unsigned long count = (size / L1_CACHE_BYTES);
- register unsigned long loop = cache_info.dc_loop;
- register unsigned long i, j;
- if (size > 64 * 1024) {
- /* Just punt and clear the whole damn thing */
- flush_data_cache();
- return;
- }
- for(i = 0; i <= count; i++, start += L1_CACHE_BYTES)
- for(j = 0; j < loop; j++)
- fdce(start);
- #else
- flush_data_cache();
- #endif
- }
- static inline void __flush_icache_range(unsigned long start, unsigned long size)
- {
- #if 0
- register unsigned long count = (size / L1_CACHE_BYTES);
- register unsigned long loop = cache_info.ic_loop;
- register unsigned long i, j;
- if (size > 64 * 1024) {
- /* Just punt and clear the whole damn thing */
- flush_instruction_cache();
- return;
- }
- for(i = 0; i <= count; i++, start += L1_CACHE_BYTES)
- for(j = 0; j < loop; j++)
- fice(start);
- #else
- flush_instruction_cache();
- #endif
- }
- static inline void
- flush_kernel_dcache_range(unsigned long start, unsigned long size)
- {
- register unsigned long end = start + size;
- register unsigned long i;
- start &= ~(L1_CACHE_BYTES - 1);
- for (i = start; i < end; i += L1_CACHE_BYTES) {
- kernel_fdc(i);
- }
- asm volatile("sync" : : );
- asm volatile("syncdma" : : );
- }
- extern void __flush_page_to_ram(unsigned long address);
- #define flush_cache_all() flush_all_caches()
- #define flush_cache_mm(foo) flush_all_caches()
- #if 0
- /* This is how I think the cache flushing should be done -- mrw */
- extern inline void flush_cache_mm(struct mm_struct *mm) {
- if (mm == current->mm) {
- flush_user_dcache_range(mm->start_data, mm->end_data);
- flush_user_icache_range(mm->start_code, mm->end_code);
- } else {
- flush_other_dcache_range(mm->context, mm->start_data, mm->end_data);
- flush_other_icache_range(mm->context, mm->start_code, mm->end_code);
- }
- }
- #endif
- #define flush_cache_range(mm, start, end) do {
- __flush_dcache_range(start, (unsigned long)end - (unsigned long)start);
- __flush_icache_range(start, (unsigned long)end - (unsigned long)start);
- } while(0)
- #define flush_cache_page(vma, vmaddr) do {
- __flush_dcache_range(vmaddr, PAGE_SIZE);
- __flush_icache_range(vmaddr, PAGE_SIZE);
- } while(0)
- #define flush_page_to_ram(page)
- __flush_page_to_ram((unsigned long)page_address(page))
- #define flush_icache_range(start, end)
- __flush_icache_range(start, end - start)
- #define flush_icache_page(vma, page)
- __flush_icache_range(page_address(page), PAGE_SIZE)
- #define flush_dcache_page(page)
- __flush_dcache_range(page_address(page), PAGE_SIZE)
- /* TLB flushing routines.... */
- extern void flush_data_tlb(void);
- extern void flush_instruction_tlb(void);
- #define flush_tlb() do {
- flush_data_tlb();
- flush_instruction_tlb();
- } while(0);
- #define flush_tlb_all() flush_tlb() /* XXX p[id]tlb */
- extern __inline__ void flush_tlb_pgtables(struct mm_struct *mm, unsigned long start, unsigned long end)
- {
- }
-
- static inline void flush_instruction_tlb_range(unsigned long start,
- unsigned long size)
- {
- #if 0
- register unsigned long count = (size / PAGE_SIZE);
- register unsigned long loop = cache_info.it_loop;
- register unsigned long i, j;
-
- for(i = 0; i <= count; i++, start += PAGE_SIZE)
- for(j = 0; j < loop; j++)
- pitlbe(start);
- #else
- flush_instruction_tlb();
- #endif
- }
- static inline void flush_data_tlb_range(unsigned long start,
- unsigned long size)
- {
- #if 0
- register unsigned long count = (size / PAGE_SIZE);
- register unsigned long loop = cache_info.dt_loop;
- register unsigned long i, j;
-
- for(i = 0; i <= count; i++, start += PAGE_SIZE)
- for(j = 0; j < loop; j++)
- pdtlbe(start);
- #else
- flush_data_tlb();
- #endif
- }
- static inline void __flush_tlb_range(unsigned long space, unsigned long start,
- unsigned long size)
- {
- unsigned long old_sr1;
- if(!size)
- return;
- old_sr1 = mfsp(1);
- mtsp(space, 1);
-
- flush_data_tlb_range(start, size);
- flush_instruction_tlb_range(start, size);
- mtsp(old_sr1, 1);
- }
- extern void __flush_tlb_space(unsigned long space);
- static inline void flush_tlb_mm(struct mm_struct *mm)
- {
- #if 0
- __flush_tlb_space(mm->context);
- #else
- flush_tlb();
- #endif
- }
- static inline void flush_tlb_page(struct vm_area_struct *vma,
- unsigned long addr)
- {
- __flush_tlb_range(vma->vm_mm->context, addr, PAGE_SIZE);
-
- }
- static inline void flush_tlb_range(struct mm_struct *mm,
- unsigned long start, unsigned long end)
- {
- __flush_tlb_range(mm->context, start, end - start);
- }
- /*
- * NOTE: Many of the below macros use PT_NLEVELS because
- * it is convenient that PT_NLEVELS == LOG2(pte size in bytes),
- * i.e. we use 3 level page tables when we use 8 byte pte's
- * (for 64 bit) and 2 level page tables when we use 4 byte pte's
- */
- #ifdef __LP64__
- #define PT_NLEVELS 3
- #define PT_INITIAL 4 /* Number of initial page tables */
- #else
- #define PT_NLEVELS 2
- #define PT_INITIAL 2 /* Number of initial page tables */
- #endif
- /* Definitions for 1st level */
- #define PGDIR_SHIFT (PAGE_SHIFT + (PT_NLEVELS - 1)*(PAGE_SHIFT - PT_NLEVELS))
- #define PGDIR_SIZE (1UL << PGDIR_SHIFT)
- #define PGDIR_MASK (~(PGDIR_SIZE-1))
- #define PTRS_PER_PGD (1UL << (PAGE_SHIFT - PT_NLEVELS))
- #define USER_PTRS_PER_PGD (TASK_SIZE/PGDIR_SIZE)
- /* Definitions for 2nd level */
- #define PMD_SHIFT (PAGE_SHIFT + (PAGE_SHIFT - PT_NLEVELS))
- #define PMD_SIZE (1UL << PMD_SHIFT)
- #define PMD_MASK (~(PMD_SIZE-1))
- #if PT_NLEVELS == 3
- #define PTRS_PER_PMD (1UL << (PAGE_SHIFT - PT_NLEVELS))
- #else
- #define PTRS_PER_PMD 1
- #endif
- /* Definitions for 3rd level */
- #define PTRS_PER_PTE (1UL << (PAGE_SHIFT - PT_NLEVELS))
- #define get_pgd_fast get_pgd_slow
- #define free_pgd_fast free_pgd_slow
- extern __inline__ pgd_t *get_pgd_slow(void)
- {
- extern unsigned long gateway_pgd_offset;
- extern unsigned long gateway_pgd_entry;
- pgd_t *ret = (pgd_t *)__get_free_page(GFP_KERNEL);
- if (ret) {
- memset (ret, 0, PTRS_PER_PGD * sizeof(pgd_t));
- /* Install HP-UX and Linux gateway page translations */
- pgd_val(*(ret + gateway_pgd_offset)) = gateway_pgd_entry;
- }
- return ret;
- }
- extern __inline__ void free_pgd_slow(pgd_t *pgd)
- {
- free_page((unsigned long)pgd);
- }
- #if PT_NLEVELS == 3
- /* Three Level Page Table Support for pmd's */
- extern __inline__ pmd_t *get_pmd_fast(void)
- {
- return NULL; /* la la */
- }
- #if 0
- extern __inline__ void free_pmd_fast(pmd_t *pmd)
- {
- }
- #else
- #define free_pmd_fast free_pmd_slow
- #endif
- extern __inline__ pmd_t *get_pmd_slow(void)
- {
- pmd_t *pmd = (pmd_t *) __get_free_page(GFP_KERNEL);
- if (pmd)
- clear_page(pmd);
- return pmd;
- }
- extern __inline__ void free_pmd_slow(pmd_t *pmd)
- {
- free_page((unsigned long)pmd);
- }
- extern void __bad_pgd(pgd_t *pgd);
- extern inline pmd_t * pmd_alloc(pgd_t *pgd, unsigned long address)
- {
- address = (address >> PMD_SHIFT) & (PTRS_PER_PMD - 1);
- if (pgd_none(*pgd))
- goto getnew;
- if (pgd_bad(*pgd))
- goto fix;
- return (pmd_t *) pgd_page(*pgd) + address;
- getnew:
- {
- pmd_t *page = get_pmd_fast();
-
- if (!page)
- page = get_pmd_slow();
- if (page) {
- if (pgd_none(*pgd)) {
- pgd_val(*pgd) = _PAGE_TABLE + __pa((unsigned long)page);
- return page + address;
- }
- else
- free_pmd_fast(page);
- }
- else {
- return NULL;
- }
- }
- fix:
- __bad_pgd(pgd);
- return NULL;
- }
- #else
- /* Two Level Page Table Support for pmd's */
- extern inline pmd_t * pmd_alloc(pgd_t * pgd, unsigned long address)
- {
- return (pmd_t *) pgd;
- }
- extern inline void free_pmd_fast(pmd_t * pmd)
- {
- }
- #endif
- extern __inline__ pte_t *get_pte_fast(void)
- {
- return NULL; /* la la */
- }
- #if 0
- extern __inline__ void free_pte_fast(pte_t *pte)
- {
- }
- #else
- #define free_pte_fast free_pte_slow
- #endif
- extern pte_t *get_pte_slow(pmd_t *pmd, unsigned long address_preadjusted);
- extern __inline__ void free_pte_slow(pte_t *pte)
- {
- free_page((unsigned long)pte);
- }
- #define pmd_alloc_kernel pmd_alloc
- #define pte_alloc_kernel pte_alloc
- #define pte_free(pte) free_pte_fast(pte)
- #define pmd_free(pmd) free_pmd_fast(pmd)
- #define pgd_free(pgd) free_pgd_fast(pgd)
- #define pgd_alloc(mm) get_pgd_fast()
- extern void __bad_pmd(pmd_t *pmd);
- extern inline pte_t * pte_alloc(pmd_t * pmd, unsigned long address)
- {
- address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
- if (pmd_none(*pmd))
- goto getnew;
- if (pmd_bad(*pmd))
- goto fix;
- return (pte_t *) pmd_page(*pmd) + address;
- getnew:
- {
- pte_t *page = get_pte_fast();
-
- if (!page)
- return get_pte_slow(pmd, address);
- pmd_val(*pmd) = _PAGE_TABLE + __pa((unsigned long)page);
- return page + address;
- }
- fix:
- __bad_pmd(pmd);
- return NULL;
- }
- extern int do_check_pgt_cache(int, int);
- #endif