diff options
author | Thomas Gleixner <tglx@linutronix.de> | 2016-01-12 05:01:12 -0500 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2016-01-12 05:01:12 -0500 |
commit | 1f16f116b01c110db20ab808562c8b8bc3ee3d6e (patch) | |
tree | 44db563f64cf5f8d62af8f99a61e2b248c44ea3a /drivers/lightnvm | |
parent | 03724ac3d48f8f0e3caf1d30fa134f8fd96c94e2 (diff) | |
parent | f9eccf24615672896dc13251410c3f2f33a14f95 (diff) |
Merge branches 'clockevents/4.4-fixes' and 'clockevents/4.5-fixes' of http://git.linaro.org/people/daniel.lezcano/linux into timers/urgent
Pull in fixes from Daniel Lezcano:
- Fix the vt8500 timer leading to a system lock up when dealing with too
small delta (Roman Volkov)
- Select the CLKSRC_MMIO when the fsl_ftm_timer is enabled with COMPILE_TEST
(Daniel Lezcano)
- Prevent to compile timers using the 'iomem' API when the architecture has
not HAS_IOMEM set (Richard Weinberger)
Diffstat (limited to 'drivers/lightnvm')
-rw-r--r-- | drivers/lightnvm/Kconfig | 1 | ||||
-rw-r--r-- | drivers/lightnvm/core.c | 158 | ||||
-rw-r--r-- | drivers/lightnvm/gennvm.c | 105 | ||||
-rw-r--r-- | drivers/lightnvm/gennvm.h | 2 | ||||
-rw-r--r-- | drivers/lightnvm/rrpc.c | 57 |
5 files changed, 215 insertions, 108 deletions
diff --git a/drivers/lightnvm/Kconfig b/drivers/lightnvm/Kconfig index a16bf56d3f28..85a339030e4b 100644 --- a/drivers/lightnvm/Kconfig +++ b/drivers/lightnvm/Kconfig | |||
@@ -18,6 +18,7 @@ if NVM | |||
18 | 18 | ||
19 | config NVM_DEBUG | 19 | config NVM_DEBUG |
20 | bool "Open-Channel SSD debugging support" | 20 | bool "Open-Channel SSD debugging support" |
21 | default n | ||
21 | ---help--- | 22 | ---help--- |
22 | Exposes a debug management interface to create/remove targets at: | 23 | Exposes a debug management interface to create/remove targets at: |
23 | 24 | ||
diff --git a/drivers/lightnvm/core.c b/drivers/lightnvm/core.c index f659e605a406..8f41b245cd55 100644 --- a/drivers/lightnvm/core.c +++ b/drivers/lightnvm/core.c | |||
@@ -74,7 +74,7 @@ EXPORT_SYMBOL(nvm_unregister_target); | |||
74 | void *nvm_dev_dma_alloc(struct nvm_dev *dev, gfp_t mem_flags, | 74 | void *nvm_dev_dma_alloc(struct nvm_dev *dev, gfp_t mem_flags, |
75 | dma_addr_t *dma_handler) | 75 | dma_addr_t *dma_handler) |
76 | { | 76 | { |
77 | return dev->ops->dev_dma_alloc(dev->q, dev->ppalist_pool, mem_flags, | 77 | return dev->ops->dev_dma_alloc(dev, dev->ppalist_pool, mem_flags, |
78 | dma_handler); | 78 | dma_handler); |
79 | } | 79 | } |
80 | EXPORT_SYMBOL(nvm_dev_dma_alloc); | 80 | EXPORT_SYMBOL(nvm_dev_dma_alloc); |
@@ -97,15 +97,47 @@ static struct nvmm_type *nvm_find_mgr_type(const char *name) | |||
97 | return NULL; | 97 | return NULL; |
98 | } | 98 | } |
99 | 99 | ||
100 | struct nvmm_type *nvm_init_mgr(struct nvm_dev *dev) | ||
101 | { | ||
102 | struct nvmm_type *mt; | ||
103 | int ret; | ||
104 | |||
105 | lockdep_assert_held(&nvm_lock); | ||
106 | |||
107 | list_for_each_entry(mt, &nvm_mgrs, list) { | ||
108 | ret = mt->register_mgr(dev); | ||
109 | if (ret < 0) { | ||
110 | pr_err("nvm: media mgr failed to init (%d) on dev %s\n", | ||
111 | ret, dev->name); | ||
112 | return NULL; /* initialization failed */ | ||
113 | } else if (ret > 0) | ||
114 | return mt; | ||
115 | } | ||
116 | |||
117 | return NULL; | ||
118 | } | ||
119 | |||
100 | int nvm_register_mgr(struct nvmm_type *mt) | 120 | int nvm_register_mgr(struct nvmm_type *mt) |
101 | { | 121 | { |
122 | struct nvm_dev *dev; | ||
102 | int ret = 0; | 123 | int ret = 0; |
103 | 124 | ||
104 | down_write(&nvm_lock); | 125 | down_write(&nvm_lock); |
105 | if (nvm_find_mgr_type(mt->name)) | 126 | if (nvm_find_mgr_type(mt->name)) { |
106 | ret = -EEXIST; | 127 | ret = -EEXIST; |
107 | else | 128 | goto finish; |
129 | } else { | ||
108 | list_add(&mt->list, &nvm_mgrs); | 130 | list_add(&mt->list, &nvm_mgrs); |
131 | } | ||
132 | |||
133 | /* try to register media mgr if any device have none configured */ | ||
134 | list_for_each_entry(dev, &nvm_devices, devices) { | ||
135 | if (dev->mt) | ||
136 | continue; | ||
137 | |||
138 | dev->mt = nvm_init_mgr(dev); | ||
139 | } | ||
140 | finish: | ||
109 | up_write(&nvm_lock); | 141 | up_write(&nvm_lock); |
110 | 142 | ||
111 | return ret; | 143 | return ret; |
@@ -160,11 +192,6 @@ int nvm_erase_blk(struct nvm_dev *dev, struct nvm_block *blk) | |||
160 | } | 192 | } |
161 | EXPORT_SYMBOL(nvm_erase_blk); | 193 | EXPORT_SYMBOL(nvm_erase_blk); |
162 | 194 | ||
163 | static void nvm_core_free(struct nvm_dev *dev) | ||
164 | { | ||
165 | kfree(dev); | ||
166 | } | ||
167 | |||
168 | static int nvm_core_init(struct nvm_dev *dev) | 195 | static int nvm_core_init(struct nvm_dev *dev) |
169 | { | 196 | { |
170 | struct nvm_id *id = &dev->identity; | 197 | struct nvm_id *id = &dev->identity; |
@@ -179,12 +206,21 @@ static int nvm_core_init(struct nvm_dev *dev) | |||
179 | dev->sec_size = grp->csecs; | 206 | dev->sec_size = grp->csecs; |
180 | dev->oob_size = grp->sos; | 207 | dev->oob_size = grp->sos; |
181 | dev->sec_per_pg = grp->fpg_sz / grp->csecs; | 208 | dev->sec_per_pg = grp->fpg_sz / grp->csecs; |
182 | dev->addr_mode = id->ppat; | 209 | memcpy(&dev->ppaf, &id->ppaf, sizeof(struct nvm_addr_format)); |
183 | dev->addr_format = id->ppaf; | ||
184 | 210 | ||
185 | dev->plane_mode = NVM_PLANE_SINGLE; | 211 | dev->plane_mode = NVM_PLANE_SINGLE; |
186 | dev->max_rq_size = dev->ops->max_phys_sect * dev->sec_size; | 212 | dev->max_rq_size = dev->ops->max_phys_sect * dev->sec_size; |
187 | 213 | ||
214 | if (grp->mtype != 0) { | ||
215 | pr_err("nvm: memory type not supported\n"); | ||
216 | return -EINVAL; | ||
217 | } | ||
218 | |||
219 | if (grp->fmtype != 0 && grp->fmtype != 1) { | ||
220 | pr_err("nvm: flash type not supported\n"); | ||
221 | return -EINVAL; | ||
222 | } | ||
223 | |||
188 | if (grp->mpos & 0x020202) | 224 | if (grp->mpos & 0x020202) |
189 | dev->plane_mode = NVM_PLANE_DOUBLE; | 225 | dev->plane_mode = NVM_PLANE_DOUBLE; |
190 | if (grp->mpos & 0x040404) | 226 | if (grp->mpos & 0x040404) |
@@ -213,21 +249,17 @@ static void nvm_free(struct nvm_dev *dev) | |||
213 | 249 | ||
214 | if (dev->mt) | 250 | if (dev->mt) |
215 | dev->mt->unregister_mgr(dev); | 251 | dev->mt->unregister_mgr(dev); |
216 | |||
217 | nvm_core_free(dev); | ||
218 | } | 252 | } |
219 | 253 | ||
220 | static int nvm_init(struct nvm_dev *dev) | 254 | static int nvm_init(struct nvm_dev *dev) |
221 | { | 255 | { |
222 | struct nvmm_type *mt; | 256 | int ret = -EINVAL; |
223 | int ret = 0; | ||
224 | 257 | ||
225 | if (!dev->q || !dev->ops) | 258 | if (!dev->q || !dev->ops) |
226 | return -EINVAL; | 259 | return ret; |
227 | 260 | ||
228 | if (dev->ops->identity(dev->q, &dev->identity)) { | 261 | if (dev->ops->identity(dev, &dev->identity)) { |
229 | pr_err("nvm: device could not be identified\n"); | 262 | pr_err("nvm: device could not be identified\n"); |
230 | ret = -EINVAL; | ||
231 | goto err; | 263 | goto err; |
232 | } | 264 | } |
233 | 265 | ||
@@ -251,29 +283,12 @@ static int nvm_init(struct nvm_dev *dev) | |||
251 | goto err; | 283 | goto err; |
252 | } | 284 | } |
253 | 285 | ||
254 | /* register with device with a supported manager */ | ||
255 | list_for_each_entry(mt, &nvm_mgrs, list) { | ||
256 | ret = mt->register_mgr(dev); | ||
257 | if (ret < 0) | ||
258 | goto err; /* initialization failed */ | ||
259 | if (ret > 0) { | ||
260 | dev->mt = mt; | ||
261 | break; /* successfully initialized */ | ||
262 | } | ||
263 | } | ||
264 | |||
265 | if (!ret) { | ||
266 | pr_info("nvm: no compatible manager found.\n"); | ||
267 | return 0; | ||
268 | } | ||
269 | |||
270 | pr_info("nvm: registered %s [%u/%u/%u/%u/%u/%u]\n", | 286 | pr_info("nvm: registered %s [%u/%u/%u/%u/%u/%u]\n", |
271 | dev->name, dev->sec_per_pg, dev->nr_planes, | 287 | dev->name, dev->sec_per_pg, dev->nr_planes, |
272 | dev->pgs_per_blk, dev->blks_per_lun, dev->nr_luns, | 288 | dev->pgs_per_blk, dev->blks_per_lun, dev->nr_luns, |
273 | dev->nr_chnls); | 289 | dev->nr_chnls); |
274 | return 0; | 290 | return 0; |
275 | err: | 291 | err: |
276 | nvm_free(dev); | ||
277 | pr_err("nvm: failed to initialize nvm\n"); | 292 | pr_err("nvm: failed to initialize nvm\n"); |
278 | return ret; | 293 | return ret; |
279 | } | 294 | } |
@@ -308,22 +323,27 @@ int nvm_register(struct request_queue *q, char *disk_name, | |||
308 | if (ret) | 323 | if (ret) |
309 | goto err_init; | 324 | goto err_init; |
310 | 325 | ||
311 | down_write(&nvm_lock); | 326 | if (dev->ops->max_phys_sect > 256) { |
312 | list_add(&dev->devices, &nvm_devices); | 327 | pr_info("nvm: max sectors supported is 256.\n"); |
313 | up_write(&nvm_lock); | 328 | ret = -EINVAL; |
329 | goto err_init; | ||
330 | } | ||
314 | 331 | ||
315 | if (dev->ops->max_phys_sect > 1) { | 332 | if (dev->ops->max_phys_sect > 1) { |
316 | dev->ppalist_pool = dev->ops->create_dma_pool(dev->q, | 333 | dev->ppalist_pool = dev->ops->create_dma_pool(dev, "ppalist"); |
317 | "ppalist"); | ||
318 | if (!dev->ppalist_pool) { | 334 | if (!dev->ppalist_pool) { |
319 | pr_err("nvm: could not create ppa pool\n"); | 335 | pr_err("nvm: could not create ppa pool\n"); |
320 | return -ENOMEM; | 336 | ret = -ENOMEM; |
337 | goto err_init; | ||
321 | } | 338 | } |
322 | } else if (dev->ops->max_phys_sect > 256) { | ||
323 | pr_info("nvm: max sectors supported is 256.\n"); | ||
324 | return -EINVAL; | ||
325 | } | 339 | } |
326 | 340 | ||
341 | /* register device with a supported media manager */ | ||
342 | down_write(&nvm_lock); | ||
343 | dev->mt = nvm_init_mgr(dev); | ||
344 | list_add(&dev->devices, &nvm_devices); | ||
345 | up_write(&nvm_lock); | ||
346 | |||
327 | return 0; | 347 | return 0; |
328 | err_init: | 348 | err_init: |
329 | kfree(dev); | 349 | kfree(dev); |
@@ -333,19 +353,22 @@ EXPORT_SYMBOL(nvm_register); | |||
333 | 353 | ||
334 | void nvm_unregister(char *disk_name) | 354 | void nvm_unregister(char *disk_name) |
335 | { | 355 | { |
336 | struct nvm_dev *dev = nvm_find_nvm_dev(disk_name); | 356 | struct nvm_dev *dev; |
337 | 357 | ||
358 | down_write(&nvm_lock); | ||
359 | dev = nvm_find_nvm_dev(disk_name); | ||
338 | if (!dev) { | 360 | if (!dev) { |
339 | pr_err("nvm: could not find device %s to unregister\n", | 361 | pr_err("nvm: could not find device %s to unregister\n", |
340 | disk_name); | 362 | disk_name); |
363 | up_write(&nvm_lock); | ||
341 | return; | 364 | return; |
342 | } | 365 | } |
343 | 366 | ||
344 | nvm_exit(dev); | ||
345 | |||
346 | down_write(&nvm_lock); | ||
347 | list_del(&dev->devices); | 367 | list_del(&dev->devices); |
348 | up_write(&nvm_lock); | 368 | up_write(&nvm_lock); |
369 | |||
370 | nvm_exit(dev); | ||
371 | kfree(dev); | ||
349 | } | 372 | } |
350 | EXPORT_SYMBOL(nvm_unregister); | 373 | EXPORT_SYMBOL(nvm_unregister); |
351 | 374 | ||
@@ -358,38 +381,24 @@ static int nvm_create_target(struct nvm_dev *dev, | |||
358 | { | 381 | { |
359 | struct nvm_ioctl_create_simple *s = &create->conf.s; | 382 | struct nvm_ioctl_create_simple *s = &create->conf.s; |
360 | struct request_queue *tqueue; | 383 | struct request_queue *tqueue; |
361 | struct nvmm_type *mt; | ||
362 | struct gendisk *tdisk; | 384 | struct gendisk *tdisk; |
363 | struct nvm_tgt_type *tt; | 385 | struct nvm_tgt_type *tt; |
364 | struct nvm_target *t; | 386 | struct nvm_target *t; |
365 | void *targetdata; | 387 | void *targetdata; |
366 | int ret = 0; | ||
367 | 388 | ||
368 | if (!dev->mt) { | 389 | if (!dev->mt) { |
369 | /* register with device with a supported NVM manager */ | 390 | pr_info("nvm: device has no media manager registered.\n"); |
370 | list_for_each_entry(mt, &nvm_mgrs, list) { | 391 | return -ENODEV; |
371 | ret = mt->register_mgr(dev); | ||
372 | if (ret < 0) | ||
373 | return ret; /* initialization failed */ | ||
374 | if (ret > 0) { | ||
375 | dev->mt = mt; | ||
376 | break; /* successfully initialized */ | ||
377 | } | ||
378 | } | ||
379 | |||
380 | if (!ret) { | ||
381 | pr_info("nvm: no compatible nvm manager found.\n"); | ||
382 | return -ENODEV; | ||
383 | } | ||
384 | } | 392 | } |
385 | 393 | ||
394 | down_write(&nvm_lock); | ||
386 | tt = nvm_find_target_type(create->tgttype); | 395 | tt = nvm_find_target_type(create->tgttype); |
387 | if (!tt) { | 396 | if (!tt) { |
388 | pr_err("nvm: target type %s not found\n", create->tgttype); | 397 | pr_err("nvm: target type %s not found\n", create->tgttype); |
398 | up_write(&nvm_lock); | ||
389 | return -EINVAL; | 399 | return -EINVAL; |
390 | } | 400 | } |
391 | 401 | ||
392 | down_write(&nvm_lock); | ||
393 | list_for_each_entry(t, &dev->online_targets, list) { | 402 | list_for_each_entry(t, &dev->online_targets, list) { |
394 | if (!strcmp(create->tgtname, t->disk->disk_name)) { | 403 | if (!strcmp(create->tgtname, t->disk->disk_name)) { |
395 | pr_err("nvm: target name already exists.\n"); | 404 | pr_err("nvm: target name already exists.\n"); |
@@ -457,11 +466,11 @@ static void nvm_remove_target(struct nvm_target *t) | |||
457 | lockdep_assert_held(&nvm_lock); | 466 | lockdep_assert_held(&nvm_lock); |
458 | 467 | ||
459 | del_gendisk(tdisk); | 468 | del_gendisk(tdisk); |
469 | blk_cleanup_queue(q); | ||
470 | |||
460 | if (tt->exit) | 471 | if (tt->exit) |
461 | tt->exit(tdisk->private_data); | 472 | tt->exit(tdisk->private_data); |
462 | 473 | ||
463 | blk_cleanup_queue(q); | ||
464 | |||
465 | put_disk(tdisk); | 474 | put_disk(tdisk); |
466 | 475 | ||
467 | list_del(&t->list); | 476 | list_del(&t->list); |
@@ -473,7 +482,9 @@ static int __nvm_configure_create(struct nvm_ioctl_create *create) | |||
473 | struct nvm_dev *dev; | 482 | struct nvm_dev *dev; |
474 | struct nvm_ioctl_create_simple *s; | 483 | struct nvm_ioctl_create_simple *s; |
475 | 484 | ||
485 | down_write(&nvm_lock); | ||
476 | dev = nvm_find_nvm_dev(create->dev); | 486 | dev = nvm_find_nvm_dev(create->dev); |
487 | up_write(&nvm_lock); | ||
477 | if (!dev) { | 488 | if (!dev) { |
478 | pr_err("nvm: device not found\n"); | 489 | pr_err("nvm: device not found\n"); |
479 | return -EINVAL; | 490 | return -EINVAL; |
@@ -532,7 +543,9 @@ static int nvm_configure_show(const char *val) | |||
532 | return -EINVAL; | 543 | return -EINVAL; |
533 | } | 544 | } |
534 | 545 | ||
546 | down_write(&nvm_lock); | ||
535 | dev = nvm_find_nvm_dev(devname); | 547 | dev = nvm_find_nvm_dev(devname); |
548 | up_write(&nvm_lock); | ||
536 | if (!dev) { | 549 | if (!dev) { |
537 | pr_err("nvm: device not found\n"); | 550 | pr_err("nvm: device not found\n"); |
538 | return -EINVAL; | 551 | return -EINVAL; |
@@ -541,7 +554,7 @@ static int nvm_configure_show(const char *val) | |||
541 | if (!dev->mt) | 554 | if (!dev->mt) |
542 | return 0; | 555 | return 0; |
543 | 556 | ||
544 | dev->mt->free_blocks_print(dev); | 557 | dev->mt->lun_info_print(dev); |
545 | 558 | ||
546 | return 0; | 559 | return 0; |
547 | } | 560 | } |
@@ -677,8 +690,10 @@ static long nvm_ioctl_info(struct file *file, void __user *arg) | |||
677 | info->tgtsize = tgt_iter; | 690 | info->tgtsize = tgt_iter; |
678 | up_write(&nvm_lock); | 691 | up_write(&nvm_lock); |
679 | 692 | ||
680 | if (copy_to_user(arg, info, sizeof(struct nvm_ioctl_info))) | 693 | if (copy_to_user(arg, info, sizeof(struct nvm_ioctl_info))) { |
694 | kfree(info); | ||
681 | return -EFAULT; | 695 | return -EFAULT; |
696 | } | ||
682 | 697 | ||
683 | kfree(info); | 698 | kfree(info); |
684 | return 0; | 699 | return 0; |
@@ -721,8 +736,11 @@ static long nvm_ioctl_get_devices(struct file *file, void __user *arg) | |||
721 | 736 | ||
722 | devices->nr_devices = i; | 737 | devices->nr_devices = i; |
723 | 738 | ||
724 | if (copy_to_user(arg, devices, sizeof(struct nvm_ioctl_get_devices))) | 739 | if (copy_to_user(arg, devices, |
740 | sizeof(struct nvm_ioctl_get_devices))) { | ||
741 | kfree(devices); | ||
725 | return -EFAULT; | 742 | return -EFAULT; |
743 | } | ||
726 | 744 | ||
727 | kfree(devices); | 745 | kfree(devices); |
728 | return 0; | 746 | return 0; |
diff --git a/drivers/lightnvm/gennvm.c b/drivers/lightnvm/gennvm.c index ae1fb2bdc5f4..f434e89e1c7a 100644 --- a/drivers/lightnvm/gennvm.c +++ b/drivers/lightnvm/gennvm.c | |||
@@ -60,23 +60,27 @@ static int gennvm_luns_init(struct nvm_dev *dev, struct gen_nvm *gn) | |||
60 | lun->vlun.lun_id = i % dev->luns_per_chnl; | 60 | lun->vlun.lun_id = i % dev->luns_per_chnl; |
61 | lun->vlun.chnl_id = i / dev->luns_per_chnl; | 61 | lun->vlun.chnl_id = i / dev->luns_per_chnl; |
62 | lun->vlun.nr_free_blocks = dev->blks_per_lun; | 62 | lun->vlun.nr_free_blocks = dev->blks_per_lun; |
63 | lun->vlun.nr_inuse_blocks = 0; | ||
64 | lun->vlun.nr_bad_blocks = 0; | ||
63 | } | 65 | } |
64 | return 0; | 66 | return 0; |
65 | } | 67 | } |
66 | 68 | ||
67 | static int gennvm_block_bb(u32 lun_id, void *bb_bitmap, unsigned int nr_blocks, | 69 | static int gennvm_block_bb(struct ppa_addr ppa, int nr_blocks, u8 *blks, |
68 | void *private) | 70 | void *private) |
69 | { | 71 | { |
70 | struct gen_nvm *gn = private; | 72 | struct gen_nvm *gn = private; |
71 | struct gen_lun *lun = &gn->luns[lun_id]; | 73 | struct nvm_dev *dev = gn->dev; |
74 | struct gen_lun *lun; | ||
72 | struct nvm_block *blk; | 75 | struct nvm_block *blk; |
73 | int i; | 76 | int i; |
74 | 77 | ||
75 | if (unlikely(bitmap_empty(bb_bitmap, nr_blocks))) | 78 | lun = &gn->luns[(dev->nr_luns * ppa.g.ch) + ppa.g.lun]; |
76 | return 0; | 79 | |
80 | for (i = 0; i < nr_blocks; i++) { | ||
81 | if (blks[i] == 0) | ||
82 | continue; | ||
77 | 83 | ||
78 | i = -1; | ||
79 | while ((i = find_next_bit(bb_bitmap, nr_blocks, i + 1)) < nr_blocks) { | ||
80 | blk = &lun->vlun.blocks[i]; | 84 | blk = &lun->vlun.blocks[i]; |
81 | if (!blk) { | 85 | if (!blk) { |
82 | pr_err("gennvm: BB data is out of bounds.\n"); | 86 | pr_err("gennvm: BB data is out of bounds.\n"); |
@@ -84,6 +88,7 @@ static int gennvm_block_bb(u32 lun_id, void *bb_bitmap, unsigned int nr_blocks, | |||
84 | } | 88 | } |
85 | 89 | ||
86 | list_move_tail(&blk->list, &lun->bb_list); | 90 | list_move_tail(&blk->list, &lun->bb_list); |
91 | lun->vlun.nr_bad_blocks++; | ||
87 | } | 92 | } |
88 | 93 | ||
89 | return 0; | 94 | return 0; |
@@ -136,6 +141,7 @@ static int gennvm_block_map(u64 slba, u32 nlb, __le64 *entries, void *private) | |||
136 | list_move_tail(&blk->list, &lun->used_list); | 141 | list_move_tail(&blk->list, &lun->used_list); |
137 | blk->type = 1; | 142 | blk->type = 1; |
138 | lun->vlun.nr_free_blocks--; | 143 | lun->vlun.nr_free_blocks--; |
144 | lun->vlun.nr_inuse_blocks++; | ||
139 | } | 145 | } |
140 | } | 146 | } |
141 | 147 | ||
@@ -164,22 +170,32 @@ static int gennvm_blocks_init(struct nvm_dev *dev, struct gen_nvm *gn) | |||
164 | block->id = cur_block_id++; | 170 | block->id = cur_block_id++; |
165 | 171 | ||
166 | /* First block is reserved for device */ | 172 | /* First block is reserved for device */ |
167 | if (unlikely(lun_iter == 0 && blk_iter == 0)) | 173 | if (unlikely(lun_iter == 0 && blk_iter == 0)) { |
174 | lun->vlun.nr_free_blocks--; | ||
168 | continue; | 175 | continue; |
176 | } | ||
169 | 177 | ||
170 | list_add_tail(&block->list, &lun->free_list); | 178 | list_add_tail(&block->list, &lun->free_list); |
171 | } | 179 | } |
172 | 180 | ||
173 | if (dev->ops->get_bb_tbl) { | 181 | if (dev->ops->get_bb_tbl) { |
174 | ret = dev->ops->get_bb_tbl(dev->q, lun->vlun.id, | 182 | struct ppa_addr ppa; |
175 | dev->blks_per_lun, gennvm_block_bb, gn); | 183 | |
184 | ppa.ppa = 0; | ||
185 | ppa.g.ch = lun->vlun.chnl_id; | ||
186 | ppa.g.lun = lun->vlun.id; | ||
187 | ppa = generic_to_dev_addr(dev, ppa); | ||
188 | |||
189 | ret = dev->ops->get_bb_tbl(dev, ppa, | ||
190 | dev->blks_per_lun, | ||
191 | gennvm_block_bb, gn); | ||
176 | if (ret) | 192 | if (ret) |
177 | pr_err("gennvm: could not read BB table\n"); | 193 | pr_err("gennvm: could not read BB table\n"); |
178 | } | 194 | } |
179 | } | 195 | } |
180 | 196 | ||
181 | if (dev->ops->get_l2p_tbl) { | 197 | if (dev->ops->get_l2p_tbl) { |
182 | ret = dev->ops->get_l2p_tbl(dev->q, 0, dev->total_pages, | 198 | ret = dev->ops->get_l2p_tbl(dev, 0, dev->total_pages, |
183 | gennvm_block_map, dev); | 199 | gennvm_block_map, dev); |
184 | if (ret) { | 200 | if (ret) { |
185 | pr_err("gennvm: could not read L2P table.\n"); | 201 | pr_err("gennvm: could not read L2P table.\n"); |
@@ -190,15 +206,27 @@ static int gennvm_blocks_init(struct nvm_dev *dev, struct gen_nvm *gn) | |||
190 | return 0; | 206 | return 0; |
191 | } | 207 | } |
192 | 208 | ||
209 | static void gennvm_free(struct nvm_dev *dev) | ||
210 | { | ||
211 | gennvm_blocks_free(dev); | ||
212 | gennvm_luns_free(dev); | ||
213 | kfree(dev->mp); | ||
214 | dev->mp = NULL; | ||
215 | } | ||
216 | |||
193 | static int gennvm_register(struct nvm_dev *dev) | 217 | static int gennvm_register(struct nvm_dev *dev) |
194 | { | 218 | { |
195 | struct gen_nvm *gn; | 219 | struct gen_nvm *gn; |
196 | int ret; | 220 | int ret; |
197 | 221 | ||
222 | if (!try_module_get(THIS_MODULE)) | ||
223 | return -ENODEV; | ||
224 | |||
198 | gn = kzalloc(sizeof(struct gen_nvm), GFP_KERNEL); | 225 | gn = kzalloc(sizeof(struct gen_nvm), GFP_KERNEL); |
199 | if (!gn) | 226 | if (!gn) |
200 | return -ENOMEM; | 227 | return -ENOMEM; |
201 | 228 | ||
229 | gn->dev = dev; | ||
202 | gn->nr_luns = dev->nr_luns; | 230 | gn->nr_luns = dev->nr_luns; |
203 | dev->mp = gn; | 231 | dev->mp = gn; |
204 | 232 | ||
@@ -216,16 +244,15 @@ static int gennvm_register(struct nvm_dev *dev) | |||
216 | 244 | ||
217 | return 1; | 245 | return 1; |
218 | err: | 246 | err: |
219 | kfree(gn); | 247 | gennvm_free(dev); |
248 | module_put(THIS_MODULE); | ||
220 | return ret; | 249 | return ret; |
221 | } | 250 | } |
222 | 251 | ||
223 | static void gennvm_unregister(struct nvm_dev *dev) | 252 | static void gennvm_unregister(struct nvm_dev *dev) |
224 | { | 253 | { |
225 | gennvm_blocks_free(dev); | 254 | gennvm_free(dev); |
226 | gennvm_luns_free(dev); | 255 | module_put(THIS_MODULE); |
227 | kfree(dev->mp); | ||
228 | dev->mp = NULL; | ||
229 | } | 256 | } |
230 | 257 | ||
231 | static struct nvm_block *gennvm_get_blk(struct nvm_dev *dev, | 258 | static struct nvm_block *gennvm_get_blk(struct nvm_dev *dev, |
@@ -240,23 +267,21 @@ static struct nvm_block *gennvm_get_blk(struct nvm_dev *dev, | |||
240 | if (list_empty(&lun->free_list)) { | 267 | if (list_empty(&lun->free_list)) { |
241 | pr_err_ratelimited("gennvm: lun %u have no free pages available", | 268 | pr_err_ratelimited("gennvm: lun %u have no free pages available", |
242 | lun->vlun.id); | 269 | lun->vlun.id); |
243 | spin_unlock(&vlun->lock); | ||
244 | goto out; | 270 | goto out; |
245 | } | 271 | } |
246 | 272 | ||
247 | while (!is_gc && lun->vlun.nr_free_blocks < lun->reserved_blocks) { | 273 | if (!is_gc && lun->vlun.nr_free_blocks < lun->reserved_blocks) |
248 | spin_unlock(&vlun->lock); | ||
249 | goto out; | 274 | goto out; |
250 | } | ||
251 | 275 | ||
252 | blk = list_first_entry(&lun->free_list, struct nvm_block, list); | 276 | blk = list_first_entry(&lun->free_list, struct nvm_block, list); |
253 | list_move_tail(&blk->list, &lun->used_list); | 277 | list_move_tail(&blk->list, &lun->used_list); |
254 | blk->type = 1; | 278 | blk->type = 1; |
255 | 279 | ||
256 | lun->vlun.nr_free_blocks--; | 280 | lun->vlun.nr_free_blocks--; |
281 | lun->vlun.nr_inuse_blocks++; | ||
257 | 282 | ||
258 | spin_unlock(&vlun->lock); | ||
259 | out: | 283 | out: |
284 | spin_unlock(&vlun->lock); | ||
260 | return blk; | 285 | return blk; |
261 | } | 286 | } |
262 | 287 | ||
@@ -271,16 +296,21 @@ static void gennvm_put_blk(struct nvm_dev *dev, struct nvm_block *blk) | |||
271 | case 1: | 296 | case 1: |
272 | list_move_tail(&blk->list, &lun->free_list); | 297 | list_move_tail(&blk->list, &lun->free_list); |
273 | lun->vlun.nr_free_blocks++; | 298 | lun->vlun.nr_free_blocks++; |
299 | lun->vlun.nr_inuse_blocks--; | ||
274 | blk->type = 0; | 300 | blk->type = 0; |
275 | break; | 301 | break; |
276 | case 2: | 302 | case 2: |
277 | list_move_tail(&blk->list, &lun->bb_list); | 303 | list_move_tail(&blk->list, &lun->bb_list); |
304 | lun->vlun.nr_bad_blocks++; | ||
305 | lun->vlun.nr_inuse_blocks--; | ||
278 | break; | 306 | break; |
279 | default: | 307 | default: |
280 | WARN_ON_ONCE(1); | 308 | WARN_ON_ONCE(1); |
281 | pr_err("gennvm: erroneous block type (%lu -> %u)\n", | 309 | pr_err("gennvm: erroneous block type (%lu -> %u)\n", |
282 | blk->id, blk->type); | 310 | blk->id, blk->type); |
283 | list_move_tail(&blk->list, &lun->bb_list); | 311 | list_move_tail(&blk->list, &lun->bb_list); |
312 | lun->vlun.nr_bad_blocks++; | ||
313 | lun->vlun.nr_inuse_blocks--; | ||
284 | } | 314 | } |
285 | 315 | ||
286 | spin_unlock(&vlun->lock); | 316 | spin_unlock(&vlun->lock); |
@@ -292,10 +322,10 @@ static void gennvm_addr_to_generic_mode(struct nvm_dev *dev, struct nvm_rq *rqd) | |||
292 | 322 | ||
293 | if (rqd->nr_pages > 1) { | 323 | if (rqd->nr_pages > 1) { |
294 | for (i = 0; i < rqd->nr_pages; i++) | 324 | for (i = 0; i < rqd->nr_pages; i++) |
295 | rqd->ppa_list[i] = addr_to_generic_mode(dev, | 325 | rqd->ppa_list[i] = dev_to_generic_addr(dev, |
296 | rqd->ppa_list[i]); | 326 | rqd->ppa_list[i]); |
297 | } else { | 327 | } else { |
298 | rqd->ppa_addr = addr_to_generic_mode(dev, rqd->ppa_addr); | 328 | rqd->ppa_addr = dev_to_generic_addr(dev, rqd->ppa_addr); |
299 | } | 329 | } |
300 | } | 330 | } |
301 | 331 | ||
@@ -305,10 +335,10 @@ static void gennvm_generic_to_addr_mode(struct nvm_dev *dev, struct nvm_rq *rqd) | |||
305 | 335 | ||
306 | if (rqd->nr_pages > 1) { | 336 | if (rqd->nr_pages > 1) { |
307 | for (i = 0; i < rqd->nr_pages; i++) | 337 | for (i = 0; i < rqd->nr_pages; i++) |
308 | rqd->ppa_list[i] = generic_to_addr_mode(dev, | 338 | rqd->ppa_list[i] = generic_to_dev_addr(dev, |
309 | rqd->ppa_list[i]); | 339 | rqd->ppa_list[i]); |
310 | } else { | 340 | } else { |
311 | rqd->ppa_addr = generic_to_addr_mode(dev, rqd->ppa_addr); | 341 | rqd->ppa_addr = generic_to_dev_addr(dev, rqd->ppa_addr); |
312 | } | 342 | } |
313 | } | 343 | } |
314 | 344 | ||
@@ -321,7 +351,7 @@ static int gennvm_submit_io(struct nvm_dev *dev, struct nvm_rq *rqd) | |||
321 | gennvm_generic_to_addr_mode(dev, rqd); | 351 | gennvm_generic_to_addr_mode(dev, rqd); |
322 | 352 | ||
323 | rqd->dev = dev; | 353 | rqd->dev = dev; |
324 | return dev->ops->submit_io(dev->q, rqd); | 354 | return dev->ops->submit_io(dev, rqd); |
325 | } | 355 | } |
326 | 356 | ||
327 | static void gennvm_blk_set_type(struct nvm_dev *dev, struct ppa_addr *ppa, | 357 | static void gennvm_blk_set_type(struct nvm_dev *dev, struct ppa_addr *ppa, |
@@ -354,10 +384,10 @@ static void gennvm_mark_blk_bad(struct nvm_dev *dev, struct nvm_rq *rqd) | |||
354 | { | 384 | { |
355 | int i; | 385 | int i; |
356 | 386 | ||
357 | if (!dev->ops->set_bb) | 387 | if (!dev->ops->set_bb_tbl) |
358 | return; | 388 | return; |
359 | 389 | ||
360 | if (dev->ops->set_bb(dev->q, rqd, 1)) | 390 | if (dev->ops->set_bb_tbl(dev, rqd, 1)) |
361 | return; | 391 | return; |
362 | 392 | ||
363 | gennvm_addr_to_generic_mode(dev, rqd); | 393 | gennvm_addr_to_generic_mode(dev, rqd); |
@@ -425,7 +455,7 @@ static int gennvm_erase_blk(struct nvm_dev *dev, struct nvm_block *blk, | |||
425 | 455 | ||
426 | gennvm_generic_to_addr_mode(dev, &rqd); | 456 | gennvm_generic_to_addr_mode(dev, &rqd); |
427 | 457 | ||
428 | ret = dev->ops->erase_block(dev->q, &rqd); | 458 | ret = dev->ops->erase_block(dev, &rqd); |
429 | 459 | ||
430 | if (plane_cnt) | 460 | if (plane_cnt) |
431 | nvm_dev_dma_free(dev, rqd.ppa_list, rqd.dma_ppa_list); | 461 | nvm_dev_dma_free(dev, rqd.ppa_list, rqd.dma_ppa_list); |
@@ -440,15 +470,24 @@ static struct nvm_lun *gennvm_get_lun(struct nvm_dev *dev, int lunid) | |||
440 | return &gn->luns[lunid].vlun; | 470 | return &gn->luns[lunid].vlun; |
441 | } | 471 | } |
442 | 472 | ||
443 | static void gennvm_free_blocks_print(struct nvm_dev *dev) | 473 | static void gennvm_lun_info_print(struct nvm_dev *dev) |
444 | { | 474 | { |
445 | struct gen_nvm *gn = dev->mp; | 475 | struct gen_nvm *gn = dev->mp; |
446 | struct gen_lun *lun; | 476 | struct gen_lun *lun; |
447 | unsigned int i; | 477 | unsigned int i; |
448 | 478 | ||
449 | gennvm_for_each_lun(gn, lun, i) | 479 | |
450 | pr_info("%s: lun%8u\t%u\n", | 480 | gennvm_for_each_lun(gn, lun, i) { |
451 | dev->name, i, lun->vlun.nr_free_blocks); | 481 | spin_lock(&lun->vlun.lock); |
482 | |||
483 | pr_info("%s: lun%8u\t%u\t%u\t%u\n", | ||
484 | dev->name, i, | ||
485 | lun->vlun.nr_free_blocks, | ||
486 | lun->vlun.nr_inuse_blocks, | ||
487 | lun->vlun.nr_bad_blocks); | ||
488 | |||
489 | spin_unlock(&lun->vlun.lock); | ||
490 | } | ||
452 | } | 491 | } |
453 | 492 | ||
454 | static struct nvmm_type gennvm = { | 493 | static struct nvmm_type gennvm = { |
@@ -466,7 +505,7 @@ static struct nvmm_type gennvm = { | |||
466 | .erase_blk = gennvm_erase_blk, | 505 | .erase_blk = gennvm_erase_blk, |
467 | 506 | ||
468 | .get_lun = gennvm_get_lun, | 507 | .get_lun = gennvm_get_lun, |
469 | .free_blocks_print = gennvm_free_blocks_print, | 508 | .lun_info_print = gennvm_lun_info_print, |
470 | }; | 509 | }; |
471 | 510 | ||
472 | static int __init gennvm_module_init(void) | 511 | static int __init gennvm_module_init(void) |
diff --git a/drivers/lightnvm/gennvm.h b/drivers/lightnvm/gennvm.h index d23bd3501ddc..9c24b5b32dac 100644 --- a/drivers/lightnvm/gennvm.h +++ b/drivers/lightnvm/gennvm.h | |||
@@ -35,6 +35,8 @@ struct gen_lun { | |||
35 | }; | 35 | }; |
36 | 36 | ||
37 | struct gen_nvm { | 37 | struct gen_nvm { |
38 | struct nvm_dev *dev; | ||
39 | |||
38 | int nr_luns; | 40 | int nr_luns; |
39 | struct gen_lun *luns; | 41 | struct gen_lun *luns; |
40 | }; | 42 | }; |
diff --git a/drivers/lightnvm/rrpc.c b/drivers/lightnvm/rrpc.c index 7ba64c87ba1c..134e4faba482 100644 --- a/drivers/lightnvm/rrpc.c +++ b/drivers/lightnvm/rrpc.c | |||
@@ -123,12 +123,42 @@ static u64 block_to_addr(struct rrpc *rrpc, struct rrpc_block *rblk) | |||
123 | return blk->id * rrpc->dev->pgs_per_blk; | 123 | return blk->id * rrpc->dev->pgs_per_blk; |
124 | } | 124 | } |
125 | 125 | ||
126 | static struct ppa_addr linear_to_generic_addr(struct nvm_dev *dev, | ||
127 | struct ppa_addr r) | ||
128 | { | ||
129 | struct ppa_addr l; | ||
130 | int secs, pgs, blks, luns; | ||
131 | sector_t ppa = r.ppa; | ||
132 | |||
133 | l.ppa = 0; | ||
134 | |||
135 | div_u64_rem(ppa, dev->sec_per_pg, &secs); | ||
136 | l.g.sec = secs; | ||
137 | |||
138 | sector_div(ppa, dev->sec_per_pg); | ||
139 | div_u64_rem(ppa, dev->sec_per_blk, &pgs); | ||
140 | l.g.pg = pgs; | ||
141 | |||
142 | sector_div(ppa, dev->pgs_per_blk); | ||
143 | div_u64_rem(ppa, dev->blks_per_lun, &blks); | ||
144 | l.g.blk = blks; | ||
145 | |||
146 | sector_div(ppa, dev->blks_per_lun); | ||
147 | div_u64_rem(ppa, dev->luns_per_chnl, &luns); | ||
148 | l.g.lun = luns; | ||
149 | |||
150 | sector_div(ppa, dev->luns_per_chnl); | ||
151 | l.g.ch = ppa; | ||
152 | |||
153 | return l; | ||
154 | } | ||
155 | |||
126 | static struct ppa_addr rrpc_ppa_to_gaddr(struct nvm_dev *dev, u64 addr) | 156 | static struct ppa_addr rrpc_ppa_to_gaddr(struct nvm_dev *dev, u64 addr) |
127 | { | 157 | { |
128 | struct ppa_addr paddr; | 158 | struct ppa_addr paddr; |
129 | 159 | ||
130 | paddr.ppa = addr; | 160 | paddr.ppa = addr; |
131 | return __linear_to_generic_addr(dev, paddr); | 161 | return linear_to_generic_addr(dev, paddr); |
132 | } | 162 | } |
133 | 163 | ||
134 | /* requires lun->lock taken */ | 164 | /* requires lun->lock taken */ |
@@ -152,7 +182,7 @@ static struct rrpc_block *rrpc_get_blk(struct rrpc *rrpc, struct rrpc_lun *rlun, | |||
152 | struct nvm_block *blk; | 182 | struct nvm_block *blk; |
153 | struct rrpc_block *rblk; | 183 | struct rrpc_block *rblk; |
154 | 184 | ||
155 | blk = nvm_get_blk(rrpc->dev, rlun->parent, 0); | 185 | blk = nvm_get_blk(rrpc->dev, rlun->parent, flags); |
156 | if (!blk) | 186 | if (!blk) |
157 | return NULL; | 187 | return NULL; |
158 | 188 | ||
@@ -172,6 +202,20 @@ static void rrpc_put_blk(struct rrpc *rrpc, struct rrpc_block *rblk) | |||
172 | nvm_put_blk(rrpc->dev, rblk->parent); | 202 | nvm_put_blk(rrpc->dev, rblk->parent); |
173 | } | 203 | } |
174 | 204 | ||
205 | static void rrpc_put_blks(struct rrpc *rrpc) | ||
206 | { | ||
207 | struct rrpc_lun *rlun; | ||
208 | int i; | ||
209 | |||
210 | for (i = 0; i < rrpc->nr_luns; i++) { | ||
211 | rlun = &rrpc->luns[i]; | ||
212 | if (rlun->cur) | ||
213 | rrpc_put_blk(rrpc, rlun->cur); | ||
214 | if (rlun->gc_cur) | ||
215 | rrpc_put_blk(rrpc, rlun->gc_cur); | ||
216 | } | ||
217 | } | ||
218 | |||
175 | static struct rrpc_lun *get_next_lun(struct rrpc *rrpc) | 219 | static struct rrpc_lun *get_next_lun(struct rrpc *rrpc) |
176 | { | 220 | { |
177 | int next = atomic_inc_return(&rrpc->next_lun); | 221 | int next = atomic_inc_return(&rrpc->next_lun); |
@@ -972,7 +1016,7 @@ static int rrpc_map_init(struct rrpc *rrpc) | |||
972 | return 0; | 1016 | return 0; |
973 | 1017 | ||
974 | /* Bring up the mapping table from device */ | 1018 | /* Bring up the mapping table from device */ |
975 | ret = dev->ops->get_l2p_tbl(dev->q, 0, dev->total_pages, | 1019 | ret = dev->ops->get_l2p_tbl(dev, 0, dev->total_pages, |
976 | rrpc_l2p_update, rrpc); | 1020 | rrpc_l2p_update, rrpc); |
977 | if (ret) { | 1021 | if (ret) { |
978 | pr_err("nvm: rrpc: could not read L2P table.\n"); | 1022 | pr_err("nvm: rrpc: could not read L2P table.\n"); |
@@ -1194,18 +1238,21 @@ static int rrpc_luns_configure(struct rrpc *rrpc) | |||
1194 | 1238 | ||
1195 | rblk = rrpc_get_blk(rrpc, rlun, 0); | 1239 | rblk = rrpc_get_blk(rrpc, rlun, 0); |
1196 | if (!rblk) | 1240 | if (!rblk) |
1197 | return -EINVAL; | 1241 | goto err; |
1198 | 1242 | ||
1199 | rrpc_set_lun_cur(rlun, rblk); | 1243 | rrpc_set_lun_cur(rlun, rblk); |
1200 | 1244 | ||
1201 | /* Emergency gc block */ | 1245 | /* Emergency gc block */ |
1202 | rblk = rrpc_get_blk(rrpc, rlun, 1); | 1246 | rblk = rrpc_get_blk(rrpc, rlun, 1); |
1203 | if (!rblk) | 1247 | if (!rblk) |
1204 | return -EINVAL; | 1248 | goto err; |
1205 | rlun->gc_cur = rblk; | 1249 | rlun->gc_cur = rblk; |
1206 | } | 1250 | } |
1207 | 1251 | ||
1208 | return 0; | 1252 | return 0; |
1253 | err: | ||
1254 | rrpc_put_blks(rrpc); | ||
1255 | return -EINVAL; | ||
1209 | } | 1256 | } |
1210 | 1257 | ||
1211 | static struct nvm_tgt_type tt_rrpc; | 1258 | static struct nvm_tgt_type tt_rrpc; |