1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230
|
/* $Id: pgalloc.h,v 1.30 2001/12/21 04:56:17 davem Exp $ */
#ifndef _SPARC64_PGALLOC_H
#define _SPARC64_PGALLOC_H
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <asm/page.h>
#include <asm/spitfire.h>
#include <asm/pgtable.h>
#include <asm/cpudata.h>
/* Page table allocation/freeing. */
#ifdef CONFIG_SMP
/* Sliiiicck */
#define pgt_quicklists cpu_data(smp_processor_id())
#else
extern struct pgtable_cache_struct {
unsigned long *pgd_cache;
unsigned long *pte_cache[2];
unsigned int pgcache_size;
unsigned int pgdcache_size;
} pgt_quicklists;
#endif
#define pgd_quicklist (pgt_quicklists.pgd_cache)
#define pmd_quicklist ((unsigned long *)0)
#define pte_quicklist (pgt_quicklists.pte_cache)
#define pgtable_cache_size (pgt_quicklists.pgcache_size)
#define pgd_cache_size (pgt_quicklists.pgdcache_size)
#ifndef CONFIG_SMP
static __inline__ void free_pgd_fast(pgd_t *pgd)
{
struct page *page = virt_to_page(pgd);
preempt_disable();
if (!page->lru.prev) {
(unsigned long *)page->lru.next = pgd_quicklist;
pgd_quicklist = (unsigned long *)page;
}
(unsigned long)page->lru.prev |=
(((unsigned long)pgd & (PAGE_SIZE / 2)) ? 2 : 1);
pgd_cache_size++;
preempt_enable();
}
static __inline__ pgd_t *get_pgd_fast(void)
{
struct page *ret;
preempt_disable();
if ((ret = (struct page *)pgd_quicklist) != NULL) {
unsigned long mask = (unsigned long)ret->lru.prev;
unsigned long off = 0;
if (mask & 1)
mask &= ~1;
else {
off = PAGE_SIZE / 2;
mask &= ~2;
}
(unsigned long)ret->lru.prev = mask;
if (!mask)
pgd_quicklist = (unsigned long *)ret->lru.next;
ret = (struct page *)(__page_address(ret) + off);
pgd_cache_size--;
preempt_enable();
} else {
struct page *page;
preempt_enable();
page = alloc_page(GFP_KERNEL|__GFP_REPEAT);
if (page) {
ret = (struct page *)page_address(page);
clear_page(ret);
(unsigned long)page->lru.prev = 2;
preempt_disable();
(unsigned long *)page->lru.next = pgd_quicklist;
pgd_quicklist = (unsigned long *)page;
pgd_cache_size++;
preempt_enable();
}
}
return (pgd_t *)ret;
}
#else /* CONFIG_SMP */
static __inline__ void free_pgd_fast(pgd_t *pgd)
{
preempt_disable();
*(unsigned long *)pgd = (unsigned long) pgd_quicklist;
pgd_quicklist = (unsigned long *) pgd;
pgtable_cache_size++;
preempt_enable();
}
static __inline__ pgd_t *get_pgd_fast(void)
{
unsigned long *ret;
preempt_disable();
if((ret = pgd_quicklist) != NULL) {
pgd_quicklist = (unsigned long *)(*ret);
ret[0] = 0;
pgtable_cache_size--;
preempt_enable();
} else {
preempt_enable();
ret = (unsigned long *) __get_free_page(GFP_KERNEL|__GFP_REPEAT);
if(ret)
memset(ret, 0, PAGE_SIZE);
}
return (pgd_t *)ret;
}
static __inline__ void free_pgd_slow(pgd_t *pgd)
{
free_page((unsigned long)pgd);
}
#endif /* CONFIG_SMP */
#if (L1DCACHE_SIZE > PAGE_SIZE) /* is there D$ aliasing problem */
#define VPTE_COLOR(address) (((address) >> (PAGE_SHIFT + 10)) & 1UL)
#define DCACHE_COLOR(address) (((address) >> PAGE_SHIFT) & 1UL)
#else
#define VPTE_COLOR(address) 0
#define DCACHE_COLOR(address) 0
#endif
#define pgd_populate(MM, PGD, PMD) pgd_set(PGD, PMD)
static __inline__ pmd_t *pmd_alloc_one_fast(struct mm_struct *mm, unsigned long address)
{
unsigned long *ret;
int color = 0;
preempt_disable();
if (pte_quicklist[color] == NULL)
color = 1;
if((ret = (unsigned long *)pte_quicklist[color]) != NULL) {
pte_quicklist[color] = (unsigned long *)(*ret);
ret[0] = 0;
pgtable_cache_size--;
}
preempt_enable();
return (pmd_t *)ret;
}
static __inline__ pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long address)
{
pmd_t *pmd;
pmd = pmd_alloc_one_fast(mm, address);
if (!pmd) {
pmd = (pmd_t *)__get_free_page(GFP_KERNEL|__GFP_REPEAT);
if (pmd)
memset(pmd, 0, PAGE_SIZE);
}
return pmd;
}
static __inline__ void free_pmd_fast(pmd_t *pmd)
{
unsigned long color = DCACHE_COLOR((unsigned long)pmd);
preempt_disable();
*(unsigned long *)pmd = (unsigned long) pte_quicklist[color];
pte_quicklist[color] = (unsigned long *) pmd;
pgtable_cache_size++;
preempt_enable();
}
static __inline__ void free_pmd_slow(pmd_t *pmd)
{
free_page((unsigned long)pmd);
}
#define pmd_populate_kernel(MM, PMD, PTE) pmd_set(PMD, PTE)
#define pmd_populate(MM,PMD,PTE_PAGE) \
pmd_populate_kernel(MM,PMD,page_address(PTE_PAGE))
extern pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address);
#define pte_alloc_one(MM,ADDR) virt_to_page(pte_alloc_one_kernel(MM,ADDR))
static __inline__ pte_t *pte_alloc_one_fast(struct mm_struct *mm, unsigned long address)
{
unsigned long color = VPTE_COLOR(address);
unsigned long *ret;
preempt_disable();
if((ret = (unsigned long *)pte_quicklist[color]) != NULL) {
pte_quicklist[color] = (unsigned long *)(*ret);
ret[0] = 0;
pgtable_cache_size--;
}
preempt_enable();
return (pte_t *)ret;
}
static __inline__ void free_pte_fast(pte_t *pte)
{
unsigned long color = DCACHE_COLOR((unsigned long)pte);
preempt_disable();
*(unsigned long *)pte = (unsigned long) pte_quicklist[color];
pte_quicklist[color] = (unsigned long *) pte;
pgtable_cache_size++;
preempt_enable();
}
static __inline__ void free_pte_slow(pte_t *pte)
{
free_page((unsigned long)pte);
}
#define pte_free_kernel(pte) free_pte_fast(pte)
#define pte_free(pte) free_pte_fast(page_address(pte))
#define pmd_free(pmd) free_pmd_fast(pmd)
#define pgd_free(pgd) free_pgd_fast(pgd)
#define pgd_alloc(mm) get_pgd_fast()
#endif /* _SPARC64_PGALLOC_H */
|