#ifndef _MOTOROLA_PGALLOC_H #define _MOTOROLA_PGALLOC_H extern struct pgtable_cache_struct { unsigned long *pmd_cache; unsigned long *pte_cache; /* This counts in units of pointer tables, of which can be eight per page. */ unsigned long pgtable_cache_sz; } quicklists; #define pgd_quicklist ((unsigned long *)0) #define pmd_quicklist (quicklists.pmd_cache) #define pte_quicklist (quicklists.pte_cache) /* This isn't accurate because of fragmentation of allocated pages for pointer tables, but that should not be a problem. */ #define pgtable_cache_size ((quicklists.pgtable_cache_sz+7)/8) extern pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset); extern pmd_t *get_pmd_slow(pgd_t *pgd, unsigned long offset); extern pmd_t *get_pointer_table(void); extern int free_pointer_table(pmd_t *); static inline void flush_tlb_kernel_page(unsigned long addr) { if (CPU_IS_040_OR_060) { mm_segment_t old_fs = get_fs(); set_fs(KERNEL_DS); __asm__ __volatile__(".chip 68040\n\t" "pflush (%0)\n\t" ".chip 68k" : : "a" (addr)); set_fs(old_fs); } else __asm__ __volatile__("pflush #4,#4,(%0)" : : "a" (addr)); } static inline pte_t *get_pte_fast(void) { unsigned long *ret; ret = pte_quicklist; if (ret) { pte_quicklist = (unsigned long *)*ret; ret[0] = 0; quicklists.pgtable_cache_sz -= 8; } return (pte_t *)ret; } #define pte_alloc_one_fast(mm,addr) get_pte_fast() static inline pte_t *pte_alloc_one(struct mm_struct *mm, unsigned long address) { pte_t *pte; pte = (pte_t *) __get_free_page(GFP_KERNEL); if (pte) { clear_page(pte); __flush_page_to_ram((unsigned long)pte); flush_tlb_kernel_page((unsigned long)pte); nocache_page((unsigned long)pte); } return pte; } static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long address) { return get_pointer_table(); } static inline void free_pte_fast(pte_t *pte) { *(unsigned long *)pte = (unsigned long)pte_quicklist; pte_quicklist = (unsigned long *)pte; quicklists.pgtable_cache_sz += 8; } static inline void free_pte_slow(pte_t *pte) { cache_page((unsigned long)pte); free_page((unsigned long) pte); } static inline pmd_t *get_pmd_fast(void) { unsigned long *ret; ret = pmd_quicklist; if (ret) { pmd_quicklist = (unsigned long *)*ret; ret[0] = 0; quicklists.pgtable_cache_sz--; } return (pmd_t *)ret; } #define pmd_alloc_one_fast(mm,addr) get_pmd_fast() static inline void free_pmd_fast(pmd_t *pmd) { *(unsigned long *)pmd = (unsigned long)pmd_quicklist; pmd_quicklist = (unsigned long *) pmd; quicklists.pgtable_cache_sz++; } static inline int free_pmd_slow(pmd_t *pmd) { return free_pointer_table(pmd); } /* The pgd cache is folded into the pmd cache, so these are dummy routines. */ static inline pgd_t *get_pgd_fast(void) { return (pgd_t *)0; } static inline void free_pgd_fast(pgd_t *pgd) { } static inline void free_pgd_slow(pgd_t *pgd) { } extern void __bad_pte(pmd_t *pmd); extern void __bad_pmd(pgd_t *pgd); static inline void pte_free(pte_t *pte) { free_pte_fast(pte); } static inline void pmd_free(pmd_t *pmd) { free_pmd_fast(pmd); } static inline void pte_free_kernel(pte_t *pte) { free_pte_fast(pte); } static inline pte_t *pte_alloc_kernel(pmd_t *pmd, unsigned long address) { return pte_alloc(&init_mm,pmd, address); } static inline void pmd_free_kernel(pmd_t *pmd) { free_pmd_fast(pmd); } static inline pmd_t *pmd_alloc_kernel(pgd_t *pgd, unsigned long address) { return pmd_alloc(&init_mm,pgd, address); } static inline void pgd_free(pgd_t *pgd) { free_pmd_fast((pmd_t *)pgd); } static inline pgd_t *pgd_alloc(struct mm_struct *mm) { pgd_t *pgd = (pgd_t *)get_pmd_fast(); if (!pgd) pgd = (pgd_t *)get_pointer_table(); return pgd; } #define pmd_populate(MM, PMD, PTE) pmd_set(PMD, PTE) #define pgd_populate(MM, PGD, PMD) pgd_set(PGD, PMD) extern int do_check_pgt_cache(int, int); static inline void set_pgdir(unsigned long address, pgd_t entry) { } /* * flush all user-space atc entries. */ static inline void __flush_tlb(void) { if (CPU_IS_040_OR_060) __asm__ __volatile__(".chip 68040\n\t" "pflushan\n\t" ".chip 68k"); else __asm__ __volatile__("pflush #0,#4"); } static inline void __flush_tlb040_one(unsigned long addr) { __asm__ __volatile__(".chip 68040\n\t" "pflush (%0)\n\t" ".chip 68k" : : "a" (addr)); } static inline void __flush_tlb_one(unsigned long addr) { if (CPU_IS_040_OR_060) __flush_tlb040_one(addr); else __asm__ __volatile__("pflush #0,#4,(%0)" : : "a" (addr)); } #define flush_tlb() __flush_tlb() /* * flush all atc entries (both kernel and user-space entries). */ static inline void flush_tlb_all(void) { if (CPU_IS_040_OR_060) __asm__ __volatile__(".chip 68040\n\t" "pflusha\n\t" ".chip 68k"); else __asm__ __volatile__("pflusha"); } static inline void flush_tlb_mm(struct mm_struct *mm) { if (mm == current->active_mm) __flush_tlb(); } static inline void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr) { if (vma->vm_mm == current->active_mm) { mm_segment_t old_fs = get_fs(); set_fs(USER_DS); __flush_tlb_one(addr); set_fs(old_fs); } } static inline void flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end) { if (mm == current->active_mm) __flush_tlb(); } static inline void flush_tlb_pgtables(struct mm_struct *mm, unsigned long start, unsigned long end) { } #endif /* _MOTOROLA_PGALLOC_H */