Root/
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 | #include <linux/mutex.h> |
37 | #include <linux/slab.h> |
38 | |
39 | #include <asm/setup.h> |
40 | #include <asm/amigahw.h> |
41 | #include <asm/pgtable.h> |
42 | |
43 | #include <linux/zorro.h> |
44 | |
45 | |
46 | extern int m68k_realnum_memory; |
47 | extern struct mem_info m68k_memory[NUM_MEMINFO]; |
48 | |
49 | #define Z2MINOR_COMBINED (0) |
50 | #define Z2MINOR_Z2ONLY (1) |
51 | #define Z2MINOR_CHIPONLY (2) |
52 | #define Z2MINOR_MEMLIST1 (4) |
53 | #define Z2MINOR_MEMLIST2 (5) |
54 | #define Z2MINOR_MEMLIST3 (6) |
55 | #define Z2MINOR_MEMLIST4 (7) |
56 | #define Z2MINOR_COUNT (8) /* Move this down when adding a new minor */ |
57 | |
58 | #define Z2RAM_CHUNK1024 ( Z2RAM_CHUNKSIZE >> 10 ) |
59 | |
60 | static DEFINE_MUTEX(z2ram_mutex); |
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 gendisk *z2ram_gendisk; |
71 | |
72 | static void do_z2_request(struct request_queue *q) |
73 | { |
74 | struct request *req; |
75 | |
76 | req = blk_fetch_request(q); |
77 | while (req) { |
78 | unsigned long start = blk_rq_pos(req) << 9; |
79 | unsigned long len = blk_rq_cur_bytes(req); |
80 | int err = 0; |
81 | |
82 | if (start + len > z2ram_size) { |
83 | pr_err(DEVICE_NAME ": bad access: block=%llu, " |
84 | "count=%u\n", |
85 | (unsigned long long)blk_rq_pos(req), |
86 | blk_rq_cur_sectors(req)); |
87 | err = -EIO; |
88 | goto done; |
89 | } |
90 | while (len) { |
91 | unsigned long addr = start & Z2RAM_CHUNKMASK; |
92 | unsigned long size = Z2RAM_CHUNKSIZE - addr; |
93 | if (len < size) |
94 | size = len; |
95 | addr += z2ram_map[ start >> Z2RAM_CHUNKSHIFT ]; |
96 | if (rq_data_dir(req) == READ) |
97 | memcpy(req->buffer, (char *)addr, size); |
98 | else |
99 | memcpy((char *)addr, req->buffer, size); |
100 | start += size; |
101 | len -= size; |
102 | } |
103 | done: |
104 | if (!__blk_end_request_cur(req, err)) |
105 | req = blk_fetch_request(q); |
106 | } |
107 | } |
108 | |
109 | static void |
110 | get_z2ram( void ) |
111 | { |
112 | int i; |
113 | |
114 | for ( i = 0; i < Z2RAM_SIZE / Z2RAM_CHUNKSIZE; i++ ) |
115 | { |
116 | if ( test_bit( i, zorro_unused_z2ram ) ) |
117 | { |
118 | z2_count++; |
119 | z2ram_map[ z2ram_size++ ] = |
120 | ZTWO_VADDR( Z2RAM_START ) + ( i << Z2RAM_CHUNKSHIFT ); |
121 | clear_bit( i, zorro_unused_z2ram ); |
122 | } |
123 | } |
124 | |
125 | return; |
126 | } |
127 | |
128 | static void |
129 | get_chipram( void ) |
130 | { |
131 | |
132 | while ( amiga_chip_avail() > ( Z2RAM_CHUNKSIZE * 4 ) ) |
133 | { |
134 | chip_count++; |
135 | z2ram_map[ z2ram_size ] = |
136 | (u_long)amiga_chip_alloc( Z2RAM_CHUNKSIZE, "z2ram" ); |
137 | |
138 | if ( z2ram_map[ z2ram_size ] == 0 ) |
139 | { |
140 | break; |
141 | } |
142 | |
143 | z2ram_size++; |
144 | } |
145 | |
146 | return; |
147 | } |
148 | |
149 | static int z2_open(struct block_device *bdev, fmode_t mode) |
150 | { |
151 | int device; |
152 | int max_z2_map = ( Z2RAM_SIZE / Z2RAM_CHUNKSIZE ) * |
153 | sizeof( z2ram_map[0] ); |
154 | int max_chip_map = ( amiga_chip_size / Z2RAM_CHUNKSIZE ) * |
155 | sizeof( z2ram_map[0] ); |
156 | int rc = -ENOMEM; |
157 | |
158 | device = MINOR(bdev->bd_dev); |
159 | |
160 | mutex_lock(&z2ram_mutex); |
161 | if ( current_device != -1 && current_device != device ) |
162 | { |
163 | rc = -EBUSY; |
164 | goto err_out; |
165 | } |
166 | |
167 | if ( current_device == -1 ) |
168 | { |
169 | z2_count = 0; |
170 | chip_count = 0; |
171 | list_count = 0; |
172 | z2ram_size = 0; |
173 | |
174 | /* Use a specific list entry. */ |
175 | if (device >= Z2MINOR_MEMLIST1 && device <= Z2MINOR_MEMLIST4) { |
176 | int index = device - Z2MINOR_MEMLIST1 + 1; |
177 | unsigned long size, paddr, vaddr; |
178 | |
179 | if (index >= m68k_realnum_memory) { |
180 | printk( KERN_ERR DEVICE_NAME |
181 | ": no such entry in z2ram_map\n" ); |
182 | goto err_out; |
183 | } |
184 | |
185 | paddr = m68k_memory[index].addr; |
186 | size = m68k_memory[index].size & ~(Z2RAM_CHUNKSIZE-1); |
187 | |
188 | #ifdef __powerpc__ |
189 | /* FIXME: ioremap doesn't build correct memory tables. */ |
190 | { |
191 | vfree(vmalloc (size)); |
192 | } |
193 | |
194 | vaddr = (unsigned long) __ioremap (paddr, size, |
195 | _PAGE_WRITETHRU); |
196 | |
197 | #else |
198 | vaddr = (unsigned long)z_remap_nocache_nonser(paddr, size); |
199 | #endif |
200 | z2ram_map = |
201 | kmalloc((size/Z2RAM_CHUNKSIZE)*sizeof(z2ram_map[0]), |
202 | GFP_KERNEL); |
203 | if ( z2ram_map == NULL ) |
204 | { |
205 | printk( KERN_ERR DEVICE_NAME |
206 | ": cannot get mem for z2ram_map\n" ); |
207 | goto err_out; |
208 | } |
209 | |
210 | while (size) { |
211 | z2ram_map[ z2ram_size++ ] = vaddr; |
212 | size -= Z2RAM_CHUNKSIZE; |
213 | vaddr += Z2RAM_CHUNKSIZE; |
214 | list_count++; |
215 | } |
216 | |
217 | if ( z2ram_size != 0 ) |
218 | printk( KERN_INFO DEVICE_NAME |
219 | ": using %iK List Entry %d Memory\n", |
220 | list_count * Z2RAM_CHUNK1024, index ); |
221 | } else |
222 | |
223 | switch ( device ) |
224 | { |
225 | case Z2MINOR_COMBINED: |
226 | |
227 | z2ram_map = kmalloc( max_z2_map + max_chip_map, GFP_KERNEL ); |
228 | if ( z2ram_map == NULL ) |
229 | { |
230 | printk( KERN_ERR DEVICE_NAME |
231 | ": cannot get mem for z2ram_map\n" ); |
232 | goto err_out; |
233 | } |
234 | |
235 | get_z2ram(); |
236 | get_chipram(); |
237 | |
238 | if ( z2ram_size != 0 ) |
239 | printk( KERN_INFO DEVICE_NAME |
240 | ": using %iK Zorro II RAM and %iK Chip RAM (Total %dK)\n", |
241 | z2_count * Z2RAM_CHUNK1024, |
242 | chip_count * Z2RAM_CHUNK1024, |
243 | ( z2_count + chip_count ) * Z2RAM_CHUNK1024 ); |
244 | |
245 | break; |
246 | |
247 | case Z2MINOR_Z2ONLY: |
248 | z2ram_map = kmalloc( max_z2_map, GFP_KERNEL ); |
249 | if ( z2ram_map == NULL ) |
250 | { |
251 | printk( KERN_ERR DEVICE_NAME |
252 | ": cannot get mem for z2ram_map\n" ); |
253 | goto err_out; |
254 | } |
255 | |
256 | get_z2ram(); |
257 | |
258 | if ( z2ram_size != 0 ) |
259 | printk( KERN_INFO DEVICE_NAME |
260 | ": using %iK of Zorro II RAM\n", |
261 | z2_count * Z2RAM_CHUNK1024 ); |
262 | |
263 | break; |
264 | |
265 | case Z2MINOR_CHIPONLY: |
266 | z2ram_map = kmalloc( max_chip_map, GFP_KERNEL ); |
267 | if ( z2ram_map == NULL ) |
268 | { |
269 | printk( KERN_ERR DEVICE_NAME |
270 | ": cannot get mem for z2ram_map\n" ); |
271 | goto err_out; |
272 | } |
273 | |
274 | get_chipram(); |
275 | |
276 | if ( z2ram_size != 0 ) |
277 | printk( KERN_INFO DEVICE_NAME |
278 | ": using %iK Chip RAM\n", |
279 | chip_count * Z2RAM_CHUNK1024 ); |
280 | |
281 | break; |
282 | |
283 | default: |
284 | rc = -ENODEV; |
285 | goto err_out; |
286 | |
287 | break; |
288 | } |
289 | |
290 | if ( z2ram_size == 0 ) |
291 | { |
292 | printk( KERN_NOTICE DEVICE_NAME |
293 | ": no unused ZII/Chip RAM found\n" ); |
294 | goto err_out_kfree; |
295 | } |
296 | |
297 | current_device = device; |
298 | z2ram_size <<= Z2RAM_CHUNKSHIFT; |
299 | set_capacity(z2ram_gendisk, z2ram_size >> 9); |
300 | } |
301 | |
302 | mutex_unlock(&z2ram_mutex); |
303 | return 0; |
304 | |
305 | err_out_kfree: |
306 | kfree(z2ram_map); |
307 | err_out: |
308 | mutex_unlock(&z2ram_mutex); |
309 | return rc; |
310 | } |
311 | |
312 | static int |
313 | z2_release(struct gendisk *disk, fmode_t mode) |
314 | { |
315 | mutex_lock(&z2ram_mutex); |
316 | if ( current_device == -1 ) { |
317 | mutex_unlock(&z2ram_mutex); |
318 | return 0; |
319 | } |
320 | mutex_unlock(&z2ram_mutex); |
321 | /* |
322 | * FIXME: unmap memory |
323 | */ |
324 | |
325 | return 0; |
326 | } |
327 | |
328 | static const struct block_device_operations z2_fops = |
329 | { |
330 | .owner = THIS_MODULE, |
331 | .open = z2_open, |
332 | .release = z2_release, |
333 | }; |
334 | |
335 | static struct kobject *z2_find(dev_t dev, int *part, void *data) |
336 | { |
337 | *part = 0; |
338 | return get_disk(z2ram_gendisk); |
339 | } |
340 | |
341 | static struct request_queue *z2_queue; |
342 | |
343 | static int __init |
344 | z2_init(void) |
345 | { |
346 | int ret; |
347 | |
348 | if (!MACH_IS_AMIGA) |
349 | return -ENODEV; |
350 | |
351 | ret = -EBUSY; |
352 | if (register_blkdev(Z2RAM_MAJOR, DEVICE_NAME)) |
353 | goto err; |
354 | |
355 | ret = -ENOMEM; |
356 | z2ram_gendisk = alloc_disk(1); |
357 | if (!z2ram_gendisk) |
358 | goto out_disk; |
359 | |
360 | z2_queue = blk_init_queue(do_z2_request, &z2ram_lock); |
361 | if (!z2_queue) |
362 | goto out_queue; |
363 | |
364 | z2ram_gendisk->major = Z2RAM_MAJOR; |
365 | z2ram_gendisk->first_minor = 0; |
366 | z2ram_gendisk->fops = &z2_fops; |
367 | sprintf(z2ram_gendisk->disk_name, "z2ram"); |
368 | |
369 | z2ram_gendisk->queue = z2_queue; |
370 | add_disk(z2ram_gendisk); |
371 | blk_register_region(MKDEV(Z2RAM_MAJOR, 0), Z2MINOR_COUNT, THIS_MODULE, |
372 | z2_find, NULL, NULL); |
373 | |
374 | return 0; |
375 | |
376 | out_queue: |
377 | put_disk(z2ram_gendisk); |
378 | out_disk: |
379 | unregister_blkdev(Z2RAM_MAJOR, DEVICE_NAME); |
380 | err: |
381 | return ret; |
382 | } |
383 | |
384 | static void __exit z2_exit(void) |
385 | { |
386 | int i, j; |
387 | blk_unregister_region(MKDEV(Z2RAM_MAJOR, 0), Z2MINOR_COUNT); |
388 | unregister_blkdev(Z2RAM_MAJOR, DEVICE_NAME); |
389 | del_gendisk(z2ram_gendisk); |
390 | put_disk(z2ram_gendisk); |
391 | blk_cleanup_queue(z2_queue); |
392 | |
393 | if ( current_device != -1 ) |
394 | { |
395 | i = 0; |
396 | |
397 | for ( j = 0 ; j < z2_count; j++ ) |
398 | { |
399 | set_bit( i++, zorro_unused_z2ram ); |
400 | } |
401 | |
402 | for ( j = 0 ; j < chip_count; j++ ) |
403 | { |
404 | if ( z2ram_map[ i ] ) |
405 | { |
406 | amiga_chip_free( (void *) z2ram_map[ i++ ] ); |
407 | } |
408 | } |
409 | |
410 | if ( z2ram_map != NULL ) |
411 | { |
412 | kfree( z2ram_map ); |
413 | } |
414 | } |
415 | |
416 | return; |
417 | } |
418 | |
419 | module_init(z2_init); |
420 | module_exit(z2_exit); |
421 | MODULE_LICENSE("GPL"); |
422 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9