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