aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Schmitz <schmitzmic@googlemail.com>2010-11-01 14:54:00 -0400
committerGeert Uytterhoeven <geert@linux-m68k.org>2011-07-30 15:21:39 -0400
commit217bbd81885587b462311fab1b04172926c59f1e (patch)
treec914306226654e239683e3c374c57ba85d9a5d9a
parentb7785e954348465e1926d9c10ff3e49c207d4ec6 (diff)
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>
-rw-r--r--arch/m68k/Kconfig.mmu6
-rw-r--r--arch/m68k/atari/stram.c354
-rw-r--r--arch/m68k/include/asm/atari_stram.h3
-rw-r--r--arch/m68k/mm/init_mm.c5
4 files changed, 70 insertions, 298 deletions
diff --git a/arch/m68k/Kconfig.mmu b/arch/m68k/Kconfig.mmu
index 16539b1d5d3a..13e20bbc4079 100644
--- a/arch/m68k/Kconfig.mmu
+++ b/arch/m68k/Kconfig.mmu
@@ -372,12 +372,6 @@ config AMIGA_PCMCIA
372 Include support in the kernel for pcmcia on Amiga 1200 and Amiga 372 Include support in the kernel for pcmcia on Amiga 1200 and Amiga
373 600. If you intend to use pcmcia cards say Y; otherwise say N. 373 600. If you intend to use pcmcia cards say Y; otherwise say N.
374 374
375config 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
381config HEARTBEAT 375config HEARTBEAT
382 bool "Use power LED as a heartbeat" if AMIGA || APOLLO || ATARI || MAC ||Q40 376 bool "Use power LED as a heartbeat" if AMIGA || APOLLO || ATARI || MAC ||Q40
383 default y if !AMIGA && !APOLLO && !ATARI && !MAC && !Q40 && HP300 377 default y if !AMIGA && !APOLLO && !ATARI && !MAC && !Q40 && HP300
diff --git a/arch/m68k/atari/stram.c b/arch/m68k/atari/stram.c
index 6ec3b7f33779..0810c8d56e59 100644
--- a/arch/m68k/atari/stram.c
+++ b/arch/m68k/atari/stram.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * arch/m68k/atari/stram.c: Functions for ST-RAM allocations 2 * Functions for ST-RAM allocations
3 * 3 *
4 * Copyright 1994-97 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de> 4 * Copyright 1994-97 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
5 * 5 *
@@ -30,91 +30,35 @@
30#include <asm/atari_stram.h> 30#include <asm/atari_stram.h>
31#include <asm/io.h> 31#include <asm/io.h>
32 32
33#undef DEBUG
34
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 33
48/* 34/*
49 * ++roman: 35 * The ST-RAM allocator allocates memory from a pool of reserved ST-RAM of
50 * 36 * configurable size, set aside on ST-RAM init.
51 * New version of ST-Ram buffer allocation. Instead of using the 37 * As long as this pool is not exhausted, allocation of real ST-RAM can be
52 * 1 MB - 4 KB that remain when the ST-Ram chunk starts at $1000 38 * guaranteed.
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 *
71 */ 39 */
72 40
73/* Start and end (virtual) of ST-RAM */
74static void *stram_start, *stram_end;
75
76/* set after memory_init() executed and allocations via start_mem aren't
77 * possible anymore */
78static int mem_init_done;
79
80/* set if kernel is in ST-RAM */ 41/* set if kernel is in ST-RAM */
81static int kernel_in_stram; 42static int kernel_in_stram;
82 43
83typedef struct stram_block { 44static struct resource stram_pool = {
84 struct stram_block *next; 45 .name = "ST-RAM Pool"
85 void *start; 46};
86 unsigned long size;
87 unsigned flags;
88 const char *owner;
89} BLOCK;
90
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() */
95 47
96/* list of allocated blocks */ 48static unsigned long pool_size = 1024*1024;
97static BLOCK *alloc_list;
98 49
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
104static BLOCK static_blocks[N_STATIC_BLOCKS];
105 50
106/***************************** Prototypes *****************************/ 51static int __init atari_stram_setup(char *arg)
52{
53 if (!MACH_IS_ATARI)
54 return 0;
107 55
108static BLOCK *add_region( void *addr, unsigned long size ); 56 pool_size = memparse(arg, NULL);
109static BLOCK *find_region( void *addr ); 57 return 0;
110static int remove_region( BLOCK *block ); 58}
111 59
112/************************* End of Prototypes **************************/ 60early_param("stram_pool", atari_stram_setup);
113 61
114
115/* ------------------------------------------------------------------------ */
116/* Public Interface */
117/* ------------------------------------------------------------------------ */
118 62
119/* 63/*
120 * This init function is called very early by atari/config.c 64 * This init function is called very early by atari/config.c
@@ -123,25 +67,23 @@ static int remove_region( BLOCK *block );
123void __init atari_stram_init(void) 67void __init atari_stram_init(void)
124{ 68{
125 int i; 69 int i;
70 void *stram_start;
126 71
127 /* initialize static blocks */ 72 /*
128 for( i = 0; i < N_STATIC_BLOCKS; ++i ) 73 * determine whether kernel code resides in ST-RAM
129 static_blocks[i].flags = BLOCK_FREE; 74 * (then ST-RAM is the first memory block at virtual 0x0)
130 75 */
131 /* determine whether kernel code resides in ST-RAM (then ST-RAM is the
132 * first memory block at virtual 0x0) */
133 stram_start = phys_to_virt(0); 76 stram_start = phys_to_virt(0);
134 kernel_in_stram = (stram_start == 0); 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 if (m68k_memory[i].addr == 0) { 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 return; 81 return;
141 } 82 }
142 } 83 }
84
143 /* Should never come here! (There is always ST-Ram!) */ 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
@@ -151,226 +93,68 @@ void __init atari_stram_init(void)
151 */ 93 */
152void __init atari_stram_reserve_pages(void *start_mem) 94void __init atari_stram_reserve_pages(void *start_mem)
153{ 95{
154 /* always reserve first page of ST-RAM, the first 2 kB are 96 /*
155 * supervisor-only! */ 97 * always reserve first page of ST-RAM, the first 2 KiB are
98 * supervisor-only!
99 */
156 if (!kernel_in_stram) 100 if (!kernel_in_stram)
157 reserve_bootmem(0, PAGE_SIZE, BOOTMEM_DEFAULT); 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
161void atari_stram_mem_init_hook (void) 107 pr_debug("atari_stram pool: size = %lu bytes, resource = %pR\n",
162{ 108 pool_size, &stram_pool);
163 mem_init_done = 1;
164} 109}
165 110
166 111
167/* 112void *atari_stram_alloc(unsigned long size, const char *owner)
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 */
181void *atari_stram_alloc(long size, const char *owner)
182{ 113{
183 void *addr = NULL; 114 struct resource *res;
184 BLOCK *block; 115 int error;
185 int flags; 116
186 117 pr_debug("atari_stram_alloc: allocate %lu bytes\n", size);
187 DPRINTK("atari_stram_alloc(size=%08lx,owner=%s)\n", size, owner); 118
188 119 /* round up */
189 if (!mem_init_done) 120 size = PAGE_ALIGN(size);
190 return alloc_bootmem_low(size); 121
191 else { 122 res = kzalloc(sizeof(struct resource), GFP_KERNEL);
192 /* After mem_init(): can only resort to __get_dma_pages() */ 123 if (!res)
193 addr = (void *)__get_dma_pages(GFP_KERNEL, get_order(size)); 124 return NULL;
194 flags = BLOCK_GFP; 125
195 DPRINTK( "atari_stram_alloc: after mem_init, " 126 res->name = owner;
196 "get_pages=%p\n", addr ); 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;
197 } 134 }
198 135
199 if (addr) { 136 pr_debug("atari_stram_alloc: returning %pR\n", res);
200 if (!(block = add_region( addr, size ))) { 137 return (void *)res->start;
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;
209 }
210 return( addr );
211} 138}
212EXPORT_SYMBOL(atari_stram_alloc); 139EXPORT_SYMBOL(atari_stram_alloc);
213 140
214void atari_stram_free( void *addr )
215 141
142void atari_stram_free(void *addr)
216{ 143{
217 BLOCK *block; 144 unsigned long start = (unsigned long)addr;
218 145 struct resource *res;
219 DPRINTK( "atari_stram_free(addr=%p)\n", addr ); 146 unsigned long size;
220 147
221 if (!(block = find_region( addr ))) { 148 res = lookup_resource(&stram_pool, start);
222 printk( KERN_ERR "Attempt to free non-allocated ST-RAM block at %p " 149 if (!res) {
223 "from %p\n", addr, __builtin_return_address(0) ); 150 pr_err("atari_stram_free: trying to free nonexistent region "
151 "at %p\n", addr);
224 return; 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
229 if (!(block->flags & BLOCK_GFP))
230 goto fail;
231 154
232 DPRINTK("atari_stram_free: is kmalloced, order_size=%d\n", 155 size = resource_size(res);
233 get_order(block->size)); 156 pr_debug("atari_stram_free: free %lu bytes at %p\n", size, addr);
234 free_pages((unsigned long)addr, get_order(block->size)); 157 release_resource(res);
235 remove_region( block ); 158 kfree(res);
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) );
241} 159}
242EXPORT_SYMBOL(atari_stram_free); 160EXPORT_SYMBOL(atari_stram_free);
243
244
245/* ------------------------------------------------------------------------ */
246/* Region Management */
247/* ------------------------------------------------------------------------ */
248
249
250/* insert a region into the alloced list (sorted) */
251static 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 */
287static 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 */
302static 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
329static 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
350static int stram_proc_open(struct inode *inode, struct file *file)
351{
352 return single_open(file, stram_proc_show, NULL);
353}
354
355static 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
362static int __init proc_stram_init(void)
363{
364 proc_create("stram", 0, NULL, &stram_proc_fops);
365 return 0;
366}
367module_init(proc_stram_init);
368#endif
369
370
371/*
372 * Local variables:
373 * c-indent-level: 4
374 * tab-width: 4
375 * End:
376 */
diff --git a/arch/m68k/include/asm/atari_stram.h b/arch/m68k/include/asm/atari_stram.h
index 7546d13963be..62e27598af91 100644
--- a/arch/m68k/include/asm/atari_stram.h
+++ b/arch/m68k/include/asm/atari_stram.h
@@ -6,12 +6,11 @@
6 */ 6 */
7 7
8/* public interface */ 8/* public interface */
9void *atari_stram_alloc(long size, const char *owner); 9void *atari_stram_alloc(unsigned long size, const char *owner);
10void atari_stram_free(void *); 10void atari_stram_free(void *);
11 11
12/* functions called internally by other parts of the kernel */ 12/* functions called internally by other parts of the kernel */
13void atari_stram_init(void); 13void atari_stram_init(void);
14void atari_stram_reserve_pages(void *start_mem); 14void atari_stram_reserve_pages(void *start_mem);
15void atari_stram_mem_init_hook (void);
16 15
17#endif /*_M68K_ATARI_STRAM_H */ 16#endif /*_M68K_ATARI_STRAM_H */
diff --git a/arch/m68k/mm/init_mm.c b/arch/m68k/mm/init_mm.c
index 9113c2f17607..bbe525434ccb 100644
--- a/arch/m68k/mm/init_mm.c
+++ b/arch/m68k/mm/init_mm.c
@@ -83,11 +83,6 @@ void __init mem_init(void)
83 int initpages = 0; 83 int initpages = 0;
84 int i; 84 int i;
85 85
86#ifdef CONFIG_ATARI
87 if (MACH_IS_ATARI)
88 atari_stram_mem_init_hook();
89#endif
90
91 /* this will put all memory onto the freelists */ 86 /* this will put all memory onto the freelists */
92 totalram_pages = num_physpages = 0; 87 totalram_pages = num_physpages = 0;
93 for_each_online_pgdat(pgdat) { 88 for_each_online_pgdat(pgdat) {