18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci** z2ram - Amiga pseudo-driver to access 16bit-RAM in ZorroII space
38c2ecf20Sopenharmony_ci**         as a block device, to be used as a RAM disk or swap space
48c2ecf20Sopenharmony_ci**
58c2ecf20Sopenharmony_ci** Copyright (C) 1994 by Ingo Wilken (Ingo.Wilken@informatik.uni-oldenburg.de)
68c2ecf20Sopenharmony_ci**
78c2ecf20Sopenharmony_ci** ++Geert: support for zorro_unused_z2ram, better range checking
88c2ecf20Sopenharmony_ci** ++roman: translate accesses via an array
98c2ecf20Sopenharmony_ci** ++Milan: support for ChipRAM usage
108c2ecf20Sopenharmony_ci** ++yambo: converted to 2.0 kernel
118c2ecf20Sopenharmony_ci** ++yambo: modularized and support added for 3 minor devices including:
128c2ecf20Sopenharmony_ci**          MAJOR  MINOR  DESCRIPTION
138c2ecf20Sopenharmony_ci**          -----  -----  ----------------------------------------------
148c2ecf20Sopenharmony_ci**          37     0       Use Zorro II and Chip ram
158c2ecf20Sopenharmony_ci**          37     1       Use only Zorro II ram
168c2ecf20Sopenharmony_ci**          37     2       Use only Chip ram
178c2ecf20Sopenharmony_ci**          37     4-7     Use memory list entry 1-4 (first is 0)
188c2ecf20Sopenharmony_ci** ++jskov: support for 1-4th memory list entry.
198c2ecf20Sopenharmony_ci**
208c2ecf20Sopenharmony_ci** Permission to use, copy, modify, and distribute this software and its
218c2ecf20Sopenharmony_ci** documentation for any purpose and without fee is hereby granted, provided
228c2ecf20Sopenharmony_ci** that the above copyright notice appear in all copies and that both that
238c2ecf20Sopenharmony_ci** copyright notice and this permission notice appear in supporting
248c2ecf20Sopenharmony_ci** documentation.  This software is provided "as is" without express or
258c2ecf20Sopenharmony_ci** implied warranty.
268c2ecf20Sopenharmony_ci*/
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci#define DEVICE_NAME "Z2RAM"
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci#include <linux/major.h>
318c2ecf20Sopenharmony_ci#include <linux/vmalloc.h>
328c2ecf20Sopenharmony_ci#include <linux/init.h>
338c2ecf20Sopenharmony_ci#include <linux/module.h>
348c2ecf20Sopenharmony_ci#include <linux/blk-mq.h>
358c2ecf20Sopenharmony_ci#include <linux/bitops.h>
368c2ecf20Sopenharmony_ci#include <linux/mutex.h>
378c2ecf20Sopenharmony_ci#include <linux/slab.h>
388c2ecf20Sopenharmony_ci#include <linux/pgtable.h>
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci#include <asm/setup.h>
418c2ecf20Sopenharmony_ci#include <asm/amigahw.h>
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci#include <linux/zorro.h>
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci#define Z2MINOR_COMBINED      (0)
478c2ecf20Sopenharmony_ci#define Z2MINOR_Z2ONLY        (1)
488c2ecf20Sopenharmony_ci#define Z2MINOR_CHIPONLY      (2)
498c2ecf20Sopenharmony_ci#define Z2MINOR_MEMLIST1      (4)
508c2ecf20Sopenharmony_ci#define Z2MINOR_MEMLIST2      (5)
518c2ecf20Sopenharmony_ci#define Z2MINOR_MEMLIST3      (6)
528c2ecf20Sopenharmony_ci#define Z2MINOR_MEMLIST4      (7)
538c2ecf20Sopenharmony_ci#define Z2MINOR_COUNT         (8) /* Move this down when adding a new minor */
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci#define Z2RAM_CHUNK1024       ( Z2RAM_CHUNKSIZE >> 10 )
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(z2ram_mutex);
588c2ecf20Sopenharmony_cistatic u_long *z2ram_map    = NULL;
598c2ecf20Sopenharmony_cistatic u_long z2ram_size    = 0;
608c2ecf20Sopenharmony_cistatic int z2_count         = 0;
618c2ecf20Sopenharmony_cistatic int chip_count       = 0;
628c2ecf20Sopenharmony_cistatic int list_count       = 0;
638c2ecf20Sopenharmony_cistatic int current_device   = -1;
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(z2ram_lock);
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_cistatic struct gendisk *z2ram_gendisk;
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_cistatic blk_status_t z2_queue_rq(struct blk_mq_hw_ctx *hctx,
708c2ecf20Sopenharmony_ci				const struct blk_mq_queue_data *bd)
718c2ecf20Sopenharmony_ci{
728c2ecf20Sopenharmony_ci	struct request *req = bd->rq;
738c2ecf20Sopenharmony_ci	unsigned long start = blk_rq_pos(req) << 9;
748c2ecf20Sopenharmony_ci	unsigned long len  = blk_rq_cur_bytes(req);
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci	blk_mq_start_request(req);
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	if (start + len > z2ram_size) {
798c2ecf20Sopenharmony_ci		pr_err(DEVICE_NAME ": bad access: block=%llu, "
808c2ecf20Sopenharmony_ci		       "count=%u\n",
818c2ecf20Sopenharmony_ci		       (unsigned long long)blk_rq_pos(req),
828c2ecf20Sopenharmony_ci		       blk_rq_cur_sectors(req));
838c2ecf20Sopenharmony_ci		return BLK_STS_IOERR;
848c2ecf20Sopenharmony_ci	}
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	spin_lock_irq(&z2ram_lock);
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	while (len) {
898c2ecf20Sopenharmony_ci		unsigned long addr = start & Z2RAM_CHUNKMASK;
908c2ecf20Sopenharmony_ci		unsigned long size = Z2RAM_CHUNKSIZE - addr;
918c2ecf20Sopenharmony_ci		void *buffer = bio_data(req->bio);
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci		if (len < size)
948c2ecf20Sopenharmony_ci			size = len;
958c2ecf20Sopenharmony_ci		addr += z2ram_map[ start >> Z2RAM_CHUNKSHIFT ];
968c2ecf20Sopenharmony_ci		if (rq_data_dir(req) == READ)
978c2ecf20Sopenharmony_ci			memcpy(buffer, (char *)addr, size);
988c2ecf20Sopenharmony_ci		else
998c2ecf20Sopenharmony_ci			memcpy((char *)addr, buffer, size);
1008c2ecf20Sopenharmony_ci		start += size;
1018c2ecf20Sopenharmony_ci		len -= size;
1028c2ecf20Sopenharmony_ci	}
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci	spin_unlock_irq(&z2ram_lock);
1058c2ecf20Sopenharmony_ci	blk_mq_end_request(req, BLK_STS_OK);
1068c2ecf20Sopenharmony_ci	return BLK_STS_OK;
1078c2ecf20Sopenharmony_ci}
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_cistatic void
1108c2ecf20Sopenharmony_ciget_z2ram( void )
1118c2ecf20Sopenharmony_ci{
1128c2ecf20Sopenharmony_ci    int i;
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci    for ( i = 0; i < Z2RAM_SIZE / Z2RAM_CHUNKSIZE; i++ )
1158c2ecf20Sopenharmony_ci    {
1168c2ecf20Sopenharmony_ci	if ( test_bit( i, zorro_unused_z2ram ) )
1178c2ecf20Sopenharmony_ci	{
1188c2ecf20Sopenharmony_ci	    z2_count++;
1198c2ecf20Sopenharmony_ci	    z2ram_map[z2ram_size++] = (unsigned long)ZTWO_VADDR(Z2RAM_START) +
1208c2ecf20Sopenharmony_ci				      (i << Z2RAM_CHUNKSHIFT);
1218c2ecf20Sopenharmony_ci	    clear_bit( i, zorro_unused_z2ram );
1228c2ecf20Sopenharmony_ci	}
1238c2ecf20Sopenharmony_ci    }
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci    return;
1268c2ecf20Sopenharmony_ci}
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_cistatic void
1298c2ecf20Sopenharmony_ciget_chipram( void )
1308c2ecf20Sopenharmony_ci{
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci    while ( amiga_chip_avail() > ( Z2RAM_CHUNKSIZE * 4 ) )
1338c2ecf20Sopenharmony_ci    {
1348c2ecf20Sopenharmony_ci	chip_count++;
1358c2ecf20Sopenharmony_ci	z2ram_map[ z2ram_size ] =
1368c2ecf20Sopenharmony_ci	    (u_long)amiga_chip_alloc( Z2RAM_CHUNKSIZE, "z2ram" );
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	if ( z2ram_map[ z2ram_size ] == 0 )
1398c2ecf20Sopenharmony_ci	{
1408c2ecf20Sopenharmony_ci	    break;
1418c2ecf20Sopenharmony_ci	}
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci	z2ram_size++;
1448c2ecf20Sopenharmony_ci    }
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci    return;
1478c2ecf20Sopenharmony_ci}
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_cistatic int z2_open(struct block_device *bdev, fmode_t mode)
1508c2ecf20Sopenharmony_ci{
1518c2ecf20Sopenharmony_ci    int device;
1528c2ecf20Sopenharmony_ci    int max_z2_map = ( Z2RAM_SIZE / Z2RAM_CHUNKSIZE ) *
1538c2ecf20Sopenharmony_ci	sizeof( z2ram_map[0] );
1548c2ecf20Sopenharmony_ci    int max_chip_map = ( amiga_chip_size / Z2RAM_CHUNKSIZE ) *
1558c2ecf20Sopenharmony_ci	sizeof( z2ram_map[0] );
1568c2ecf20Sopenharmony_ci    int rc = -ENOMEM;
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci    device = MINOR(bdev->bd_dev);
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci    mutex_lock(&z2ram_mutex);
1618c2ecf20Sopenharmony_ci    if ( current_device != -1 && current_device != device )
1628c2ecf20Sopenharmony_ci    {
1638c2ecf20Sopenharmony_ci	rc = -EBUSY;
1648c2ecf20Sopenharmony_ci	goto err_out;
1658c2ecf20Sopenharmony_ci    }
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci    if ( current_device == -1 )
1688c2ecf20Sopenharmony_ci    {
1698c2ecf20Sopenharmony_ci	z2_count   = 0;
1708c2ecf20Sopenharmony_ci	chip_count = 0;
1718c2ecf20Sopenharmony_ci	list_count = 0;
1728c2ecf20Sopenharmony_ci	z2ram_size = 0;
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci	/* Use a specific list entry. */
1758c2ecf20Sopenharmony_ci	if (device >= Z2MINOR_MEMLIST1 && device <= Z2MINOR_MEMLIST4) {
1768c2ecf20Sopenharmony_ci		int index = device - Z2MINOR_MEMLIST1 + 1;
1778c2ecf20Sopenharmony_ci		unsigned long size, paddr, vaddr;
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci		if (index >= m68k_realnum_memory) {
1808c2ecf20Sopenharmony_ci			printk( KERN_ERR DEVICE_NAME
1818c2ecf20Sopenharmony_ci				": no such entry in z2ram_map\n" );
1828c2ecf20Sopenharmony_ci		        goto err_out;
1838c2ecf20Sopenharmony_ci		}
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci		paddr = m68k_memory[index].addr;
1868c2ecf20Sopenharmony_ci		size = m68k_memory[index].size & ~(Z2RAM_CHUNKSIZE-1);
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci#ifdef __powerpc__
1898c2ecf20Sopenharmony_ci		/* FIXME: ioremap doesn't build correct memory tables. */
1908c2ecf20Sopenharmony_ci		{
1918c2ecf20Sopenharmony_ci			vfree(vmalloc (size));
1928c2ecf20Sopenharmony_ci		}
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci		vaddr = (unsigned long)ioremap_wt(paddr, size);
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci#else
1978c2ecf20Sopenharmony_ci		vaddr = (unsigned long)z_remap_nocache_nonser(paddr, size);
1988c2ecf20Sopenharmony_ci#endif
1998c2ecf20Sopenharmony_ci		z2ram_map =
2008c2ecf20Sopenharmony_ci			kmalloc_array(size / Z2RAM_CHUNKSIZE,
2018c2ecf20Sopenharmony_ci                                      sizeof(z2ram_map[0]),
2028c2ecf20Sopenharmony_ci                                      GFP_KERNEL);
2038c2ecf20Sopenharmony_ci		if ( z2ram_map == NULL )
2048c2ecf20Sopenharmony_ci		{
2058c2ecf20Sopenharmony_ci		    printk( KERN_ERR DEVICE_NAME
2068c2ecf20Sopenharmony_ci			": cannot get mem for z2ram_map\n" );
2078c2ecf20Sopenharmony_ci		    goto err_out;
2088c2ecf20Sopenharmony_ci		}
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci		while (size) {
2118c2ecf20Sopenharmony_ci			z2ram_map[ z2ram_size++ ] = vaddr;
2128c2ecf20Sopenharmony_ci			size -= Z2RAM_CHUNKSIZE;
2138c2ecf20Sopenharmony_ci			vaddr += Z2RAM_CHUNKSIZE;
2148c2ecf20Sopenharmony_ci			list_count++;
2158c2ecf20Sopenharmony_ci		}
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci		if ( z2ram_size != 0 )
2188c2ecf20Sopenharmony_ci		    printk( KERN_INFO DEVICE_NAME
2198c2ecf20Sopenharmony_ci			": using %iK List Entry %d Memory\n",
2208c2ecf20Sopenharmony_ci			list_count * Z2RAM_CHUNK1024, index );
2218c2ecf20Sopenharmony_ci	} else
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci	switch ( device )
2248c2ecf20Sopenharmony_ci	{
2258c2ecf20Sopenharmony_ci	    case Z2MINOR_COMBINED:
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci		z2ram_map = kmalloc( max_z2_map + max_chip_map, GFP_KERNEL );
2288c2ecf20Sopenharmony_ci		if ( z2ram_map == NULL )
2298c2ecf20Sopenharmony_ci		{
2308c2ecf20Sopenharmony_ci		    printk( KERN_ERR DEVICE_NAME
2318c2ecf20Sopenharmony_ci			": cannot get mem for z2ram_map\n" );
2328c2ecf20Sopenharmony_ci		    goto err_out;
2338c2ecf20Sopenharmony_ci		}
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci		get_z2ram();
2368c2ecf20Sopenharmony_ci		get_chipram();
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci		if ( z2ram_size != 0 )
2398c2ecf20Sopenharmony_ci		    printk( KERN_INFO DEVICE_NAME
2408c2ecf20Sopenharmony_ci			": using %iK Zorro II RAM and %iK Chip RAM (Total %dK)\n",
2418c2ecf20Sopenharmony_ci			z2_count * Z2RAM_CHUNK1024,
2428c2ecf20Sopenharmony_ci			chip_count * Z2RAM_CHUNK1024,
2438c2ecf20Sopenharmony_ci			( z2_count + chip_count ) * Z2RAM_CHUNK1024 );
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci	    break;
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci    	    case Z2MINOR_Z2ONLY:
2488c2ecf20Sopenharmony_ci		z2ram_map = kmalloc( max_z2_map, GFP_KERNEL );
2498c2ecf20Sopenharmony_ci		if ( z2ram_map == NULL )
2508c2ecf20Sopenharmony_ci		{
2518c2ecf20Sopenharmony_ci		    printk( KERN_ERR DEVICE_NAME
2528c2ecf20Sopenharmony_ci			": cannot get mem for z2ram_map\n" );
2538c2ecf20Sopenharmony_ci		    goto err_out;
2548c2ecf20Sopenharmony_ci		}
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci		get_z2ram();
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci		if ( z2ram_size != 0 )
2598c2ecf20Sopenharmony_ci		    printk( KERN_INFO DEVICE_NAME
2608c2ecf20Sopenharmony_ci			": using %iK of Zorro II RAM\n",
2618c2ecf20Sopenharmony_ci			z2_count * Z2RAM_CHUNK1024 );
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	    break;
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	    case Z2MINOR_CHIPONLY:
2668c2ecf20Sopenharmony_ci		z2ram_map = kmalloc( max_chip_map, GFP_KERNEL );
2678c2ecf20Sopenharmony_ci		if ( z2ram_map == NULL )
2688c2ecf20Sopenharmony_ci		{
2698c2ecf20Sopenharmony_ci		    printk( KERN_ERR DEVICE_NAME
2708c2ecf20Sopenharmony_ci			": cannot get mem for z2ram_map\n" );
2718c2ecf20Sopenharmony_ci		    goto err_out;
2728c2ecf20Sopenharmony_ci		}
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci		get_chipram();
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci		if ( z2ram_size != 0 )
2778c2ecf20Sopenharmony_ci		    printk( KERN_INFO DEVICE_NAME
2788c2ecf20Sopenharmony_ci			": using %iK Chip RAM\n",
2798c2ecf20Sopenharmony_ci			chip_count * Z2RAM_CHUNK1024 );
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci	    break;
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci	    default:
2848c2ecf20Sopenharmony_ci		rc = -ENODEV;
2858c2ecf20Sopenharmony_ci		goto err_out;
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci	    break;
2888c2ecf20Sopenharmony_ci	}
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci	if ( z2ram_size == 0 )
2918c2ecf20Sopenharmony_ci	{
2928c2ecf20Sopenharmony_ci	    printk( KERN_NOTICE DEVICE_NAME
2938c2ecf20Sopenharmony_ci		": no unused ZII/Chip RAM found\n" );
2948c2ecf20Sopenharmony_ci	    goto err_out_kfree;
2958c2ecf20Sopenharmony_ci	}
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci	current_device = device;
2988c2ecf20Sopenharmony_ci	z2ram_size <<= Z2RAM_CHUNKSHIFT;
2998c2ecf20Sopenharmony_ci	set_capacity(z2ram_gendisk, z2ram_size >> 9);
3008c2ecf20Sopenharmony_ci    }
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci    mutex_unlock(&z2ram_mutex);
3038c2ecf20Sopenharmony_ci    return 0;
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_cierr_out_kfree:
3068c2ecf20Sopenharmony_ci    kfree(z2ram_map);
3078c2ecf20Sopenharmony_cierr_out:
3088c2ecf20Sopenharmony_ci    mutex_unlock(&z2ram_mutex);
3098c2ecf20Sopenharmony_ci    return rc;
3108c2ecf20Sopenharmony_ci}
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_cistatic void
3138c2ecf20Sopenharmony_ciz2_release(struct gendisk *disk, fmode_t mode)
3148c2ecf20Sopenharmony_ci{
3158c2ecf20Sopenharmony_ci    mutex_lock(&z2ram_mutex);
3168c2ecf20Sopenharmony_ci    if ( current_device == -1 ) {
3178c2ecf20Sopenharmony_ci    	mutex_unlock(&z2ram_mutex);
3188c2ecf20Sopenharmony_ci    	return;
3198c2ecf20Sopenharmony_ci    }
3208c2ecf20Sopenharmony_ci    mutex_unlock(&z2ram_mutex);
3218c2ecf20Sopenharmony_ci    /*
3228c2ecf20Sopenharmony_ci     * FIXME: unmap memory
3238c2ecf20Sopenharmony_ci     */
3248c2ecf20Sopenharmony_ci}
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_cistatic const struct block_device_operations z2_fops =
3278c2ecf20Sopenharmony_ci{
3288c2ecf20Sopenharmony_ci	.owner		= THIS_MODULE,
3298c2ecf20Sopenharmony_ci	.open		= z2_open,
3308c2ecf20Sopenharmony_ci	.release	= z2_release,
3318c2ecf20Sopenharmony_ci};
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_cistatic struct kobject *z2_find(dev_t dev, int *part, void *data)
3348c2ecf20Sopenharmony_ci{
3358c2ecf20Sopenharmony_ci	*part = 0;
3368c2ecf20Sopenharmony_ci	return get_disk_and_module(z2ram_gendisk);
3378c2ecf20Sopenharmony_ci}
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_cistatic struct request_queue *z2_queue;
3408c2ecf20Sopenharmony_cistatic struct blk_mq_tag_set tag_set;
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_cistatic const struct blk_mq_ops z2_mq_ops = {
3438c2ecf20Sopenharmony_ci	.queue_rq	= z2_queue_rq,
3448c2ecf20Sopenharmony_ci};
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_cistatic int __init
3478c2ecf20Sopenharmony_ciz2_init(void)
3488c2ecf20Sopenharmony_ci{
3498c2ecf20Sopenharmony_ci    int ret;
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci    if (!MACH_IS_AMIGA)
3528c2ecf20Sopenharmony_ci	return -ENODEV;
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci    ret = -EBUSY;
3558c2ecf20Sopenharmony_ci    if (register_blkdev(Z2RAM_MAJOR, DEVICE_NAME))
3568c2ecf20Sopenharmony_ci	goto err;
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci    ret = -ENOMEM;
3598c2ecf20Sopenharmony_ci    z2ram_gendisk = alloc_disk(1);
3608c2ecf20Sopenharmony_ci    if (!z2ram_gendisk)
3618c2ecf20Sopenharmony_ci	goto out_disk;
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci    z2_queue = blk_mq_init_sq_queue(&tag_set, &z2_mq_ops, 16,
3648c2ecf20Sopenharmony_ci					BLK_MQ_F_SHOULD_MERGE);
3658c2ecf20Sopenharmony_ci    if (IS_ERR(z2_queue)) {
3668c2ecf20Sopenharmony_ci	ret = PTR_ERR(z2_queue);
3678c2ecf20Sopenharmony_ci	z2_queue = NULL;
3688c2ecf20Sopenharmony_ci	goto out_queue;
3698c2ecf20Sopenharmony_ci    }
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_ci    z2ram_gendisk->major = Z2RAM_MAJOR;
3728c2ecf20Sopenharmony_ci    z2ram_gendisk->first_minor = 0;
3738c2ecf20Sopenharmony_ci    z2ram_gendisk->fops = &z2_fops;
3748c2ecf20Sopenharmony_ci    sprintf(z2ram_gendisk->disk_name, "z2ram");
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ci    z2ram_gendisk->queue = z2_queue;
3778c2ecf20Sopenharmony_ci    add_disk(z2ram_gendisk);
3788c2ecf20Sopenharmony_ci    blk_register_region(MKDEV(Z2RAM_MAJOR, 0), Z2MINOR_COUNT, THIS_MODULE,
3798c2ecf20Sopenharmony_ci				z2_find, NULL, NULL);
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci    return 0;
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ciout_queue:
3848c2ecf20Sopenharmony_ci    put_disk(z2ram_gendisk);
3858c2ecf20Sopenharmony_ciout_disk:
3868c2ecf20Sopenharmony_ci    unregister_blkdev(Z2RAM_MAJOR, DEVICE_NAME);
3878c2ecf20Sopenharmony_cierr:
3888c2ecf20Sopenharmony_ci    return ret;
3898c2ecf20Sopenharmony_ci}
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_cistatic void __exit z2_exit(void)
3928c2ecf20Sopenharmony_ci{
3938c2ecf20Sopenharmony_ci    int i, j;
3948c2ecf20Sopenharmony_ci    blk_unregister_region(MKDEV(Z2RAM_MAJOR, 0), Z2MINOR_COUNT);
3958c2ecf20Sopenharmony_ci    unregister_blkdev(Z2RAM_MAJOR, DEVICE_NAME);
3968c2ecf20Sopenharmony_ci    del_gendisk(z2ram_gendisk);
3978c2ecf20Sopenharmony_ci    put_disk(z2ram_gendisk);
3988c2ecf20Sopenharmony_ci    blk_cleanup_queue(z2_queue);
3998c2ecf20Sopenharmony_ci    blk_mq_free_tag_set(&tag_set);
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ci    if ( current_device != -1 )
4028c2ecf20Sopenharmony_ci    {
4038c2ecf20Sopenharmony_ci	i = 0;
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci	for ( j = 0 ; j < z2_count; j++ )
4068c2ecf20Sopenharmony_ci	{
4078c2ecf20Sopenharmony_ci	    set_bit( i++, zorro_unused_z2ram );
4088c2ecf20Sopenharmony_ci	}
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_ci	for ( j = 0 ; j < chip_count; j++ )
4118c2ecf20Sopenharmony_ci	{
4128c2ecf20Sopenharmony_ci	    if ( z2ram_map[ i ] )
4138c2ecf20Sopenharmony_ci	    {
4148c2ecf20Sopenharmony_ci		amiga_chip_free( (void *) z2ram_map[ i++ ] );
4158c2ecf20Sopenharmony_ci	    }
4168c2ecf20Sopenharmony_ci	}
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci	if ( z2ram_map != NULL )
4198c2ecf20Sopenharmony_ci	{
4208c2ecf20Sopenharmony_ci	    kfree( z2ram_map );
4218c2ecf20Sopenharmony_ci	}
4228c2ecf20Sopenharmony_ci    }
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci    return;
4258c2ecf20Sopenharmony_ci}
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_cimodule_init(z2_init);
4288c2ecf20Sopenharmony_cimodule_exit(z2_exit);
4298c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
430