Commit 217bbd81885587b462311fab1b04172926c59f1e
Committed by
Geert Uytterhoeven
1 parent
b7785e9543
Exists in
master
and in
6 other branches
m68k/atari: Reserve some ST-RAM early on for device buffer use
Based on an original patch from Michael Schmitz: Because mem_init() is now called before device init, devices that rely on ST-RAM may find all ST-RAM already allocated to other users by the time device init happens. In particular, a large initrd RAM disk may use up enough of ST-RAM to cause atari_stram_alloc() to resort to __get_dma_pages() allocation. In the current state of Atari memory management, all of RAM is marked DMA capable, so __get_dma_pages() may well return RAM that is not in actual fact DMA capable. Using this for frame buffer or SCSI DMA buffer causes subtle failure. The ST-RAM allocator has been changed to allocate memory from a pool of reserved ST-RAM of configurable size, set aside on ST-RAM init (i.e. before mem_init()). As long as this pool is not exhausted, allocation of real ST-RAM can be guaranteed. Other changes: - Replace the custom allocator in the ST-RAM pool by the existing allocator in the resource subsystem, - Remove mem_init_done and its hook, as memory init is now done before device init, - Remove /proc/stram, as ST-RAM usage now shows up under /proc/iomem, e.g. 005f2000-006f1fff : ST-RAM Pool 005f2000-0063dfff : atafb 0063e000-00641fff : ataflop 00642000-00642fff : SCSI Signed-off-by: Michael Schmitz <schmitz@debian.org> [Andreas Schwab <schwab@linux-m68k.org>: Use memparse()] [Geert: Use the resource subsystem instead of a custom allocator] Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
Showing 4 changed files with 70 additions and 298 deletions Side-by-side Diff
arch/m68k/Kconfig.mmu
... | ... | @@ -372,12 +372,6 @@ |
372 | 372 | Include support in the kernel for pcmcia on Amiga 1200 and Amiga |
373 | 373 | 600. If you intend to use pcmcia cards say Y; otherwise say N. |
374 | 374 | |
375 | -config STRAM_PROC | |
376 | - bool "ST-RAM statistics in /proc" | |
377 | - depends on ATARI | |
378 | - help | |
379 | - Say Y here to report ST-RAM usage statistics in /proc/stram. | |
380 | - | |
381 | 375 | config HEARTBEAT |
382 | 376 | bool "Use power LED as a heartbeat" if AMIGA || APOLLO || ATARI || MAC ||Q40 |
383 | 377 | default y if !AMIGA && !APOLLO && !ATARI && !MAC && !Q40 && HP300 |
arch/m68k/atari/stram.c
1 | 1 | /* |
2 | - * arch/m68k/atari/stram.c: Functions for ST-RAM allocations | |
2 | + * Functions for ST-RAM allocations | |
3 | 3 | * |
4 | 4 | * Copyright 1994-97 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de> |
5 | 5 | * |
6 | 6 | |
7 | 7 | |
8 | 8 | |
9 | 9 | |
10 | 10 | |
11 | 11 | |
12 | 12 | |
13 | 13 | |
14 | 14 | |
15 | 15 | |
16 | 16 | |
... | ... | @@ -30,92 +30,36 @@ |
30 | 30 | #include <asm/atari_stram.h> |
31 | 31 | #include <asm/io.h> |
32 | 32 | |
33 | -#undef DEBUG | |
34 | 33 | |
35 | -#ifdef DEBUG | |
36 | -#define DPRINTK(fmt,args...) printk( fmt, ##args ) | |
37 | -#else | |
38 | -#define DPRINTK(fmt,args...) | |
39 | -#endif | |
40 | - | |
41 | -#if defined(CONFIG_PROC_FS) && defined(CONFIG_STRAM_PROC) | |
42 | -/* abbrev for the && above... */ | |
43 | -#define DO_PROC | |
44 | -#include <linux/proc_fs.h> | |
45 | -#include <linux/seq_file.h> | |
46 | -#endif | |
47 | - | |
48 | 34 | /* |
49 | - * ++roman: | |
50 | - * | |
51 | - * New version of ST-Ram buffer allocation. Instead of using the | |
52 | - * 1 MB - 4 KB that remain when the ST-Ram chunk starts at $1000 | |
53 | - * (1 MB granularity!), such buffers are reserved like this: | |
54 | - * | |
55 | - * - If the kernel resides in ST-Ram anyway, we can take the buffer | |
56 | - * from behind the current kernel data space the normal way | |
57 | - * (incrementing start_mem). | |
58 | - * | |
59 | - * - If the kernel is in TT-Ram, stram_init() initializes start and | |
60 | - * end of the available region. Buffers are allocated from there | |
61 | - * and mem_init() later marks the such used pages as reserved. | |
62 | - * Since each TT-Ram chunk is at least 4 MB in size, I hope there | |
63 | - * won't be an overrun of the ST-Ram region by normal kernel data | |
64 | - * space. | |
65 | - * | |
66 | - * For that, ST-Ram may only be allocated while kernel initialization | |
67 | - * is going on, or exactly: before mem_init() is called. There is also | |
68 | - * no provision now for freeing ST-Ram buffers. It seems that isn't | |
69 | - * really needed. | |
70 | - * | |
35 | + * The ST-RAM allocator allocates memory from a pool of reserved ST-RAM of | |
36 | + * configurable size, set aside on ST-RAM init. | |
37 | + * As long as this pool is not exhausted, allocation of real ST-RAM can be | |
38 | + * guaranteed. | |
71 | 39 | */ |
72 | 40 | |
73 | -/* Start and end (virtual) of ST-RAM */ | |
74 | -static void *stram_start, *stram_end; | |
75 | - | |
76 | -/* set after memory_init() executed and allocations via start_mem aren't | |
77 | - * possible anymore */ | |
78 | -static int mem_init_done; | |
79 | - | |
80 | 41 | /* set if kernel is in ST-RAM */ |
81 | 42 | static int kernel_in_stram; |
82 | 43 | |
83 | -typedef struct stram_block { | |
84 | - struct stram_block *next; | |
85 | - void *start; | |
86 | - unsigned long size; | |
87 | - unsigned flags; | |
88 | - const char *owner; | |
89 | -} BLOCK; | |
44 | +static struct resource stram_pool = { | |
45 | + .name = "ST-RAM Pool" | |
46 | +}; | |
90 | 47 | |
91 | -/* values for flags field */ | |
92 | -#define BLOCK_FREE 0x01 /* free structure in the BLOCKs pool */ | |
93 | -#define BLOCK_KMALLOCED 0x02 /* structure allocated by kmalloc() */ | |
94 | -#define BLOCK_GFP 0x08 /* block allocated with __get_dma_pages() */ | |
48 | +static unsigned long pool_size = 1024*1024; | |
95 | 49 | |
96 | -/* list of allocated blocks */ | |
97 | -static BLOCK *alloc_list; | |
98 | 50 | |
99 | -/* We can't always use kmalloc() to allocate BLOCK structures, since | |
100 | - * stram_alloc() can be called rather early. So we need some pool of | |
101 | - * statically allocated structures. 20 of them is more than enough, so in most | |
102 | - * cases we never should need to call kmalloc(). */ | |
103 | -#define N_STATIC_BLOCKS 20 | |
104 | -static BLOCK static_blocks[N_STATIC_BLOCKS]; | |
51 | +static int __init atari_stram_setup(char *arg) | |
52 | +{ | |
53 | + if (!MACH_IS_ATARI) | |
54 | + return 0; | |
105 | 55 | |
106 | -/***************************** Prototypes *****************************/ | |
56 | + pool_size = memparse(arg, NULL); | |
57 | + return 0; | |
58 | +} | |
107 | 59 | |
108 | -static BLOCK *add_region( void *addr, unsigned long size ); | |
109 | -static BLOCK *find_region( void *addr ); | |
110 | -static int remove_region( BLOCK *block ); | |
60 | +early_param("stram_pool", atari_stram_setup); | |
111 | 61 | |
112 | -/************************* End of Prototypes **************************/ | |
113 | 62 | |
114 | - | |
115 | -/* ------------------------------------------------------------------------ */ | |
116 | -/* Public Interface */ | |
117 | -/* ------------------------------------------------------------------------ */ | |
118 | - | |
119 | 63 | /* |
120 | 64 | * This init function is called very early by atari/config.c |
121 | 65 | * It initializes some internal variables needed for stram_alloc() |
122 | 66 | |
123 | 67 | |
124 | 68 | |
125 | 69 | |
126 | 70 | |
... | ... | @@ -123,25 +67,23 @@ |
123 | 67 | void __init atari_stram_init(void) |
124 | 68 | { |
125 | 69 | int i; |
70 | + void *stram_start; | |
126 | 71 | |
127 | - /* initialize static blocks */ | |
128 | - for( i = 0; i < N_STATIC_BLOCKS; ++i ) | |
129 | - static_blocks[i].flags = BLOCK_FREE; | |
130 | - | |
131 | - /* determine whether kernel code resides in ST-RAM (then ST-RAM is the | |
132 | - * first memory block at virtual 0x0) */ | |
72 | + /* | |
73 | + * determine whether kernel code resides in ST-RAM | |
74 | + * (then ST-RAM is the first memory block at virtual 0x0) | |
75 | + */ | |
133 | 76 | stram_start = phys_to_virt(0); |
134 | 77 | kernel_in_stram = (stram_start == 0); |
135 | 78 | |
136 | - for( i = 0; i < m68k_num_memory; ++i ) { | |
79 | + for (i = 0; i < m68k_num_memory; ++i) { | |
137 | 80 | if (m68k_memory[i].addr == 0) { |
138 | - /* skip first 2kB or page (supervisor-only!) */ | |
139 | - stram_end = stram_start + m68k_memory[i].size; | |
140 | 81 | return; |
141 | 82 | } |
142 | 83 | } |
84 | + | |
143 | 85 | /* Should never come here! (There is always ST-Ram!) */ |
144 | - panic( "atari_stram_init: no ST-RAM found!" ); | |
86 | + panic("atari_stram_init: no ST-RAM found!"); | |
145 | 87 | } |
146 | 88 | |
147 | 89 | |
148 | 90 | |
149 | 91 | |
150 | 92 | |
151 | 93 | |
152 | 94 | |
153 | 95 | |
154 | 96 | |
155 | 97 | |
156 | 98 | |
157 | 99 | |
158 | 100 | |
159 | 101 | |
160 | 102 | |
161 | 103 | |
162 | 104 | |
... | ... | @@ -151,227 +93,69 @@ |
151 | 93 | */ |
152 | 94 | void __init atari_stram_reserve_pages(void *start_mem) |
153 | 95 | { |
154 | - /* always reserve first page of ST-RAM, the first 2 kB are | |
155 | - * supervisor-only! */ | |
96 | + /* | |
97 | + * always reserve first page of ST-RAM, the first 2 KiB are | |
98 | + * supervisor-only! | |
99 | + */ | |
156 | 100 | if (!kernel_in_stram) |
157 | 101 | reserve_bootmem(0, PAGE_SIZE, BOOTMEM_DEFAULT); |
158 | 102 | |
159 | -} | |
103 | + stram_pool.start = (resource_size_t)alloc_bootmem_low_pages(pool_size); | |
104 | + stram_pool.end = stram_pool.start + pool_size - 1; | |
105 | + request_resource(&iomem_resource, &stram_pool); | |
160 | 106 | |
161 | -void atari_stram_mem_init_hook (void) | |
162 | -{ | |
163 | - mem_init_done = 1; | |
107 | + pr_debug("atari_stram pool: size = %lu bytes, resource = %pR\n", | |
108 | + pool_size, &stram_pool); | |
164 | 109 | } |
165 | 110 | |
166 | 111 | |
167 | -/* | |
168 | - * This is main public interface: somehow allocate a ST-RAM block | |
169 | - * | |
170 | - * - If we're before mem_init(), we have to make a static allocation. The | |
171 | - * region is taken in the kernel data area (if the kernel is in ST-RAM) or | |
172 | - * from the start of ST-RAM (if the kernel is in TT-RAM) and added to the | |
173 | - * rsvd_stram_* region. The ST-RAM is somewhere in the middle of kernel | |
174 | - * address space in the latter case. | |
175 | - * | |
176 | - * - If mem_init() already has been called, try with __get_dma_pages(). | |
177 | - * This has the disadvantage that it's very hard to get more than 1 page, | |
178 | - * and it is likely to fail :-( | |
179 | - * | |
180 | - */ | |
181 | -void *atari_stram_alloc(long size, const char *owner) | |
112 | +void *atari_stram_alloc(unsigned long size, const char *owner) | |
182 | 113 | { |
183 | - void *addr = NULL; | |
184 | - BLOCK *block; | |
185 | - int flags; | |
114 | + struct resource *res; | |
115 | + int error; | |
186 | 116 | |
187 | - DPRINTK("atari_stram_alloc(size=%08lx,owner=%s)\n", size, owner); | |
117 | + pr_debug("atari_stram_alloc: allocate %lu bytes\n", size); | |
188 | 118 | |
189 | - if (!mem_init_done) | |
190 | - return alloc_bootmem_low(size); | |
191 | - else { | |
192 | - /* After mem_init(): can only resort to __get_dma_pages() */ | |
193 | - addr = (void *)__get_dma_pages(GFP_KERNEL, get_order(size)); | |
194 | - flags = BLOCK_GFP; | |
195 | - DPRINTK( "atari_stram_alloc: after mem_init, " | |
196 | - "get_pages=%p\n", addr ); | |
197 | - } | |
119 | + /* round up */ | |
120 | + size = PAGE_ALIGN(size); | |
198 | 121 | |
199 | - if (addr) { | |
200 | - if (!(block = add_region( addr, size ))) { | |
201 | - /* out of memory for BLOCK structure :-( */ | |
202 | - DPRINTK( "atari_stram_alloc: out of mem for BLOCK -- " | |
203 | - "freeing again\n" ); | |
204 | - free_pages((unsigned long)addr, get_order(size)); | |
205 | - return( NULL ); | |
206 | - } | |
207 | - block->owner = owner; | |
208 | - block->flags |= flags; | |
122 | + res = kzalloc(sizeof(struct resource), GFP_KERNEL); | |
123 | + if (!res) | |
124 | + return NULL; | |
125 | + | |
126 | + res->name = owner; | |
127 | + error = allocate_resource(&stram_pool, res, size, 0, UINT_MAX, | |
128 | + PAGE_SIZE, NULL, NULL); | |
129 | + if (error < 0) { | |
130 | + pr_err("atari_stram_alloc: allocate_resource() failed %d!\n", | |
131 | + error); | |
132 | + kfree(res); | |
133 | + return NULL; | |
209 | 134 | } |
210 | - return( addr ); | |
135 | + | |
136 | + pr_debug("atari_stram_alloc: returning %pR\n", res); | |
137 | + return (void *)res->start; | |
211 | 138 | } |
212 | 139 | EXPORT_SYMBOL(atari_stram_alloc); |
213 | 140 | |
214 | -void atari_stram_free( void *addr ) | |
215 | 141 | |
142 | +void atari_stram_free(void *addr) | |
216 | 143 | { |
217 | - BLOCK *block; | |
144 | + unsigned long start = (unsigned long)addr; | |
145 | + struct resource *res; | |
146 | + unsigned long size; | |
218 | 147 | |
219 | - DPRINTK( "atari_stram_free(addr=%p)\n", addr ); | |
220 | - | |
221 | - if (!(block = find_region( addr ))) { | |
222 | - printk( KERN_ERR "Attempt to free non-allocated ST-RAM block at %p " | |
223 | - "from %p\n", addr, __builtin_return_address(0) ); | |
148 | + res = lookup_resource(&stram_pool, start); | |
149 | + if (!res) { | |
150 | + pr_err("atari_stram_free: trying to free nonexistent region " | |
151 | + "at %p\n", addr); | |
224 | 152 | return; |
225 | 153 | } |
226 | - DPRINTK( "atari_stram_free: found block (%p): size=%08lx, owner=%s, " | |
227 | - "flags=%02x\n", block, block->size, block->owner, block->flags ); | |
228 | 154 | |
229 | - if (!(block->flags & BLOCK_GFP)) | |
230 | - goto fail; | |
231 | - | |
232 | - DPRINTK("atari_stram_free: is kmalloced, order_size=%d\n", | |
233 | - get_order(block->size)); | |
234 | - free_pages((unsigned long)addr, get_order(block->size)); | |
235 | - remove_region( block ); | |
236 | - return; | |
237 | - | |
238 | - fail: | |
239 | - printk( KERN_ERR "atari_stram_free: cannot free block at %p " | |
240 | - "(called from %p)\n", addr, __builtin_return_address(0) ); | |
155 | + size = resource_size(res); | |
156 | + pr_debug("atari_stram_free: free %lu bytes at %p\n", size, addr); | |
157 | + release_resource(res); | |
158 | + kfree(res); | |
241 | 159 | } |
242 | 160 | EXPORT_SYMBOL(atari_stram_free); |
243 | - | |
244 | - | |
245 | -/* ------------------------------------------------------------------------ */ | |
246 | -/* Region Management */ | |
247 | -/* ------------------------------------------------------------------------ */ | |
248 | - | |
249 | - | |
250 | -/* insert a region into the alloced list (sorted) */ | |
251 | -static BLOCK *add_region( void *addr, unsigned long size ) | |
252 | -{ | |
253 | - BLOCK **p, *n = NULL; | |
254 | - int i; | |
255 | - | |
256 | - for( i = 0; i < N_STATIC_BLOCKS; ++i ) { | |
257 | - if (static_blocks[i].flags & BLOCK_FREE) { | |
258 | - n = &static_blocks[i]; | |
259 | - n->flags = 0; | |
260 | - break; | |
261 | - } | |
262 | - } | |
263 | - if (!n && mem_init_done) { | |
264 | - /* if statics block pool exhausted and we can call kmalloc() already | |
265 | - * (after mem_init()), try that */ | |
266 | - n = kmalloc( sizeof(BLOCK), GFP_KERNEL ); | |
267 | - if (n) | |
268 | - n->flags = BLOCK_KMALLOCED; | |
269 | - } | |
270 | - if (!n) { | |
271 | - printk( KERN_ERR "Out of memory for ST-RAM descriptor blocks\n" ); | |
272 | - return( NULL ); | |
273 | - } | |
274 | - n->start = addr; | |
275 | - n->size = size; | |
276 | - | |
277 | - for( p = &alloc_list; *p; p = &((*p)->next) ) | |
278 | - if ((*p)->start > addr) break; | |
279 | - n->next = *p; | |
280 | - *p = n; | |
281 | - | |
282 | - return( n ); | |
283 | -} | |
284 | - | |
285 | - | |
286 | -/* find a region (by start addr) in the alloced list */ | |
287 | -static BLOCK *find_region( void *addr ) | |
288 | -{ | |
289 | - BLOCK *p; | |
290 | - | |
291 | - for( p = alloc_list; p; p = p->next ) { | |
292 | - if (p->start == addr) | |
293 | - return( p ); | |
294 | - if (p->start > addr) | |
295 | - break; | |
296 | - } | |
297 | - return( NULL ); | |
298 | -} | |
299 | - | |
300 | - | |
301 | -/* remove a block from the alloced list */ | |
302 | -static int remove_region( BLOCK *block ) | |
303 | -{ | |
304 | - BLOCK **p; | |
305 | - | |
306 | - for( p = &alloc_list; *p; p = &((*p)->next) ) | |
307 | - if (*p == block) break; | |
308 | - if (!*p) | |
309 | - return( 0 ); | |
310 | - | |
311 | - *p = block->next; | |
312 | - if (block->flags & BLOCK_KMALLOCED) | |
313 | - kfree( block ); | |
314 | - else | |
315 | - block->flags |= BLOCK_FREE; | |
316 | - return( 1 ); | |
317 | -} | |
318 | - | |
319 | - | |
320 | - | |
321 | -/* ------------------------------------------------------------------------ */ | |
322 | -/* /proc statistics file stuff */ | |
323 | -/* ------------------------------------------------------------------------ */ | |
324 | - | |
325 | -#ifdef DO_PROC | |
326 | - | |
327 | -#define PRINT_PROC(fmt,args...) seq_printf( m, fmt, ##args ) | |
328 | - | |
329 | -static int stram_proc_show(struct seq_file *m, void *v) | |
330 | -{ | |
331 | - BLOCK *p; | |
332 | - | |
333 | - PRINT_PROC("Total ST-RAM: %8u kB\n", | |
334 | - (stram_end - stram_start) >> 10); | |
335 | - PRINT_PROC( "Allocated regions:\n" ); | |
336 | - for( p = alloc_list; p; p = p->next ) { | |
337 | - PRINT_PROC("0x%08lx-0x%08lx: %s (", | |
338 | - virt_to_phys(p->start), | |
339 | - virt_to_phys(p->start+p->size-1), | |
340 | - p->owner); | |
341 | - if (p->flags & BLOCK_GFP) | |
342 | - PRINT_PROC( "page-alloced)\n" ); | |
343 | - else | |
344 | - PRINT_PROC( "??)\n" ); | |
345 | - } | |
346 | - | |
347 | - return 0; | |
348 | -} | |
349 | - | |
350 | -static int stram_proc_open(struct inode *inode, struct file *file) | |
351 | -{ | |
352 | - return single_open(file, stram_proc_show, NULL); | |
353 | -} | |
354 | - | |
355 | -static const struct file_operations stram_proc_fops = { | |
356 | - .open = stram_proc_open, | |
357 | - .read = seq_read, | |
358 | - .llseek = seq_lseek, | |
359 | - .release = single_release, | |
360 | -}; | |
361 | - | |
362 | -static int __init proc_stram_init(void) | |
363 | -{ | |
364 | - proc_create("stram", 0, NULL, &stram_proc_fops); | |
365 | - return 0; | |
366 | -} | |
367 | -module_init(proc_stram_init); | |
368 | -#endif | |
369 | - | |
370 | - | |
371 | -/* | |
372 | - * Local variables: | |
373 | - * c-indent-level: 4 | |
374 | - * tab-width: 4 | |
375 | - * End: | |
376 | - */ |
arch/m68k/include/asm/atari_stram.h
... | ... | @@ -6,13 +6,12 @@ |
6 | 6 | */ |
7 | 7 | |
8 | 8 | /* public interface */ |
9 | -void *atari_stram_alloc(long size, const char *owner); | |
9 | +void *atari_stram_alloc(unsigned long size, const char *owner); | |
10 | 10 | void atari_stram_free(void *); |
11 | 11 | |
12 | 12 | /* functions called internally by other parts of the kernel */ |
13 | 13 | void atari_stram_init(void); |
14 | 14 | void atari_stram_reserve_pages(void *start_mem); |
15 | -void atari_stram_mem_init_hook (void); | |
16 | 15 | |
17 | 16 | #endif /*_M68K_ATARI_STRAM_H */ |
arch/m68k/mm/init_mm.c
... | ... | @@ -83,11 +83,6 @@ |
83 | 83 | int initpages = 0; |
84 | 84 | int i; |
85 | 85 | |
86 | -#ifdef CONFIG_ATARI | |
87 | - if (MACH_IS_ATARI) | |
88 | - atari_stram_mem_init_hook(); | |
89 | -#endif | |
90 | - | |
91 | 86 | /* this will put all memory onto the freelists */ |
92 | 87 | totalram_pages = num_physpages = 0; |
93 | 88 | for_each_online_pgdat(pgdat) { |