OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [uclinux/] [uClinux-2.0.x/] [arch/] [armnommu/] [mm/] [small_page.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 199 simons
/*
2
 *  linux/arch/arm/mm/small_page.c
3
 *
4
 *  Copyright (C) 1996  Russell King
5
 *
6
 * Changelog:
7
 *  26/01/1996  RMK     Cleaned up various areas to make little more generic
8
 */
9
 
10
#include <linux/signal.h>
11
#include <linux/sched.h>
12
#include <linux/head.h>
13
#include <linux/kernel.h>
14
#include <linux/errno.h>
15
#include <linux/string.h>
16
#include <linux/types.h>
17
#include <linux/ptrace.h>
18
#include <linux/mman.h>
19
#include <linux/mm.h>
20
#include <linux/swap.h>
21
#include <linux/smp.h>
22
 
23
#define SMALL_ALLOC_SHIFT       (10)
24
#define SMALL_ALLOC_SIZE        (1 << SMALL_ALLOC_SHIFT)
25
#define NR_BLOCKS               (PAGE_SIZE / SMALL_ALLOC_SIZE)
26
 
27
#if NR_BLOCKS != 4
28
#error I only support 4 blocks per page!
29
#endif
30
 
31
#define USED(pg)                (((pg)->count >> 8) & 15)
32
#define SET_USED(pg,off)        ((pg)->count |= 256 << off)
33
#define CLEAR_USED(pg,off)      ((pg)->count &= ~(256 << off))
34
#define IS_FREE(pg,off)         (!((pg)->count & (256 << off)))
35
#define PAGE_PTR(page,block)    ((struct free_small_page *)((page) + \
36
                                        ((block) << SMALL_ALLOC_SHIFT)))
37
 
38
struct free_small_page {
39
        unsigned long next;
40
        unsigned long prev;
41
};
42
 
43
/*
44
 * To handle allocating small pages, we use the main get_free_page routine,
45
 * and split the page up into 4.  The page is marked in mem_map as reserved,
46
 * so it can't be free'd by free_page.  The count field is used to keep track
47
 * of which sections of this page are allocated.
48
 */
49
static unsigned long small_page_ptr;
50
 
51
static unsigned char offsets[1<<NR_BLOCKS] = {
52
        0,       /* 0000 */
53
        1,      /* 0001 */
54
        0,       /* 0010 */
55
        2,      /* 0011 */
56
        0,       /* 0100 */
57
        1,      /* 0101 */
58
        0,       /* 0110 */
59
        3,      /* 0111 */
60
        0,       /* 1000 */
61
        1,      /* 1001 */
62
        0,       /* 1010 */
63
        2,      /* 1011 */
64
        0,       /* 1100 */
65
        1,      /* 1101 */
66
        0,       /* 1110 */
67
        4       /* 1111 */
68
};
69
 
70
static inline void clear_page_links(unsigned long page)
71
{
72
        struct free_small_page *fsp;
73
        int i;
74
 
75
        for (i = 0; i < NR_BLOCKS; i++) {
76
                fsp = PAGE_PTR(page, i);
77
                fsp->next = fsp->prev = 0;
78
        }
79
}
80
 
81
static inline void set_page_links_prev(unsigned long page, unsigned long prev)
82
{
83
        struct free_small_page *fsp;
84
        unsigned int mask;
85
        int i;
86
 
87
        if (!page)
88
                return;
89
 
90
        mask = USED(&mem_map[MAP_NR(page)]);
91
        for (i = 0; i < NR_BLOCKS; i++) {
92
                if (mask & (1 << i))
93
                        continue;
94
                fsp = PAGE_PTR(page, i);
95
                fsp->prev = prev;
96
        }
97
}
98
 
99
static inline void set_page_links_next(unsigned long page, unsigned long next)
100
{
101
        struct free_small_page *fsp;
102
        unsigned int mask;
103
        int i;
104
 
105
        if (!page)
106
                return;
107
 
108
        mask = USED(&mem_map[MAP_NR(page)]);
109
        for (i = 0; i < NR_BLOCKS; i++) {
110
                if (mask & (1 << i))
111
                        continue;
112
                fsp = PAGE_PTR(page, i);
113
                fsp->next = next;
114
        }
115
}
116
 
117
unsigned long get_small_page(int priority)
118
{
119
        struct free_small_page *fsp;
120
        unsigned long new_page;
121
        unsigned long flags;
122
        struct page *page;
123
        int offset;
124
 
125
        save_flags(flags);
126
        if (!small_page_ptr)
127
                goto need_new_page;
128
        cli();
129
again:
130
        page = mem_map + MAP_NR(small_page_ptr);
131
        offset = offsets[USED(page)];
132
        SET_USED(page, offset);
133
        new_page = (unsigned long)PAGE_PTR(small_page_ptr, offset);
134
        if (USED(page) == 15) {
135
                fsp = (struct free_small_page *)new_page;
136
                set_page_links_prev (fsp->next, 0);
137
                small_page_ptr = fsp->next;
138
        }
139
        restore_flags(flags);
140
        return new_page;
141
 
142
need_new_page:
143
        new_page = __get_free_page(priority);
144
        if (!small_page_ptr) {
145
                if (new_page) {
146
                        set_bit (PG_reserved, &mem_map[MAP_NR(new_page)].flags);
147
                        clear_page_links (new_page);
148
                        cli();
149
                        small_page_ptr = new_page;
150
                        goto again;
151
                }
152
                restore_flags(flags);
153
                return 0;
154
        }
155
        free_page(new_page);
156
        cli();
157
        goto again;
158
}
159
 
160
void free_small_page(unsigned long spage)
161
{
162
        struct free_small_page *ofsp, *cfsp;
163
        unsigned long flags;
164
        struct page *page;
165
        int offset, oldoffset;
166
 
167
        offset = (spage >> SMALL_ALLOC_SHIFT) & (NR_BLOCKS - 1);
168
        spage -= offset << SMALL_ALLOC_SHIFT;
169
 
170
        page = mem_map + MAP_NR(spage);
171
        if (!PageReserved(page) || !USED(page)) {
172
                printk ("Trying to free non-small page from %p\n", __builtin_return_address(0));
173
                return;
174
        }
175
        if (IS_FREE(page, offset)) {
176
                printk ("Trying to free free small page from %p\n", __builtin_return_address(0));
177
                return;
178
        }
179
        save_flags_cli (flags);
180
        oldoffset = offsets[USED(page)];
181
        CLEAR_USED(page, offset);
182
        ofsp = PAGE_PTR(spage, oldoffset);
183
        cfsp = PAGE_PTR(spage, offset);
184
 
185
        if (oldoffset == NR_BLOCKS) { /* going from totally used to mostly used */
186
                cfsp->prev = 0;
187
                cfsp->next = small_page_ptr;
188
                set_page_links_prev (small_page_ptr, spage);
189
                small_page_ptr = spage;
190
        } else if (!USED(page)) {
191
                set_page_links_prev (ofsp->next, ofsp->prev);
192
                set_page_links_next (ofsp->prev, ofsp->next);
193
                if (spage == small_page_ptr)
194
                        small_page_ptr = ofsp->next;
195
                clear_bit (PG_reserved, &page->flags);
196
                restore_flags(flags);
197
                free_page (spage);
198
        } else
199
                *cfsp = *ofsp;
200
        restore_flags(flags);
201
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.