| .. | .. | 
|---|
| 7 | 7 | * (at your option) any later version. | 
|---|
| 8 | 8 | */ | 
|---|
| 9 | 9 |  | 
|---|
|  | 10 | +#define pr_fmt(fmt) "rk_nand: " fmt | 
|---|
|  | 11 | + | 
|---|
| 10 | 12 | #include <linux/kernel.h> | 
|---|
| 11 | 13 | #include <linux/slab.h> | 
|---|
| 12 | 14 | #include <linux/module.h> | 
|---|
| 13 | 15 | #include <linux/list.h> | 
|---|
| 14 | 16 | #include <linux/fs.h> | 
|---|
| 15 | 17 | #include <linux/blkdev.h> | 
|---|
|  | 18 | +#include <linux/blk-mq.h> | 
|---|
| 16 | 19 | #include <linux/blkpg.h> | 
|---|
| 17 | 20 | #include <linux/spinlock.h> | 
|---|
| 18 | 21 | #include <linux/hdreg.h> | 
|---|
| .. | .. | 
|---|
| 36 | 39 | #include "rk_nand_blk.h" | 
|---|
| 37 | 40 | #include "rk_ftl_api.h" | 
|---|
| 38 | 41 |  | 
|---|
| 39 |  | -static struct nand_part disk_array[MAX_PART_COUNT]; | 
|---|
| 40 |  | -static int g_max_part_num = 4; | 
|---|
| 41 |  | - | 
|---|
| 42 | 42 | #define PART_READONLY 0x85 | 
|---|
| 43 | 43 | #define PART_WRITEONLY 0x86 | 
|---|
| 44 | 44 | #define PART_NO_ACCESS 0x87 | 
|---|
| .. | .. | 
|---|
| 48 | 48 | static unsigned long totle_read_count; | 
|---|
| 49 | 49 | static unsigned long totle_write_count; | 
|---|
| 50 | 50 | static int rk_nand_dev_initialised; | 
|---|
|  | 51 | +static unsigned long rk_ftl_gc_do; | 
|---|
|  | 52 | +static DECLARE_WAIT_QUEUE_HEAD(rknand_thread_wait); | 
|---|
|  | 53 | +static unsigned long rk_ftl_gc_jiffies; | 
|---|
| 51 | 54 |  | 
|---|
| 52 | 55 | static char *mtd_read_temp_buffer; | 
|---|
| 53 | 56 | #define MTD_RW_SECTORS (512) | 
|---|
| 54 | 57 |  | 
|---|
|  | 58 | +#define DISABLE_WRITE _IO('V', 0) | 
|---|
|  | 59 | +#define ENABLE_WRITE _IO('V', 1) | 
|---|
|  | 60 | +#define DISABLE_READ _IO('V', 2) | 
|---|
|  | 61 | +#define ENABLE_READ _IO('V', 3) | 
|---|
| 55 | 62 | static int rknand_proc_show(struct seq_file *m, void *v) | 
|---|
| 56 | 63 | { | 
|---|
| 57 | 64 | m->count = rknand_proc_ftlread(m->buf); | 
|---|
| .. | .. | 
|---|
| 62 | 69 | return 0; | 
|---|
| 63 | 70 | } | 
|---|
| 64 | 71 |  | 
|---|
| 65 |  | -static int rknand_mtd_proc_show(struct seq_file *m, void *v) | 
|---|
| 66 |  | -{ | 
|---|
| 67 |  | -	int i; | 
|---|
| 68 |  | - | 
|---|
| 69 |  | -	seq_printf(m, "%s", "dev:    size   erasesize  name\n"); | 
|---|
| 70 |  | -	for (i = 0; i < g_max_part_num; i++) { | 
|---|
| 71 |  | -		seq_printf(m, "rknand%d: %8.8llx %8.8x \"%s\"\n", i, | 
|---|
| 72 |  | -			   (unsigned long long)disk_array[i].size * 512, | 
|---|
| 73 |  | -			   32 * 0x200, disk_array[i].name); | 
|---|
| 74 |  | -	} | 
|---|
| 75 |  | -	return 0; | 
|---|
| 76 |  | -} | 
|---|
| 77 |  | - | 
|---|
| 78 | 72 | static int rknand_proc_open(struct inode *inode, struct file *file) | 
|---|
| 79 | 73 | { | 
|---|
| 80 | 74 | return single_open(file, rknand_proc_show, PDE_DATA(inode)); | 
|---|
| 81 | 75 | } | 
|---|
| 82 | 76 |  | 
|---|
| 83 |  | -static int rknand_mtd_proc_open(struct inode *inode, struct file *file) | 
|---|
| 84 |  | -{ | 
|---|
| 85 |  | -	return single_open(file, rknand_mtd_proc_show, PDE_DATA(inode)); | 
|---|
| 86 |  | -} | 
|---|
| 87 |  | - | 
|---|
| 88 |  | -static const struct file_operations rknand_proc_fops = { | 
|---|
| 89 |  | -	.owner		= THIS_MODULE, | 
|---|
| 90 |  | -	.open		= rknand_proc_open, | 
|---|
| 91 |  | -	.read		= seq_read, | 
|---|
| 92 |  | -	.llseek		= seq_lseek, | 
|---|
| 93 |  | -	.release	= single_release, | 
|---|
| 94 |  | -}; | 
|---|
| 95 |  | - | 
|---|
| 96 |  | -static const struct file_operations rknand_mtd_proc_fops = { | 
|---|
| 97 |  | -	.owner		= THIS_MODULE, | 
|---|
| 98 |  | -	.open		= rknand_mtd_proc_open, | 
|---|
| 99 |  | -	.read		= seq_read, | 
|---|
| 100 |  | -	.llseek		= seq_lseek, | 
|---|
| 101 |  | -	.release	= single_release, | 
|---|
|  | 77 | +static const struct proc_ops rknand_proc_fops = { | 
|---|
|  | 78 | +	.proc_open	= rknand_proc_open, | 
|---|
|  | 79 | +	.proc_read	= seq_read, | 
|---|
|  | 80 | +	.proc_lseek	= seq_lseek, | 
|---|
|  | 81 | +	.proc_release	= single_release, | 
|---|
| 102 | 82 | }; | 
|---|
| 103 | 83 |  | 
|---|
| 104 | 84 | static int rknand_create_procfs(void) | 
|---|
| .. | .. | 
|---|
| 110 | 90 | if (!ent) | 
|---|
| 111 | 91 | return -1; | 
|---|
| 112 | 92 |  | 
|---|
| 113 |  | -	ent = proc_create_data("mtd", 0444, NULL, &rknand_mtd_proc_fops, | 
|---|
| 114 |  | -			       (void *)0); | 
|---|
| 115 |  | -	if (!ent) | 
|---|
| 116 |  | -		return -1; | 
|---|
| 117 | 93 | return 0; | 
|---|
| 118 | 94 | } | 
|---|
| 119 | 95 |  | 
|---|
| .. | .. | 
|---|
| 143 | 119 | unsigned long start, | 
|---|
| 144 | 120 | unsigned long nsector, | 
|---|
| 145 | 121 | char *buf, | 
|---|
| 146 |  | -			     int cmd, | 
|---|
| 147 |  | -			     int totle_nsec) | 
|---|
|  | 122 | +			     int cmd) | 
|---|
| 148 | 123 | { | 
|---|
| 149 | 124 | int ret; | 
|---|
| 150 | 125 |  | 
|---|
| .. | .. | 
|---|
| 155 | 130 | } | 
|---|
| 156 | 131 |  | 
|---|
| 157 | 132 | start += dev->off_size; | 
|---|
| 158 |  | -	rknand_device_lock(); | 
|---|
| 159 | 133 |  | 
|---|
| 160 | 134 | switch (cmd) { | 
|---|
| 161 | 135 | case READ: | 
|---|
| .. | .. | 
|---|
| 179 | 153 | break; | 
|---|
| 180 | 154 | } | 
|---|
| 181 | 155 |  | 
|---|
| 182 |  | -	rknand_device_unlock(); | 
|---|
| 183 | 156 | return ret; | 
|---|
| 184 |  | -} | 
|---|
| 185 |  | - | 
|---|
| 186 |  | -static DECLARE_WAIT_QUEUE_HEAD(rknand_thread_wait); | 
|---|
| 187 |  | -static void rk_ftl_gc_timeout_hack(struct timer_list *unused); | 
|---|
| 188 |  | -static DEFINE_TIMER(rk_ftl_gc_timeout, rk_ftl_gc_timeout_hack); | 
|---|
| 189 |  | -static unsigned long rk_ftl_gc_jiffies; | 
|---|
| 190 |  | -static unsigned long rk_ftl_gc_do; | 
|---|
| 191 |  | - | 
|---|
| 192 |  | -static void rk_ftl_gc_timeout_hack(struct timer_list *unused) | 
|---|
| 193 |  | -{ | 
|---|
| 194 |  | -	del_timer(&rk_ftl_gc_timeout); | 
|---|
| 195 |  | -	rk_ftl_gc_do++; | 
|---|
| 196 |  | -	rk_ftl_gc_timeout.expires = jiffies + rk_ftl_gc_jiffies * rk_ftl_gc_do; | 
|---|
| 197 |  | -	add_timer(&rk_ftl_gc_timeout); | 
|---|
| 198 | 157 | } | 
|---|
| 199 | 158 |  | 
|---|
| 200 | 159 | static int req_check_buffer_align(struct request *req, char **pbuf) | 
|---|
| .. | .. | 
|---|
| 225 | 184 | return 1; | 
|---|
| 226 | 185 | } | 
|---|
| 227 | 186 |  | 
|---|
| 228 |  | -static int nand_blktrans_thread(void *arg) | 
|---|
|  | 187 | +static blk_status_t do_blktrans_all_request(struct nand_blk_dev *dev, | 
|---|
|  | 188 | +					    struct request *req) | 
|---|
| 229 | 189 | { | 
|---|
| 230 |  | -	struct nand_blk_ops *nandr = arg; | 
|---|
| 231 |  | -	struct request_queue *rq = nandr->rq; | 
|---|
| 232 |  | -	struct request *req = NULL; | 
|---|
| 233 |  | -	int ftl_gc_status = 0; | 
|---|
| 234 |  | -	char *buf, *page_buf; | 
|---|
|  | 190 | +	unsigned long block, nsect; | 
|---|
|  | 191 | +	char *buf = NULL, *page_buf; | 
|---|
| 235 | 192 | struct req_iterator rq_iter; | 
|---|
| 236 | 193 | struct bio_vec bvec; | 
|---|
| 237 |  | -	unsigned long long sector_index = ULLONG_MAX; | 
|---|
|  | 194 | +	int ret = BLK_STS_IOERR; | 
|---|
| 238 | 195 | unsigned long totle_nsect; | 
|---|
| 239 |  | -	int rw_flag = 0; | 
|---|
| 240 |  | -	int req_empty_times = 0; | 
|---|
| 241 |  | -	int op; | 
|---|
| 242 | 196 |  | 
|---|
| 243 |  | -	spin_lock_irq(rq->queue_lock); | 
|---|
| 244 |  | -	rk_ftl_gc_jiffies = HZ / 10; /* do garbage collect after 100ms */ | 
|---|
|  | 197 | +	block = blk_rq_pos(req); | 
|---|
|  | 198 | +	nsect = blk_rq_cur_bytes(req) >> 9; | 
|---|
|  | 199 | +	totle_nsect = (req->__data_len) >> 9; | 
|---|
|  | 200 | + | 
|---|
|  | 201 | +	if (blk_rq_pos(req) + blk_rq_cur_sectors(req) > get_capacity(req->rq_disk)) | 
|---|
|  | 202 | +		return BLK_STS_IOERR; | 
|---|
|  | 203 | + | 
|---|
|  | 204 | +	switch (req_op(req)) { | 
|---|
|  | 205 | +	case REQ_OP_DISCARD: | 
|---|
|  | 206 | +		if (FtlDiscard(block, nsect)) | 
|---|
|  | 207 | +			return BLK_STS_IOERR; | 
|---|
|  | 208 | +		return BLK_STS_OK; | 
|---|
|  | 209 | +	case REQ_OP_READ: | 
|---|
|  | 210 | +		buf = mtd_read_temp_buffer; | 
|---|
|  | 211 | +		req_check_buffer_align(req, &buf); | 
|---|
|  | 212 | +		ret = nand_dev_transfer(dev, block, totle_nsect, buf, REQ_OP_READ); | 
|---|
|  | 213 | +		if (buf == mtd_read_temp_buffer) { | 
|---|
|  | 214 | +			char *p = buf; | 
|---|
|  | 215 | + | 
|---|
|  | 216 | +			rq_for_each_segment(bvec, req, rq_iter) { | 
|---|
|  | 217 | +				page_buf = kmap_atomic(bvec.bv_page); | 
|---|
|  | 218 | + | 
|---|
|  | 219 | +				memcpy(page_buf + bvec.bv_offset, p, bvec.bv_len); | 
|---|
|  | 220 | +				p += bvec.bv_len; | 
|---|
|  | 221 | +				kunmap_atomic(page_buf); | 
|---|
|  | 222 | +			} | 
|---|
|  | 223 | +		} | 
|---|
|  | 224 | + | 
|---|
|  | 225 | +		if (ret) | 
|---|
|  | 226 | +			return BLK_STS_IOERR; | 
|---|
|  | 227 | +		else | 
|---|
|  | 228 | +			return BLK_STS_OK; | 
|---|
|  | 229 | +	case REQ_OP_WRITE: | 
|---|
|  | 230 | +		buf = mtd_read_temp_buffer; | 
|---|
|  | 231 | +		req_check_buffer_align(req, &buf); | 
|---|
|  | 232 | + | 
|---|
|  | 233 | +		if (buf == mtd_read_temp_buffer) { | 
|---|
|  | 234 | +			char *p = buf; | 
|---|
|  | 235 | + | 
|---|
|  | 236 | +			rq_for_each_segment(bvec, req, rq_iter) { | 
|---|
|  | 237 | +				page_buf = kmap_atomic(bvec.bv_page); | 
|---|
|  | 238 | +				memcpy(p, page_buf + bvec.bv_offset, bvec.bv_len); | 
|---|
|  | 239 | +				p += bvec.bv_len; | 
|---|
|  | 240 | +				kunmap_atomic(page_buf); | 
|---|
|  | 241 | +			} | 
|---|
|  | 242 | +		} | 
|---|
|  | 243 | + | 
|---|
|  | 244 | +		ret = nand_dev_transfer(dev, block, totle_nsect, buf, REQ_OP_WRITE); | 
|---|
|  | 245 | + | 
|---|
|  | 246 | +		if (ret) | 
|---|
|  | 247 | +			return BLK_STS_IOERR; | 
|---|
|  | 248 | +		else | 
|---|
|  | 249 | +			return BLK_STS_OK; | 
|---|
|  | 250 | + | 
|---|
|  | 251 | +	default: | 
|---|
|  | 252 | +		return BLK_STS_IOERR; | 
|---|
|  | 253 | +	} | 
|---|
|  | 254 | +} | 
|---|
|  | 255 | + | 
|---|
|  | 256 | +static struct request *rk_nand_next_request(struct nand_blk_dev *dev) | 
|---|
|  | 257 | +{ | 
|---|
|  | 258 | +	struct nand_blk_ops *nand_ops = dev->nand_ops; | 
|---|
|  | 259 | +	struct request *rq; | 
|---|
|  | 260 | + | 
|---|
|  | 261 | +	rq = list_first_entry_or_null(&nand_ops->rq_list, struct request, queuelist); | 
|---|
|  | 262 | +	if (rq) { | 
|---|
|  | 263 | +		list_del_init(&rq->queuelist); | 
|---|
|  | 264 | +		blk_mq_start_request(rq); | 
|---|
|  | 265 | +		return rq; | 
|---|
|  | 266 | +	} | 
|---|
|  | 267 | + | 
|---|
|  | 268 | +	return NULL; | 
|---|
|  | 269 | +} | 
|---|
|  | 270 | + | 
|---|
|  | 271 | +static void rk_nand_blktrans_work(struct nand_blk_dev *dev) | 
|---|
|  | 272 | +	__releases(&dev->nand_ops->queue_lock) | 
|---|
|  | 273 | +	__acquires(&dev->nand_ops->queue_lock) | 
|---|
|  | 274 | +{ | 
|---|
|  | 275 | +	struct request *req = NULL; | 
|---|
|  | 276 | + | 
|---|
|  | 277 | +	while (1) { | 
|---|
|  | 278 | +		blk_status_t res; | 
|---|
|  | 279 | + | 
|---|
|  | 280 | +		req = rk_nand_next_request(dev); | 
|---|
|  | 281 | +		if (!req) | 
|---|
|  | 282 | +			break; | 
|---|
|  | 283 | + | 
|---|
|  | 284 | +		spin_unlock_irq(&dev->nand_ops->queue_lock); | 
|---|
|  | 285 | + | 
|---|
|  | 286 | +		rknand_device_lock(); | 
|---|
|  | 287 | +		res = do_blktrans_all_request(dev, req); | 
|---|
|  | 288 | +		rknand_device_unlock(); | 
|---|
|  | 289 | + | 
|---|
|  | 290 | +		if (!blk_update_request(req, res, req->__data_len)) { | 
|---|
|  | 291 | +			__blk_mq_end_request(req, res); | 
|---|
|  | 292 | +			req = NULL; | 
|---|
|  | 293 | +		} | 
|---|
|  | 294 | + | 
|---|
|  | 295 | +		spin_lock_irq(&dev->nand_ops->queue_lock); | 
|---|
|  | 296 | +	} | 
|---|
|  | 297 | +} | 
|---|
|  | 298 | + | 
|---|
|  | 299 | +static blk_status_t rk_nand_queue_rq(struct blk_mq_hw_ctx *hctx, | 
|---|
|  | 300 | +				     const struct blk_mq_queue_data *bd) | 
|---|
|  | 301 | +{ | 
|---|
|  | 302 | +	struct nand_blk_dev *dev; | 
|---|
|  | 303 | + | 
|---|
|  | 304 | +	dev = hctx->queue->queuedata; | 
|---|
|  | 305 | +	if (!dev) { | 
|---|
|  | 306 | +		blk_mq_start_request(bd->rq); | 
|---|
|  | 307 | +		return BLK_STS_IOERR; | 
|---|
|  | 308 | +	} | 
|---|
|  | 309 | + | 
|---|
| 245 | 310 | rk_ftl_gc_do = 0; | 
|---|
| 246 |  | -	rk_ftl_gc_timeout.expires = jiffies + rk_ftl_gc_jiffies; | 
|---|
| 247 |  | -	add_timer(&rk_ftl_gc_timeout); | 
|---|
|  | 311 | +	spin_lock_irq(&dev->nand_ops->queue_lock); | 
|---|
|  | 312 | +	list_add_tail(&bd->rq->queuelist, &dev->nand_ops->rq_list); | 
|---|
|  | 313 | +	rk_nand_blktrans_work(dev); | 
|---|
|  | 314 | +	spin_unlock_irq(&dev->nand_ops->queue_lock); | 
|---|
| 248 | 315 |  | 
|---|
| 249 |  | -	while (!nandr->quit) { | 
|---|
| 250 |  | -		int res; | 
|---|
| 251 |  | -		struct nand_blk_dev *dev; | 
|---|
|  | 316 | +	/* wake up gc thread */ | 
|---|
|  | 317 | +	rk_ftl_gc_do = 1; | 
|---|
|  | 318 | +	wake_up(&dev->nand_ops->thread_wq); | 
|---|
|  | 319 | + | 
|---|
|  | 320 | +	return BLK_STS_OK; | 
|---|
|  | 321 | +} | 
|---|
|  | 322 | + | 
|---|
|  | 323 | +static const struct blk_mq_ops rk_nand_mq_ops = { | 
|---|
|  | 324 | +	.queue_rq	= rk_nand_queue_rq, | 
|---|
|  | 325 | +}; | 
|---|
|  | 326 | + | 
|---|
|  | 327 | +static int nand_gc_thread(void *arg) | 
|---|
|  | 328 | +{ | 
|---|
|  | 329 | +	struct nand_blk_ops *nand_ops = arg; | 
|---|
|  | 330 | +	int ftl_gc_status = 0; | 
|---|
|  | 331 | +	int req_empty_times = 0; | 
|---|
|  | 332 | +	int gc_done_times = 0; | 
|---|
|  | 333 | + | 
|---|
|  | 334 | +	rk_ftl_gc_jiffies = HZ / 10; | 
|---|
|  | 335 | +	rk_ftl_gc_do = 1; | 
|---|
|  | 336 | + | 
|---|
|  | 337 | +	while (!nand_ops->quit) { | 
|---|
| 252 | 338 | DECLARE_WAITQUEUE(wait, current); | 
|---|
| 253 | 339 |  | 
|---|
| 254 |  | -		if (!req) | 
|---|
| 255 |  | -			req = blk_fetch_request(rq); | 
|---|
| 256 |  | -		if (!req) { | 
|---|
| 257 |  | -			add_wait_queue(&nandr->thread_wq, &wait); | 
|---|
| 258 |  | -			set_current_state(TASK_INTERRUPTIBLE); | 
|---|
| 259 |  | -			spin_unlock_irq(rq->queue_lock); | 
|---|
|  | 340 | +		add_wait_queue(&nand_ops->thread_wq, &wait); | 
|---|
|  | 341 | +		set_current_state(TASK_INTERRUPTIBLE); | 
|---|
|  | 342 | + | 
|---|
|  | 343 | +		if (rk_ftl_gc_do) { | 
|---|
|  | 344 | +			 /* do garbage collect at idle state */ | 
|---|
| 260 | 345 | if (rknand_device_trylock()) { | 
|---|
| 261 | 346 | ftl_gc_status = rk_ftl_garbage_collect(1, 0); | 
|---|
| 262 | 347 | rknand_device_unlock(); | 
|---|
| 263 | 348 | rk_ftl_gc_jiffies = HZ / 50; | 
|---|
| 264 |  | -				if (ftl_gc_status == 0) | 
|---|
| 265 |  | -					rk_ftl_gc_jiffies = 1 * HZ; | 
|---|
| 266 |  | - | 
|---|
|  | 349 | +				if (ftl_gc_status == 0) { | 
|---|
|  | 350 | +					gc_done_times++; | 
|---|
|  | 351 | +					if (gc_done_times > 10) | 
|---|
|  | 352 | +						rk_ftl_gc_jiffies = 10 * HZ; | 
|---|
|  | 353 | +					else | 
|---|
|  | 354 | +						rk_ftl_gc_jiffies = 1 * HZ; | 
|---|
|  | 355 | +				} else { | 
|---|
|  | 356 | +					gc_done_times = 0; | 
|---|
|  | 357 | +				} | 
|---|
| 267 | 358 | } else { | 
|---|
| 268 |  | -				rk_ftl_gc_jiffies = HZ / 50; | 
|---|
|  | 359 | +				rk_ftl_gc_jiffies = 1 * HZ; | 
|---|
| 269 | 360 | } | 
|---|
| 270 | 361 | req_empty_times++; | 
|---|
| 271 | 362 | if (req_empty_times < 10) | 
|---|
| 272 | 363 | rk_ftl_gc_jiffies = HZ / 50; | 
|---|
| 273 |  | -			/* 100ms cache write back */ | 
|---|
|  | 364 | +			/* cache write back after 100ms */ | 
|---|
| 274 | 365 | if (req_empty_times >= 5 && req_empty_times < 7) { | 
|---|
| 275 | 366 | rknand_device_lock(); | 
|---|
| 276 | 367 | rk_ftl_cache_write_back(); | 
|---|
| 277 | 368 | rknand_device_unlock(); | 
|---|
| 278 | 369 | } | 
|---|
| 279 |  | -			wait_event_timeout(nandr->thread_wq, | 
|---|
| 280 |  | -					   rk_ftl_gc_do || nandr->quit, | 
|---|
| 281 |  | -					   rk_ftl_gc_jiffies); | 
|---|
| 282 |  | -			rk_ftl_gc_do = 0; | 
|---|
| 283 |  | -			spin_lock_irq(rq->queue_lock); | 
|---|
| 284 |  | -			remove_wait_queue(&nandr->thread_wq, &wait); | 
|---|
| 285 |  | -			continue; | 
|---|
| 286 | 370 | } else { | 
|---|
| 287 |  | -			rk_ftl_gc_jiffies = 1 * HZ; | 
|---|
| 288 | 371 | req_empty_times = 0; | 
|---|
|  | 372 | +			rk_ftl_gc_jiffies = 1 * HZ; | 
|---|
| 289 | 373 | } | 
|---|
| 290 |  | - | 
|---|
| 291 |  | -		dev = req->rq_disk->private_data; | 
|---|
| 292 |  | -		totle_nsect = (req->__data_len) >> 9; | 
|---|
| 293 |  | -		sector_index = blk_rq_pos(req); | 
|---|
| 294 |  | -		buf = 0; | 
|---|
| 295 |  | -		res = 0; | 
|---|
| 296 |  | - | 
|---|
| 297 |  | -		op = req_op(req); | 
|---|
| 298 |  | -		if (op == REQ_OP_DISCARD) { | 
|---|
| 299 |  | -			spin_unlock_irq(rq->queue_lock); | 
|---|
| 300 |  | -			rknand_device_lock(); | 
|---|
| 301 |  | -			if (FtlDiscard(blk_rq_pos(req) + | 
|---|
| 302 |  | -				       dev->off_size, totle_nsect)) | 
|---|
| 303 |  | -				res = BLK_STS_IOERR; | 
|---|
| 304 |  | -			rknand_device_unlock(); | 
|---|
| 305 |  | -			spin_lock_irq(rq->queue_lock); | 
|---|
| 306 |  | -			if (!__blk_end_request_cur(req, res)) | 
|---|
| 307 |  | -				req = NULL; | 
|---|
| 308 |  | -			continue; | 
|---|
| 309 |  | -		} else if (op == REQ_OP_FLUSH) { | 
|---|
| 310 |  | -			spin_unlock_irq(rq->queue_lock); | 
|---|
| 311 |  | -			rknand_device_lock(); | 
|---|
| 312 |  | -			rk_ftl_cache_write_back(); | 
|---|
| 313 |  | -			rknand_device_unlock(); | 
|---|
| 314 |  | -			spin_lock_irq(rq->queue_lock); | 
|---|
| 315 |  | -			if (!__blk_end_request_cur(req, res)) | 
|---|
| 316 |  | -				req = NULL; | 
|---|
| 317 |  | -			continue; | 
|---|
| 318 |  | -		} else if (op == REQ_OP_READ) { | 
|---|
| 319 |  | -			rw_flag = READ; | 
|---|
| 320 |  | -		} else if (op == REQ_OP_WRITE) { | 
|---|
| 321 |  | -			rw_flag = WRITE; | 
|---|
| 322 |  | -		} else { | 
|---|
| 323 |  | -			__blk_end_request_all(req, BLK_STS_IOERR); | 
|---|
| 324 |  | -			req = NULL; | 
|---|
| 325 |  | -			continue; | 
|---|
| 326 |  | -		} | 
|---|
| 327 |  | - | 
|---|
| 328 |  | -		if (mtd_read_temp_buffer) { | 
|---|
| 329 |  | -			buf = mtd_read_temp_buffer; | 
|---|
| 330 |  | -			req_check_buffer_align(req, &buf); | 
|---|
| 331 |  | - | 
|---|
| 332 |  | -			if (rw_flag == WRITE && buf == mtd_read_temp_buffer) { | 
|---|
| 333 |  | -				char *p = buf; | 
|---|
| 334 |  | - | 
|---|
| 335 |  | -				rq_for_each_segment(bvec, req, rq_iter) { | 
|---|
| 336 |  | -					page_buf = kmap_atomic(bvec.bv_page); | 
|---|
| 337 |  | -					memcpy(p, | 
|---|
| 338 |  | -					       page_buf + bvec.bv_offset, | 
|---|
| 339 |  | -					       bvec.bv_len); | 
|---|
| 340 |  | -					p += bvec.bv_len; | 
|---|
| 341 |  | -					kunmap_atomic(page_buf); | 
|---|
| 342 |  | -				} | 
|---|
| 343 |  | -			} | 
|---|
| 344 |  | - | 
|---|
| 345 |  | -			spin_unlock_irq(rq->queue_lock); | 
|---|
| 346 |  | -			res = nand_dev_transfer(dev, | 
|---|
| 347 |  | -						sector_index, | 
|---|
| 348 |  | -						totle_nsect, | 
|---|
| 349 |  | -						buf, | 
|---|
| 350 |  | -						rw_flag, | 
|---|
| 351 |  | -						totle_nsect); | 
|---|
| 352 |  | -			spin_lock_irq(rq->queue_lock); | 
|---|
| 353 |  | - | 
|---|
| 354 |  | -			if (rw_flag == READ && buf == mtd_read_temp_buffer) { | 
|---|
| 355 |  | -				char *p = buf; | 
|---|
| 356 |  | - | 
|---|
| 357 |  | -				rq_for_each_segment(bvec, req, rq_iter) { | 
|---|
| 358 |  | -					page_buf = kmap_atomic(bvec.bv_page); | 
|---|
| 359 |  | - | 
|---|
| 360 |  | -					memcpy(page_buf + bvec.bv_offset, | 
|---|
| 361 |  | -					       p, | 
|---|
| 362 |  | -					       bvec.bv_len); | 
|---|
| 363 |  | -					p += bvec.bv_len; | 
|---|
| 364 |  | -					kunmap_atomic(page_buf); | 
|---|
| 365 |  | -				} | 
|---|
| 366 |  | -			} | 
|---|
| 367 |  | -			__blk_end_request_all(req, res); | 
|---|
| 368 |  | -			req = NULL; | 
|---|
| 369 |  | -		} else { | 
|---|
| 370 |  | -			while (req) { | 
|---|
| 371 |  | -				sector_index = blk_rq_pos(req); | 
|---|
| 372 |  | -				totle_nsect = blk_rq_cur_bytes(req); | 
|---|
| 373 |  | -				buf = kmap_atomic(bio_page(req->bio)) + | 
|---|
| 374 |  | -					   bio_offset(req->bio); | 
|---|
| 375 |  | -				spin_unlock_irq(rq->queue_lock); | 
|---|
| 376 |  | -				res = nand_dev_transfer(dev, | 
|---|
| 377 |  | -							sector_index, | 
|---|
| 378 |  | -							totle_nsect, | 
|---|
| 379 |  | -							buf, | 
|---|
| 380 |  | -							rw_flag, | 
|---|
| 381 |  | -							totle_nsect); | 
|---|
| 382 |  | -				spin_lock_irq(rq->queue_lock); | 
|---|
| 383 |  | -				kunmap_atomic(buf); | 
|---|
| 384 |  | -				if (!__blk_end_request_cur(req, res)) | 
|---|
| 385 |  | -					req = NULL; | 
|---|
| 386 |  | -			} | 
|---|
| 387 |  | -		} | 
|---|
|  | 374 | +		wait_event_timeout(nand_ops->thread_wq, nand_ops->quit, | 
|---|
|  | 375 | +				   rk_ftl_gc_jiffies); | 
|---|
|  | 376 | +		remove_wait_queue(&nand_ops->thread_wq, &wait); | 
|---|
|  | 377 | +		continue; | 
|---|
| 388 | 378 | } | 
|---|
| 389 |  | -	pr_info("nand th quited\n"); | 
|---|
| 390 |  | -	nandr->nand_th_quited = 1; | 
|---|
| 391 |  | -	if (req) | 
|---|
| 392 |  | -		__blk_end_request_all(req, BLK_STS_IOERR); | 
|---|
| 393 |  | -	rk_nand_schedule_enable_config(0); | 
|---|
| 394 |  | -	while ((req = blk_fetch_request(rq)) != NULL) | 
|---|
| 395 |  | -		__blk_end_request_all(req, BLK_STS_IOERR); | 
|---|
| 396 |  | -	spin_unlock_irq(rq->queue_lock); | 
|---|
| 397 |  | -	complete_and_exit(&nandr->thread_exit, 0); | 
|---|
| 398 |  | -	return 0; | 
|---|
| 399 |  | -} | 
|---|
| 400 |  | - | 
|---|
| 401 |  | -static void nand_blk_request(struct request_queue *rq) | 
|---|
| 402 |  | -{ | 
|---|
| 403 |  | -	struct nand_blk_ops *nandr = rq->queuedata; | 
|---|
| 404 |  | -	struct request *req = NULL; | 
|---|
| 405 |  | - | 
|---|
| 406 |  | -	if (nandr->nand_th_quited) { | 
|---|
| 407 |  | -		while ((req = blk_fetch_request(rq)) != NULL) | 
|---|
| 408 |  | -			__blk_end_request_all(req, BLK_STS_IOERR); | 
|---|
| 409 |  | -		return; | 
|---|
| 410 |  | -	} | 
|---|
| 411 |  | -	rk_ftl_gc_do = 1; | 
|---|
| 412 |  | -	wake_up(&nandr->thread_wq); | 
|---|
| 413 |  | -} | 
|---|
| 414 |  | - | 
|---|
| 415 |  | -static int rknand_get_part(char *parts, | 
|---|
| 416 |  | -			   struct nand_part *this_part, | 
|---|
| 417 |  | -			   int *part_index) | 
|---|
| 418 |  | -{ | 
|---|
| 419 |  | -	char delim; | 
|---|
| 420 |  | -	unsigned int mask_flags; | 
|---|
| 421 |  | -	unsigned long long size, offset = ULLONG_MAX; | 
|---|
| 422 |  | -	char name[40] = "\0"; | 
|---|
| 423 |  | - | 
|---|
| 424 |  | -	if (*parts == '-') { | 
|---|
| 425 |  | -		size = ULLONG_MAX; | 
|---|
| 426 |  | -		parts++; | 
|---|
| 427 |  | -	} else { | 
|---|
| 428 |  | -		size = memparse(parts, &parts); | 
|---|
| 429 |  | -	} | 
|---|
| 430 |  | - | 
|---|
| 431 |  | -	if (*parts == '@') { | 
|---|
| 432 |  | -		parts++; | 
|---|
| 433 |  | -		offset = memparse(parts, &parts); | 
|---|
| 434 |  | -	} | 
|---|
| 435 |  | - | 
|---|
| 436 |  | -	mask_flags = 0; | 
|---|
| 437 |  | -	delim = 0; | 
|---|
| 438 |  | - | 
|---|
| 439 |  | -	if (*parts == '(') | 
|---|
| 440 |  | -		delim = ')'; | 
|---|
| 441 |  | - | 
|---|
| 442 |  | -	if (delim) { | 
|---|
| 443 |  | -		char *p; | 
|---|
| 444 |  | - | 
|---|
| 445 |  | -		p = strchr(parts + 1, delim); | 
|---|
| 446 |  | -		if (!p) | 
|---|
| 447 |  | -			return 0; | 
|---|
| 448 |  | -		strncpy(name, parts + 1, p - (parts + 1)); | 
|---|
| 449 |  | -		parts = p + 1; | 
|---|
| 450 |  | -	} | 
|---|
| 451 |  | - | 
|---|
| 452 |  | -	if (strncmp(parts, "ro", 2) == 0) { | 
|---|
| 453 |  | -		mask_flags = PART_READONLY; | 
|---|
| 454 |  | -		parts += 2; | 
|---|
| 455 |  | -	} | 
|---|
| 456 |  | - | 
|---|
| 457 |  | -	if (strncmp(parts, "wo", 2) == 0) { | 
|---|
| 458 |  | -		mask_flags = PART_WRITEONLY; | 
|---|
| 459 |  | -		parts += 2; | 
|---|
| 460 |  | -	} | 
|---|
| 461 |  | - | 
|---|
| 462 |  | -	this_part->size = (unsigned long)size; | 
|---|
| 463 |  | -	this_part->offset = (unsigned long)offset; | 
|---|
| 464 |  | -	this_part->type = mask_flags; | 
|---|
| 465 |  | -	sprintf(this_part->name, "%s", name); | 
|---|
| 466 |  | - | 
|---|
| 467 |  | -	if ((++(*part_index) < MAX_PART_COUNT) && (*parts == ',')) | 
|---|
| 468 |  | -		rknand_get_part(++parts, this_part + 1, part_index); | 
|---|
| 469 |  | - | 
|---|
| 470 |  | -	return 1; | 
|---|
| 471 |  | -} | 
|---|
| 472 |  | - | 
|---|
| 473 |  | -static int nand_prase_cmdline_part(struct nand_part *pdisk_part) | 
|---|
| 474 |  | -{ | 
|---|
| 475 |  | -	char *pbuf; | 
|---|
| 476 |  | -	int part_num = 0, i; | 
|---|
| 477 |  | -	unsigned int cap_size = rk_ftl_get_capacity(); | 
|---|
| 478 |  | -	char *cmdline; | 
|---|
| 479 |  | - | 
|---|
| 480 |  | -	cmdline = strstr(saved_command_line, "mtdparts="); | 
|---|
| 481 |  | -	if (!cmdline) | 
|---|
| 482 |  | -		return 0; | 
|---|
| 483 |  | -	cmdline += 9; | 
|---|
| 484 |  | -	if (!memcmp(cmdline, "rk29xxnand:", strlen("rk29xxnand:"))) { | 
|---|
| 485 |  | -		pbuf = cmdline + strlen("rk29xxnand:"); | 
|---|
| 486 |  | -		rknand_get_part(pbuf, pdisk_part, &part_num); | 
|---|
| 487 |  | -		if (part_num) | 
|---|
| 488 |  | -			pdisk_part[part_num - 1].size = cap_size - | 
|---|
| 489 |  | -				pdisk_part[part_num - 1].offset; | 
|---|
| 490 |  | - | 
|---|
| 491 |  | -		for (i = 0; i < part_num; i++) { | 
|---|
| 492 |  | -			if (pdisk_part[i].size + pdisk_part[i].offset | 
|---|
| 493 |  | -				> cap_size) { | 
|---|
| 494 |  | -				pdisk_part[i].size = cap_size - | 
|---|
| 495 |  | -					pdisk_part[i].offset; | 
|---|
| 496 |  | -				pr_err("partition error....max cap:%x\n", | 
|---|
| 497 |  | -					cap_size); | 
|---|
| 498 |  | -				if (!pdisk_part[i].size) | 
|---|
| 499 |  | -					return i; | 
|---|
| 500 |  | -				else | 
|---|
| 501 |  | -					return (i + 1); | 
|---|
| 502 |  | -			} | 
|---|
| 503 |  | -		} | 
|---|
| 504 |  | -		return part_num; | 
|---|
| 505 |  | -	} | 
|---|
|  | 379 | +	pr_info("nand gc quited\n"); | 
|---|
|  | 380 | +	nand_ops->nand_th_quited = 1; | 
|---|
|  | 381 | +	complete_and_exit(&nand_ops->thread_exit, 0); | 
|---|
| 506 | 382 | return 0; | 
|---|
| 507 | 383 | } | 
|---|
| 508 | 384 |  | 
|---|
| .. | .. | 
|---|
| 515 | 391 | { | 
|---|
| 516 | 392 | }; | 
|---|
| 517 | 393 |  | 
|---|
| 518 |  | -#define DISABLE_WRITE _IO('V', 0) | 
|---|
| 519 |  | -#define ENABLE_WRITE _IO('V', 1) | 
|---|
| 520 |  | -#define DISABLE_READ _IO('V', 2) | 
|---|
| 521 |  | -#define ENABLE_READ _IO('V', 3) | 
|---|
| 522 | 394 | static int rknand_ioctl(struct block_device *bdev, fmode_t mode, | 
|---|
| 523 | 395 | unsigned int cmd, | 
|---|
| 524 | 396 | unsigned long arg) | 
|---|
| .. | .. | 
|---|
| 564 | 436 | .owner = THIS_MODULE, | 
|---|
| 565 | 437 | }; | 
|---|
| 566 | 438 |  | 
|---|
| 567 |  | -static int nand_add_dev(struct nand_blk_ops *nandr, struct nand_part *part) | 
|---|
|  | 439 | +static int nand_add_dev(struct nand_blk_ops *nand_ops, struct nand_part *part) | 
|---|
| 568 | 440 | { | 
|---|
| 569 | 441 | struct nand_blk_dev *dev; | 
|---|
| 570 | 442 | struct gendisk *gd; | 
|---|
| .. | .. | 
|---|
| 576 | 448 | if (!dev) | 
|---|
| 577 | 449 | return -ENOMEM; | 
|---|
| 578 | 450 |  | 
|---|
| 579 |  | -	gd = alloc_disk(1 << nandr->minorbits); | 
|---|
|  | 451 | +	gd = alloc_disk(1 << nand_ops->minorbits); | 
|---|
| 580 | 452 | if (!gd) { | 
|---|
| 581 | 453 | kfree(dev); | 
|---|
| 582 | 454 | return -ENOMEM; | 
|---|
| 583 | 455 | } | 
|---|
| 584 |  | - | 
|---|
| 585 |  | -	dev->nandr = nandr; | 
|---|
|  | 456 | +	nand_ops->rq->queuedata = dev; | 
|---|
|  | 457 | +	dev->nand_ops = nand_ops; | 
|---|
| 586 | 458 | dev->size = part->size; | 
|---|
| 587 | 459 | dev->off_size = part->offset; | 
|---|
| 588 |  | -	dev->devnum = nandr->last_dev_index; | 
|---|
| 589 |  | -	list_add_tail(&dev->list, &nandr->devs); | 
|---|
| 590 |  | -	nandr->last_dev_index++; | 
|---|
|  | 460 | +	dev->devnum = nand_ops->last_dev_index; | 
|---|
|  | 461 | +	list_add_tail(&dev->list, &nand_ops->devs); | 
|---|
|  | 462 | +	nand_ops->last_dev_index++; | 
|---|
| 591 | 463 |  | 
|---|
| 592 |  | -	gd->major = nandr->major; | 
|---|
| 593 |  | -	gd->first_minor = (dev->devnum) << nandr->minorbits; | 
|---|
|  | 464 | +	gd->major = nand_ops->major; | 
|---|
|  | 465 | +	gd->first_minor = (dev->devnum) << nand_ops->minorbits; | 
|---|
| 594 | 466 |  | 
|---|
| 595 | 467 | gd->fops = &nand_blktrans_ops; | 
|---|
| 596 | 468 |  | 
|---|
| 597 |  | -	if (part->name[0]) { | 
|---|
| 598 |  | -		snprintf(gd->disk_name, | 
|---|
| 599 |  | -			 sizeof(gd->disk_name), | 
|---|
| 600 |  | -			 "%s_%s", | 
|---|
| 601 |  | -			 nandr->name, | 
|---|
| 602 |  | -			 part->name); | 
|---|
| 603 |  | -	} else { | 
|---|
| 604 |  | -		gd->flags = GENHD_FL_EXT_DEVT; | 
|---|
| 605 |  | -		gd->minors = 255; | 
|---|
| 606 |  | -		snprintf(gd->disk_name, | 
|---|
| 607 |  | -			 sizeof(gd->disk_name), | 
|---|
| 608 |  | -			 "%s%d", | 
|---|
| 609 |  | -			 nandr->name, | 
|---|
| 610 |  | -			 dev->devnum); | 
|---|
| 611 |  | -	} | 
|---|
|  | 469 | +	gd->flags = GENHD_FL_EXT_DEVT; | 
|---|
|  | 470 | +	gd->minors = 255; | 
|---|
|  | 471 | +	snprintf(gd->disk_name, | 
|---|
|  | 472 | +		 sizeof(gd->disk_name), | 
|---|
|  | 473 | +		 "%s%d", | 
|---|
|  | 474 | +		 nand_ops->name, | 
|---|
|  | 475 | +		 dev->devnum); | 
|---|
|  | 476 | + | 
|---|
| 612 | 477 | set_capacity(gd, dev->size); | 
|---|
| 613 | 478 |  | 
|---|
| 614 | 479 | gd->private_data = dev; | 
|---|
| 615 | 480 | dev->blkcore_priv = gd; | 
|---|
| 616 |  | -	gd->queue = nandr->rq; | 
|---|
| 617 |  | -	gd->queue->bypass_depth = 1; | 
|---|
|  | 481 | +	gd->queue = nand_ops->rq; | 
|---|
| 618 | 482 |  | 
|---|
| 619 | 483 | if (part->type == PART_NO_ACCESS) | 
|---|
| 620 | 484 | dev->disable_access = 1; | 
|---|
| .. | .. | 
|---|
| 628 | 492 | if (dev->readonly) | 
|---|
| 629 | 493 | set_disk_ro(gd, 1); | 
|---|
| 630 | 494 |  | 
|---|
| 631 |  | -	if (gd->flags != GENHD_FL_EXT_DEVT) | 
|---|
| 632 |  | -		add_disk(gd); | 
|---|
| 633 |  | -	else | 
|---|
| 634 |  | -		device_add_disk(g_nand_device, gd); | 
|---|
|  | 495 | +	device_add_disk(g_nand_device, gd, NULL); | 
|---|
| 635 | 496 |  | 
|---|
| 636 | 497 | return 0; | 
|---|
| 637 | 498 | } | 
|---|
| .. | .. | 
|---|
| 646 | 507 | del_gendisk(gd); | 
|---|
| 647 | 508 | put_disk(gd); | 
|---|
| 648 | 509 | kfree(dev); | 
|---|
|  | 510 | + | 
|---|
| 649 | 511 | return 0; | 
|---|
| 650 | 512 | } | 
|---|
| 651 | 513 |  | 
|---|
| 652 |  | -int nand_blk_add_whole_disk(void) | 
|---|
|  | 514 | +static int nand_blk_register(struct nand_blk_ops *nand_ops) | 
|---|
| 653 | 515 | { | 
|---|
| 654 | 516 | struct nand_part part; | 
|---|
| 655 |  | - | 
|---|
| 656 |  | -	part.offset = 0; | 
|---|
| 657 |  | -	part.size = rk_ftl_get_capacity(); | 
|---|
| 658 |  | -	part.type = 0; | 
|---|
| 659 |  | -	strncpy(part.name, "rknand", sizeof(part.name)); | 
|---|
| 660 |  | -	nand_add_dev(&mytr, &part); | 
|---|
| 661 |  | -	return 0; | 
|---|
| 662 |  | -} | 
|---|
| 663 |  | - | 
|---|
| 664 |  | -static int nand_blk_register(struct nand_blk_ops *nandr) | 
|---|
| 665 |  | -{ | 
|---|
| 666 |  | -	int i, ret; | 
|---|
| 667 |  | -	u32 part_size; | 
|---|
| 668 |  | -	struct nand_part part; | 
|---|
|  | 517 | +	int ret; | 
|---|
| 669 | 518 |  | 
|---|
| 670 | 519 | rk_nand_schedule_enable_config(1); | 
|---|
| 671 |  | -	nandr->quit = 0; | 
|---|
| 672 |  | -	nandr->nand_th_quited = 0; | 
|---|
|  | 520 | +	nand_ops->quit = 0; | 
|---|
|  | 521 | +	nand_ops->nand_th_quited = 0; | 
|---|
| 673 | 522 |  | 
|---|
| 674 |  | -	mtd_read_temp_buffer = kmalloc(MTD_RW_SECTORS * 512, | 
|---|
| 675 |  | -				       GFP_KERNEL | GFP_DMA); | 
|---|
| 676 |  | - | 
|---|
| 677 |  | -	ret = register_blkdev(nandr->major, nandr->name); | 
|---|
|  | 523 | +	ret = register_blkdev(nand_ops->major, nand_ops->name); | 
|---|
| 678 | 524 | if (ret) | 
|---|
| 679 |  | -		return -1; | 
|---|
|  | 525 | +		return ret; | 
|---|
| 680 | 526 |  | 
|---|
| 681 |  | -	spin_lock_init(&nandr->queue_lock); | 
|---|
| 682 |  | -	init_completion(&nandr->thread_exit); | 
|---|
| 683 |  | -	init_waitqueue_head(&nandr->thread_wq); | 
|---|
| 684 |  | -	rknand_device_lock_init(); | 
|---|
| 685 |  | - | 
|---|
| 686 |  | -	nandr->rq = blk_init_queue(nand_blk_request, &nandr->queue_lock); | 
|---|
| 687 |  | -	if (!nandr->rq) { | 
|---|
| 688 |  | -		unregister_blkdev(nandr->major, nandr->name); | 
|---|
| 689 |  | -		return  -1; | 
|---|
|  | 527 | +	mtd_read_temp_buffer = kmalloc(MTD_RW_SECTORS * 512, GFP_KERNEL | GFP_DMA); | 
|---|
|  | 528 | +	if (!mtd_read_temp_buffer) { | 
|---|
|  | 529 | +		ret = -ENOMEM; | 
|---|
|  | 530 | +		goto mtd_buffer_error; | 
|---|
| 690 | 531 | } | 
|---|
| 691 | 532 |  | 
|---|
| 692 |  | -	blk_queue_max_hw_sectors(nandr->rq, MTD_RW_SECTORS); | 
|---|
| 693 |  | -	blk_queue_max_segments(nandr->rq, MTD_RW_SECTORS); | 
|---|
|  | 533 | +	init_completion(&nand_ops->thread_exit); | 
|---|
|  | 534 | +	init_waitqueue_head(&nand_ops->thread_wq); | 
|---|
|  | 535 | +	rknand_device_lock_init(); | 
|---|
| 694 | 536 |  | 
|---|
| 695 |  | -	blk_queue_flag_set(QUEUE_FLAG_DISCARD, nandr->rq); | 
|---|
| 696 |  | -	blk_queue_max_discard_sectors(nandr->rq, UINT_MAX >> 9); | 
|---|
|  | 537 | +	/* Create the request queue */ | 
|---|
|  | 538 | +	spin_lock_init(&nand_ops->queue_lock); | 
|---|
|  | 539 | +	INIT_LIST_HEAD(&nand_ops->rq_list); | 
|---|
|  | 540 | + | 
|---|
|  | 541 | +	nand_ops->tag_set = kzalloc(sizeof(*nand_ops->tag_set), GFP_KERNEL); | 
|---|
|  | 542 | +	if (!nand_ops->tag_set) { | 
|---|
|  | 543 | +		ret = -ENOMEM; | 
|---|
|  | 544 | +		goto tag_set_error; | 
|---|
|  | 545 | +	} | 
|---|
|  | 546 | + | 
|---|
|  | 547 | +	nand_ops->rq = blk_mq_init_sq_queue(nand_ops->tag_set, &rk_nand_mq_ops, 1, | 
|---|
|  | 548 | +					   BLK_MQ_F_SHOULD_MERGE | BLK_MQ_F_BLOCKING); | 
|---|
|  | 549 | +	if (IS_ERR(nand_ops->rq)) { | 
|---|
|  | 550 | +		ret = PTR_ERR(nand_ops->rq); | 
|---|
|  | 551 | +		nand_ops->rq = NULL; | 
|---|
|  | 552 | +		goto rq_init_error; | 
|---|
|  | 553 | +	} | 
|---|
|  | 554 | + | 
|---|
|  | 555 | +	blk_queue_max_hw_sectors(nand_ops->rq, MTD_RW_SECTORS); | 
|---|
|  | 556 | +	blk_queue_max_segments(nand_ops->rq, MTD_RW_SECTORS); | 
|---|
|  | 557 | + | 
|---|
|  | 558 | +	blk_queue_flag_set(QUEUE_FLAG_DISCARD, nand_ops->rq); | 
|---|
|  | 559 | +	blk_queue_max_discard_sectors(nand_ops->rq, UINT_MAX >> 9); | 
|---|
| 697 | 560 | /* discard_granularity config to one nand page size 32KB*/ | 
|---|
| 698 |  | -	nandr->rq->limits.discard_granularity = 64 << 9; | 
|---|
|  | 561 | +	nand_ops->rq->limits.discard_granularity = 64 << 9; | 
|---|
| 699 | 562 |  | 
|---|
| 700 |  | -	nandr->rq->queuedata = nandr; | 
|---|
| 701 |  | -	INIT_LIST_HEAD(&nandr->devs); | 
|---|
| 702 |  | -	kthread_run(nand_blktrans_thread, (void *)nandr, "rknand"); | 
|---|
|  | 563 | +	INIT_LIST_HEAD(&nand_ops->devs); | 
|---|
|  | 564 | +	kthread_run(nand_gc_thread, (void *)nand_ops, "rknand_gc"); | 
|---|
| 703 | 565 |  | 
|---|
| 704 |  | -	g_max_part_num = nand_prase_cmdline_part(disk_array); | 
|---|
| 705 |  | - | 
|---|
| 706 |  | -	nandr->last_dev_index = 0; | 
|---|
|  | 566 | +	nand_ops->last_dev_index = 0; | 
|---|
| 707 | 567 | part.offset = 0; | 
|---|
| 708 | 568 | part.size = rk_ftl_get_capacity(); | 
|---|
| 709 | 569 | part.type = 0; | 
|---|
| 710 | 570 | part.name[0] = 0; | 
|---|
| 711 |  | -	nand_add_dev(&mytr, &part); | 
|---|
| 712 |  | - | 
|---|
| 713 |  | -	if (g_max_part_num) { | 
|---|
| 714 |  | -		for (i = 0; i < g_max_part_num; i++) { | 
|---|
| 715 |  | -			part_size = (disk_array[i].offset + disk_array[i].size); | 
|---|
| 716 |  | -			pr_info("%10s: 0x%09llx -- 0x%09llx (%llu MB)\n", | 
|---|
| 717 |  | -				disk_array[i].name, | 
|---|
| 718 |  | -				(u64)disk_array[i].offset * 512, | 
|---|
| 719 |  | -				(u64)part_size * 512, | 
|---|
| 720 |  | -				(u64)disk_array[i].size / 2048); | 
|---|
| 721 |  | -			nand_add_dev(nandr, &disk_array[i]); | 
|---|
| 722 |  | -		} | 
|---|
| 723 |  | -	} | 
|---|
|  | 571 | +	nand_add_dev(nand_ops, &part); | 
|---|
| 724 | 572 |  | 
|---|
| 725 | 573 | rknand_create_procfs(); | 
|---|
| 726 | 574 | rk_ftl_storage_sys_init(); | 
|---|
| .. | .. | 
|---|
| 735 | 583 | } | 
|---|
| 736 | 584 |  | 
|---|
| 737 | 585 | return 0; | 
|---|
|  | 586 | + | 
|---|
|  | 587 | +rq_init_error: | 
|---|
|  | 588 | +	kfree(nand_ops->tag_set); | 
|---|
|  | 589 | +tag_set_error: | 
|---|
|  | 590 | +	kfree(mtd_read_temp_buffer); | 
|---|
|  | 591 | +	mtd_read_temp_buffer = NULL; | 
|---|
|  | 592 | +mtd_buffer_error: | 
|---|
|  | 593 | +	unregister_blkdev(nand_ops->major, nand_ops->name); | 
|---|
|  | 594 | + | 
|---|
|  | 595 | +	return ret; | 
|---|
| 738 | 596 | } | 
|---|
| 739 | 597 |  | 
|---|
| 740 |  | -static void nand_blk_unregister(struct nand_blk_ops *nandr) | 
|---|
|  | 598 | +static void nand_blk_unregister(struct nand_blk_ops *nand_ops) | 
|---|
| 741 | 599 | { | 
|---|
| 742 | 600 | struct list_head *this, *next; | 
|---|
| 743 | 601 |  | 
|---|
| 744 | 602 | if (!rk_nand_dev_initialised) | 
|---|
| 745 | 603 | return; | 
|---|
| 746 |  | -	nandr->quit = 1; | 
|---|
| 747 |  | -	wake_up(&nandr->thread_wq); | 
|---|
| 748 |  | -	wait_for_completion(&nandr->thread_exit); | 
|---|
| 749 |  | -	list_for_each_safe(this, next, &nandr->devs) { | 
|---|
|  | 604 | +	nand_ops->quit = 1; | 
|---|
|  | 605 | +	wake_up(&nand_ops->thread_wq); | 
|---|
|  | 606 | +	wait_for_completion(&nand_ops->thread_exit); | 
|---|
|  | 607 | +	list_for_each_safe(this, next, &nand_ops->devs) { | 
|---|
| 750 | 608 | struct nand_blk_dev *dev | 
|---|
| 751 | 609 | = list_entry(this, struct nand_blk_dev, list); | 
|---|
| 752 | 610 |  | 
|---|
| 753 | 611 | nand_remove_dev(dev); | 
|---|
| 754 | 612 | } | 
|---|
| 755 |  | -	blk_cleanup_queue(nandr->rq); | 
|---|
| 756 |  | -	unregister_blkdev(nandr->major, nandr->name); | 
|---|
|  | 613 | +	blk_cleanup_queue(nand_ops->rq); | 
|---|
|  | 614 | +	unregister_blkdev(nand_ops->major, nand_ops->name); | 
|---|
| 757 | 615 | } | 
|---|
| 758 | 616 |  | 
|---|
| 759 | 617 | void rknand_dev_flush(void) | 
|---|