• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/drivers/block/
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/smp_lock.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
46extern int m68k_realnum_memory;
47extern 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
60static u_long *z2ram_map    = NULL;
61static u_long z2ram_size    = 0;
62static int z2_count         = 0;
63static int chip_count       = 0;
64static int list_count       = 0;
65static int current_device   = -1;
66
67static DEFINE_SPINLOCK(z2ram_lock);
68
69static struct gendisk *z2ram_gendisk;
70
71static void do_z2_request(struct request_queue *q)
72{
73	struct request *req;
74
75	req = blk_fetch_request(q);
76	while (req) {
77		unsigned long start = blk_rq_pos(req) << 9;
78		unsigned long len  = blk_rq_cur_bytes(req);
79		int err = 0;
80
81		if (start + len > z2ram_size) {
82			printk( KERN_ERR DEVICE_NAME ": bad access: block=%lu, count=%u\n",
83				blk_rq_pos(req), blk_rq_cur_sectors(req));
84			err = -EIO;
85			goto done;
86		}
87		while (len) {
88			unsigned long addr = start & Z2RAM_CHUNKMASK;
89			unsigned long size = Z2RAM_CHUNKSIZE - addr;
90			if (len < size)
91				size = len;
92			addr += z2ram_map[ start >> Z2RAM_CHUNKSHIFT ];
93			if (rq_data_dir(req) == READ)
94				memcpy(req->buffer, (char *)addr, size);
95			else
96				memcpy((char *)addr, req->buffer, size);
97			start += size;
98			len -= size;
99		}
100	done:
101		if (!__blk_end_request_cur(req, err))
102			req = blk_fetch_request(q);
103	}
104}
105
106static void
107get_z2ram( void )
108{
109    int i;
110
111    for ( i = 0; i < Z2RAM_SIZE / Z2RAM_CHUNKSIZE; i++ )
112    {
113	if ( test_bit( i, zorro_unused_z2ram ) )
114	{
115	    z2_count++;
116	    z2ram_map[ z2ram_size++ ] =
117		ZTWO_VADDR( Z2RAM_START ) + ( i << Z2RAM_CHUNKSHIFT );
118	    clear_bit( i, zorro_unused_z2ram );
119	}
120    }
121
122    return;
123}
124
125static void
126get_chipram( void )
127{
128
129    while ( amiga_chip_avail() > ( Z2RAM_CHUNKSIZE * 4 ) )
130    {
131	chip_count++;
132	z2ram_map[ z2ram_size ] =
133	    (u_long)amiga_chip_alloc( Z2RAM_CHUNKSIZE, "z2ram" );
134
135	if ( z2ram_map[ z2ram_size ] == 0 )
136	{
137	    break;
138	}
139
140	z2ram_size++;
141    }
142
143    return;
144}
145
146static int z2_open(struct block_device *bdev, fmode_t mode)
147{
148    int device;
149    int max_z2_map = ( Z2RAM_SIZE / Z2RAM_CHUNKSIZE ) *
150	sizeof( z2ram_map[0] );
151    int max_chip_map = ( amiga_chip_size / Z2RAM_CHUNKSIZE ) *
152	sizeof( z2ram_map[0] );
153    int rc = -ENOMEM;
154
155    device = MINOR(bdev->bd_dev);
156
157    lock_kernel();
158    if ( current_device != -1 && current_device != device )
159    {
160	rc = -EBUSY;
161	goto err_out;
162    }
163
164    if ( current_device == -1 )
165    {
166	z2_count   = 0;
167	chip_count = 0;
168	list_count = 0;
169	z2ram_size = 0;
170
171	/* Use a specific list entry. */
172	if (device >= Z2MINOR_MEMLIST1 && device <= Z2MINOR_MEMLIST4) {
173		int index = device - Z2MINOR_MEMLIST1 + 1;
174		unsigned long size, paddr, vaddr;
175
176		if (index >= m68k_realnum_memory) {
177			printk( KERN_ERR DEVICE_NAME
178				": no such entry in z2ram_map\n" );
179		        goto err_out;
180		}
181
182		paddr = m68k_memory[index].addr;
183		size = m68k_memory[index].size & ~(Z2RAM_CHUNKSIZE-1);
184
185#ifdef __powerpc__
186		{
187			vfree(vmalloc (size));
188		}
189
190		vaddr = (unsigned long) __ioremap (paddr, size,
191						   _PAGE_WRITETHRU);
192
193#else
194		vaddr = (unsigned long)z_remap_nocache_nonser(paddr, size);
195#endif
196		z2ram_map =
197			kmalloc((size/Z2RAM_CHUNKSIZE)*sizeof(z2ram_map[0]),
198				GFP_KERNEL);
199		if ( z2ram_map == NULL )
200		{
201		    printk( KERN_ERR DEVICE_NAME
202			": cannot get mem for z2ram_map\n" );
203		    goto err_out;
204		}
205
206		while (size) {
207			z2ram_map[ z2ram_size++ ] = vaddr;
208			size -= Z2RAM_CHUNKSIZE;
209			vaddr += Z2RAM_CHUNKSIZE;
210			list_count++;
211		}
212
213		if ( z2ram_size != 0 )
214		    printk( KERN_INFO DEVICE_NAME
215			": using %iK List Entry %d Memory\n",
216			list_count * Z2RAM_CHUNK1024, index );
217	} else
218
219	switch ( device )
220	{
221	    case Z2MINOR_COMBINED:
222
223		z2ram_map = kmalloc( max_z2_map + max_chip_map, GFP_KERNEL );
224		if ( z2ram_map == NULL )
225		{
226		    printk( KERN_ERR DEVICE_NAME
227			": cannot get mem for z2ram_map\n" );
228		    goto err_out;
229		}
230
231		get_z2ram();
232		get_chipram();
233
234		if ( z2ram_size != 0 )
235		    printk( KERN_INFO DEVICE_NAME
236			": using %iK Zorro II RAM and %iK Chip RAM (Total %dK)\n",
237			z2_count * Z2RAM_CHUNK1024,
238			chip_count * Z2RAM_CHUNK1024,
239			( z2_count + chip_count ) * Z2RAM_CHUNK1024 );
240
241	    break;
242
243    	    case Z2MINOR_Z2ONLY:
244		z2ram_map = kmalloc( max_z2_map, GFP_KERNEL );
245		if ( z2ram_map == NULL )
246		{
247		    printk( KERN_ERR DEVICE_NAME
248			": cannot get mem for z2ram_map\n" );
249		    goto err_out;
250		}
251
252		get_z2ram();
253
254		if ( z2ram_size != 0 )
255		    printk( KERN_INFO DEVICE_NAME
256			": using %iK of Zorro II RAM\n",
257			z2_count * Z2RAM_CHUNK1024 );
258
259	    break;
260
261	    case Z2MINOR_CHIPONLY:
262		z2ram_map = kmalloc( max_chip_map, GFP_KERNEL );
263		if ( z2ram_map == NULL )
264		{
265		    printk( KERN_ERR DEVICE_NAME
266			": cannot get mem for z2ram_map\n" );
267		    goto err_out;
268		}
269
270		get_chipram();
271
272		if ( z2ram_size != 0 )
273		    printk( KERN_INFO DEVICE_NAME
274			": using %iK Chip RAM\n",
275			chip_count * Z2RAM_CHUNK1024 );
276
277	    break;
278
279	    default:
280		rc = -ENODEV;
281		goto err_out;
282
283	    break;
284	}
285
286	if ( z2ram_size == 0 )
287	{
288	    printk( KERN_NOTICE DEVICE_NAME
289		": no unused ZII/Chip RAM found\n" );
290	    goto err_out_kfree;
291	}
292
293	current_device = device;
294	z2ram_size <<= Z2RAM_CHUNKSHIFT;
295	set_capacity(z2ram_gendisk, z2ram_size >> 9);
296    }
297
298    unlock_kernel();
299    return 0;
300
301err_out_kfree:
302    kfree(z2ram_map);
303err_out:
304    unlock_kernel();
305    return rc;
306}
307
308static int
309z2_release(struct gendisk *disk, fmode_t mode)
310{
311    lock_kernel();
312    if ( current_device == -1 ) {
313    	unlock_kernel();
314    	return 0;
315    }
316    unlock_kernel();
317
318    return 0;
319}
320
321static const struct block_device_operations z2_fops =
322{
323	.owner		= THIS_MODULE,
324	.open		= z2_open,
325	.release	= z2_release,
326};
327
328static struct kobject *z2_find(dev_t dev, int *part, void *data)
329{
330	*part = 0;
331	return get_disk(z2ram_gendisk);
332}
333
334static struct request_queue *z2_queue;
335
336static int __init
337z2_init(void)
338{
339    int ret;
340
341    if (!MACH_IS_AMIGA)
342	return -ENODEV;
343
344    ret = -EBUSY;
345    if (register_blkdev(Z2RAM_MAJOR, DEVICE_NAME))
346	goto err;
347
348    ret = -ENOMEM;
349    z2ram_gendisk = alloc_disk(1);
350    if (!z2ram_gendisk)
351	goto out_disk;
352
353    z2_queue = blk_init_queue(do_z2_request, &z2ram_lock);
354    if (!z2_queue)
355	goto out_queue;
356
357    z2ram_gendisk->major = Z2RAM_MAJOR;
358    z2ram_gendisk->first_minor = 0;
359    z2ram_gendisk->fops = &z2_fops;
360    sprintf(z2ram_gendisk->disk_name, "z2ram");
361
362    z2ram_gendisk->queue = z2_queue;
363    add_disk(z2ram_gendisk);
364    blk_register_region(MKDEV(Z2RAM_MAJOR, 0), Z2MINOR_COUNT, THIS_MODULE,
365				z2_find, NULL, NULL);
366
367    return 0;
368
369out_queue:
370    put_disk(z2ram_gendisk);
371out_disk:
372    unregister_blkdev(Z2RAM_MAJOR, DEVICE_NAME);
373err:
374    return ret;
375}
376
377static void __exit z2_exit(void)
378{
379    int i, j;
380    blk_unregister_region(MKDEV(Z2RAM_MAJOR, 0), Z2MINOR_COUNT);
381    unregister_blkdev(Z2RAM_MAJOR, DEVICE_NAME);
382    del_gendisk(z2ram_gendisk);
383    put_disk(z2ram_gendisk);
384    blk_cleanup_queue(z2_queue);
385
386    if ( current_device != -1 )
387    {
388	i = 0;
389
390	for ( j = 0 ; j < z2_count; j++ )
391	{
392	    set_bit( i++, zorro_unused_z2ram );
393	}
394
395	for ( j = 0 ; j < chip_count; j++ )
396	{
397	    if ( z2ram_map[ i ] )
398	    {
399		amiga_chip_free( (void *) z2ram_map[ i++ ] );
400	    }
401	}
402
403	if ( z2ram_map != NULL )
404	{
405	    kfree( z2ram_map );
406	}
407    }
408
409    return;
410}
411
412module_init(z2_init);
413module_exit(z2_exit);
414MODULE_LICENSE("GPL");
415