diff options
Diffstat (limited to 'drivers/block/z2ram.c')
-rw-r--r-- | drivers/block/z2ram.c | 429 |
1 files changed, 429 insertions, 0 deletions
diff --git a/drivers/block/z2ram.c b/drivers/block/z2ram.c new file mode 100644 index 000000000000..007f6a662439 --- /dev/null +++ b/drivers/block/z2ram.c | |||
@@ -0,0 +1,429 @@ | |||
1 | /* | ||
2 | ** z2ram - Amiga pseudo-driver to access 16bit-RAM in ZorroII space | ||
3 | ** as a block device, to be used as a RAM disk or swap space | ||
4 | ** | ||
5 | ** Copyright (C) 1994 by Ingo Wilken (Ingo.Wilken@informatik.uni-oldenburg.de) | ||
6 | ** | ||
7 | ** ++Geert: support for zorro_unused_z2ram, better range checking | ||
8 | ** ++roman: translate accesses via an array | ||
9 | ** ++Milan: support for ChipRAM usage | ||
10 | ** ++yambo: converted to 2.0 kernel | ||
11 | ** ++yambo: modularized and support added for 3 minor devices including: | ||
12 | ** MAJOR MINOR DESCRIPTION | ||
13 | ** ----- ----- ---------------------------------------------- | ||
14 | ** 37 0 Use Zorro II and Chip ram | ||
15 | ** 37 1 Use only Zorro II ram | ||
16 | ** 37 2 Use only Chip ram | ||
17 | ** 37 4-7 Use memory list entry 1-4 (first is 0) | ||
18 | ** ++jskov: support for 1-4th memory list entry. | ||
19 | ** | ||
20 | ** Permission to use, copy, modify, and distribute this software and its | ||
21 | ** documentation for any purpose and without fee is hereby granted, provided | ||
22 | ** that the above copyright notice appear in all copies and that both that | ||
23 | ** copyright notice and this permission notice appear in supporting | ||
24 | ** documentation. This software is provided "as is" without express or | ||
25 | ** implied warranty. | ||
26 | */ | ||
27 | |||
28 | #define DEVICE_NAME "Z2RAM" | ||
29 | |||
30 | #include <linux/major.h> | ||
31 | #include <linux/vmalloc.h> | ||
32 | #include <linux/init.h> | ||
33 | #include <linux/module.h> | ||
34 | #include <linux/blkdev.h> | ||
35 | #include <linux/bitops.h> | ||
36 | |||
37 | #include <asm/setup.h> | ||
38 | #include <asm/amigahw.h> | ||
39 | #include <asm/pgtable.h> | ||
40 | |||
41 | #include <linux/zorro.h> | ||
42 | |||
43 | |||
44 | extern int m68k_realnum_memory; | ||
45 | extern struct mem_info m68k_memory[NUM_MEMINFO]; | ||
46 | |||
47 | #define TRUE (1) | ||
48 | #define FALSE (0) | ||
49 | |||
50 | #define Z2MINOR_COMBINED (0) | ||
51 | #define Z2MINOR_Z2ONLY (1) | ||
52 | #define Z2MINOR_CHIPONLY (2) | ||
53 | #define Z2MINOR_MEMLIST1 (4) | ||
54 | #define Z2MINOR_MEMLIST2 (5) | ||
55 | #define Z2MINOR_MEMLIST3 (6) | ||
56 | #define Z2MINOR_MEMLIST4 (7) | ||
57 | #define Z2MINOR_COUNT (8) /* Move this down when adding a new minor */ | ||
58 | |||
59 | #define Z2RAM_CHUNK1024 ( Z2RAM_CHUNKSIZE >> 10 ) | ||
60 | |||
61 | static u_long *z2ram_map = NULL; | ||
62 | static u_long z2ram_size = 0; | ||
63 | static int z2_count = 0; | ||
64 | static int chip_count = 0; | ||
65 | static int list_count = 0; | ||
66 | static int current_device = -1; | ||
67 | |||
68 | static DEFINE_SPINLOCK(z2ram_lock); | ||
69 | |||
70 | static struct block_device_operations z2_fops; | ||
71 | static struct gendisk *z2ram_gendisk; | ||
72 | |||
73 | static void do_z2_request(request_queue_t *q) | ||
74 | { | ||
75 | struct request *req; | ||
76 | while ((req = elv_next_request(q)) != NULL) { | ||
77 | unsigned long start = req->sector << 9; | ||
78 | unsigned long len = req->current_nr_sectors << 9; | ||
79 | |||
80 | if (start + len > z2ram_size) { | ||
81 | printk( KERN_ERR DEVICE_NAME ": bad access: block=%lu, count=%u\n", | ||
82 | req->sector, req->current_nr_sectors); | ||
83 | end_request(req, 0); | ||
84 | continue; | ||
85 | } | ||
86 | while (len) { | ||
87 | unsigned long addr = start & Z2RAM_CHUNKMASK; | ||
88 | unsigned long size = Z2RAM_CHUNKSIZE - addr; | ||
89 | if (len < size) | ||
90 | size = len; | ||
91 | addr += z2ram_map[ start >> Z2RAM_CHUNKSHIFT ]; | ||
92 | if (rq_data_dir(req) == READ) | ||
93 | memcpy(req->buffer, (char *)addr, size); | ||
94 | else | ||
95 | memcpy((char *)addr, req->buffer, size); | ||
96 | start += size; | ||
97 | len -= size; | ||
98 | } | ||
99 | end_request(req, 1); | ||
100 | } | ||
101 | } | ||
102 | |||
103 | static void | ||
104 | get_z2ram( void ) | ||
105 | { | ||
106 | int i; | ||
107 | |||
108 | for ( i = 0; i < Z2RAM_SIZE / Z2RAM_CHUNKSIZE; i++ ) | ||
109 | { | ||
110 | if ( test_bit( i, zorro_unused_z2ram ) ) | ||
111 | { | ||
112 | z2_count++; | ||
113 | z2ram_map[ z2ram_size++ ] = | ||
114 | ZTWO_VADDR( Z2RAM_START ) + ( i << Z2RAM_CHUNKSHIFT ); | ||
115 | clear_bit( i, zorro_unused_z2ram ); | ||
116 | } | ||
117 | } | ||
118 | |||
119 | return; | ||
120 | } | ||
121 | |||
122 | static void | ||
123 | get_chipram( void ) | ||
124 | { | ||
125 | |||
126 | while ( amiga_chip_avail() > ( Z2RAM_CHUNKSIZE * 4 ) ) | ||
127 | { | ||
128 | chip_count++; | ||
129 | z2ram_map[ z2ram_size ] = | ||
130 | (u_long)amiga_chip_alloc( Z2RAM_CHUNKSIZE, "z2ram" ); | ||
131 | |||
132 | if ( z2ram_map[ z2ram_size ] == 0 ) | ||
133 | { | ||
134 | break; | ||
135 | } | ||
136 | |||
137 | z2ram_size++; | ||
138 | } | ||
139 | |||
140 | return; | ||
141 | } | ||
142 | |||
143 | static int | ||
144 | z2_open( struct inode *inode, struct file *filp ) | ||
145 | { | ||
146 | int device; | ||
147 | int max_z2_map = ( Z2RAM_SIZE / Z2RAM_CHUNKSIZE ) * | ||
148 | sizeof( z2ram_map[0] ); | ||
149 | int max_chip_map = ( amiga_chip_size / Z2RAM_CHUNKSIZE ) * | ||
150 | sizeof( z2ram_map[0] ); | ||
151 | int rc = -ENOMEM; | ||
152 | |||
153 | device = iminor(inode); | ||
154 | |||
155 | if ( current_device != -1 && current_device != device ) | ||
156 | { | ||
157 | rc = -EBUSY; | ||
158 | goto err_out; | ||
159 | } | ||
160 | |||
161 | if ( current_device == -1 ) | ||
162 | { | ||
163 | z2_count = 0; | ||
164 | chip_count = 0; | ||
165 | list_count = 0; | ||
166 | z2ram_size = 0; | ||
167 | |||
168 | /* Use a specific list entry. */ | ||
169 | if (device >= Z2MINOR_MEMLIST1 && device <= Z2MINOR_MEMLIST4) { | ||
170 | int index = device - Z2MINOR_MEMLIST1 + 1; | ||
171 | unsigned long size, paddr, vaddr; | ||
172 | |||
173 | if (index >= m68k_realnum_memory) { | ||
174 | printk( KERN_ERR DEVICE_NAME | ||
175 | ": no such entry in z2ram_map\n" ); | ||
176 | goto err_out; | ||
177 | } | ||
178 | |||
179 | paddr = m68k_memory[index].addr; | ||
180 | size = m68k_memory[index].size & ~(Z2RAM_CHUNKSIZE-1); | ||
181 | |||
182 | #ifdef __powerpc__ | ||
183 | /* FIXME: ioremap doesn't build correct memory tables. */ | ||
184 | { | ||
185 | vfree(vmalloc (size)); | ||
186 | } | ||
187 | |||
188 | vaddr = (unsigned long) __ioremap (paddr, size, | ||
189 | _PAGE_WRITETHRU); | ||
190 | |||
191 | #else | ||
192 | vaddr = (unsigned long)z_remap_nocache_nonser(paddr, size); | ||
193 | #endif | ||
194 | z2ram_map = | ||
195 | kmalloc((size/Z2RAM_CHUNKSIZE)*sizeof(z2ram_map[0]), | ||
196 | GFP_KERNEL); | ||
197 | if ( z2ram_map == NULL ) | ||
198 | { | ||
199 | printk( KERN_ERR DEVICE_NAME | ||
200 | ": cannot get mem for z2ram_map\n" ); | ||
201 | goto err_out; | ||
202 | } | ||
203 | |||
204 | while (size) { | ||
205 | z2ram_map[ z2ram_size++ ] = vaddr; | ||
206 | size -= Z2RAM_CHUNKSIZE; | ||
207 | vaddr += Z2RAM_CHUNKSIZE; | ||
208 | list_count++; | ||
209 | } | ||
210 | |||
211 | if ( z2ram_size != 0 ) | ||
212 | printk( KERN_INFO DEVICE_NAME | ||
213 | ": using %iK List Entry %d Memory\n", | ||
214 | list_count * Z2RAM_CHUNK1024, index ); | ||
215 | } else | ||
216 | |||
217 | switch ( device ) | ||
218 | { | ||
219 | case Z2MINOR_COMBINED: | ||
220 | |||
221 | z2ram_map = kmalloc( max_z2_map + max_chip_map, GFP_KERNEL ); | ||
222 | if ( z2ram_map == NULL ) | ||
223 | { | ||
224 | printk( KERN_ERR DEVICE_NAME | ||
225 | ": cannot get mem for z2ram_map\n" ); | ||
226 | goto err_out; | ||
227 | } | ||
228 | |||
229 | get_z2ram(); | ||
230 | get_chipram(); | ||
231 | |||
232 | if ( z2ram_size != 0 ) | ||
233 | printk( KERN_INFO DEVICE_NAME | ||
234 | ": using %iK Zorro II RAM and %iK Chip RAM (Total %dK)\n", | ||
235 | z2_count * Z2RAM_CHUNK1024, | ||
236 | chip_count * Z2RAM_CHUNK1024, | ||
237 | ( z2_count + chip_count ) * Z2RAM_CHUNK1024 ); | ||
238 | |||
239 | break; | ||
240 | |||
241 | case Z2MINOR_Z2ONLY: | ||
242 | z2ram_map = kmalloc( max_z2_map, GFP_KERNEL ); | ||
243 | if ( z2ram_map == NULL ) | ||
244 | { | ||
245 | printk( KERN_ERR DEVICE_NAME | ||
246 | ": cannot get mem for z2ram_map\n" ); | ||
247 | goto err_out; | ||
248 | } | ||
249 | |||
250 | get_z2ram(); | ||
251 | |||
252 | if ( z2ram_size != 0 ) | ||
253 | printk( KERN_INFO DEVICE_NAME | ||
254 | ": using %iK of Zorro II RAM\n", | ||
255 | z2_count * Z2RAM_CHUNK1024 ); | ||
256 | |||
257 | break; | ||
258 | |||
259 | case Z2MINOR_CHIPONLY: | ||
260 | z2ram_map = kmalloc( max_chip_map, GFP_KERNEL ); | ||
261 | if ( z2ram_map == NULL ) | ||
262 | { | ||
263 | printk( KERN_ERR DEVICE_NAME | ||
264 | ": cannot get mem for z2ram_map\n" ); | ||
265 | goto err_out; | ||
266 | } | ||
267 | |||
268 | get_chipram(); | ||
269 | |||
270 | if ( z2ram_size != 0 ) | ||
271 | printk( KERN_INFO DEVICE_NAME | ||
272 | ": using %iK Chip RAM\n", | ||
273 | chip_count * Z2RAM_CHUNK1024 ); | ||
274 | |||
275 | break; | ||
276 | |||
277 | default: | ||
278 | rc = -ENODEV; | ||
279 | goto err_out; | ||
280 | |||
281 | break; | ||
282 | } | ||
283 | |||
284 | if ( z2ram_size == 0 ) | ||
285 | { | ||
286 | printk( KERN_NOTICE DEVICE_NAME | ||
287 | ": no unused ZII/Chip RAM found\n" ); | ||
288 | goto err_out_kfree; | ||
289 | } | ||
290 | |||
291 | current_device = device; | ||
292 | z2ram_size <<= Z2RAM_CHUNKSHIFT; | ||
293 | set_capacity(z2ram_gendisk, z2ram_size >> 9); | ||
294 | } | ||
295 | |||
296 | return 0; | ||
297 | |||
298 | err_out_kfree: | ||
299 | kfree( z2ram_map ); | ||
300 | err_out: | ||
301 | return rc; | ||
302 | } | ||
303 | |||
304 | static int | ||
305 | z2_release( struct inode *inode, struct file *filp ) | ||
306 | { | ||
307 | if ( current_device == -1 ) | ||
308 | return 0; | ||
309 | |||
310 | /* | ||
311 | * FIXME: unmap memory | ||
312 | */ | ||
313 | |||
314 | return 0; | ||
315 | } | ||
316 | |||
317 | static struct block_device_operations z2_fops = | ||
318 | { | ||
319 | .owner = THIS_MODULE, | ||
320 | .open = z2_open, | ||
321 | .release = z2_release, | ||
322 | }; | ||
323 | |||
324 | static struct kobject *z2_find(dev_t dev, int *part, void *data) | ||
325 | { | ||
326 | *part = 0; | ||
327 | return get_disk(z2ram_gendisk); | ||
328 | } | ||
329 | |||
330 | static struct request_queue *z2_queue; | ||
331 | |||
332 | int __init | ||
333 | z2_init(void) | ||
334 | { | ||
335 | int ret; | ||
336 | |||
337 | if (!MACH_IS_AMIGA) | ||
338 | return -ENXIO; | ||
339 | |||
340 | ret = -EBUSY; | ||
341 | if (register_blkdev(Z2RAM_MAJOR, DEVICE_NAME)) | ||
342 | goto err; | ||
343 | |||
344 | ret = -ENOMEM; | ||
345 | z2ram_gendisk = alloc_disk(1); | ||
346 | if (!z2ram_gendisk) | ||
347 | goto out_disk; | ||
348 | |||
349 | z2_queue = blk_init_queue(do_z2_request, &z2ram_lock); | ||
350 | if (!z2_queue) | ||
351 | goto out_queue; | ||
352 | |||
353 | z2ram_gendisk->major = Z2RAM_MAJOR; | ||
354 | z2ram_gendisk->first_minor = 0; | ||
355 | z2ram_gendisk->fops = &z2_fops; | ||
356 | sprintf(z2ram_gendisk->disk_name, "z2ram"); | ||
357 | strcpy(z2ram_gendisk->devfs_name, z2ram_gendisk->disk_name); | ||
358 | |||
359 | z2ram_gendisk->queue = z2_queue; | ||
360 | add_disk(z2ram_gendisk); | ||
361 | blk_register_region(MKDEV(Z2RAM_MAJOR, 0), Z2MINOR_COUNT, THIS_MODULE, | ||
362 | z2_find, NULL, NULL); | ||
363 | |||
364 | return 0; | ||
365 | |||
366 | out_queue: | ||
367 | put_disk(z2ram_gendisk); | ||
368 | out_disk: | ||
369 | unregister_blkdev(Z2RAM_MAJOR, DEVICE_NAME); | ||
370 | err: | ||
371 | return ret; | ||
372 | } | ||
373 | |||
374 | #if defined(MODULE) | ||
375 | |||
376 | MODULE_LICENSE("GPL"); | ||
377 | |||
378 | int | ||
379 | init_module( void ) | ||
380 | { | ||
381 | int error; | ||
382 | |||
383 | error = z2_init(); | ||
384 | if ( error == 0 ) | ||
385 | { | ||
386 | printk( KERN_INFO DEVICE_NAME ": loaded as module\n" ); | ||
387 | } | ||
388 | |||
389 | return error; | ||
390 | } | ||
391 | |||
392 | void | ||
393 | cleanup_module( void ) | ||
394 | { | ||
395 | int i, j; | ||
396 | blk_unregister_region(MKDEV(Z2RAM_MAJOR, 0), 256); | ||
397 | if ( unregister_blkdev( Z2RAM_MAJOR, DEVICE_NAME ) != 0 ) | ||
398 | printk( KERN_ERR DEVICE_NAME ": unregister of device failed\n"); | ||
399 | |||
400 | del_gendisk(z2ram_gendisk); | ||
401 | put_disk(z2ram_gendisk); | ||
402 | blk_cleanup_queue(z2_queue); | ||
403 | |||
404 | if ( current_device != -1 ) | ||
405 | { | ||
406 | i = 0; | ||
407 | |||
408 | for ( j = 0 ; j < z2_count; j++ ) | ||
409 | { | ||
410 | set_bit( i++, zorro_unused_z2ram ); | ||
411 | } | ||
412 | |||
413 | for ( j = 0 ; j < chip_count; j++ ) | ||
414 | { | ||
415 | if ( z2ram_map[ i ] ) | ||
416 | { | ||
417 | amiga_chip_free( (void *) z2ram_map[ i++ ] ); | ||
418 | } | ||
419 | } | ||
420 | |||
421 | if ( z2ram_map != NULL ) | ||
422 | { | ||
423 | kfree( z2ram_map ); | ||
424 | } | ||
425 | } | ||
426 | |||
427 | return; | ||
428 | } | ||
429 | #endif | ||