diff options
-rw-r--r-- | drivers/lightnvm/core.c | 1 | ||||
-rw-r--r-- | drivers/lightnvm/gennvm.c | 67 | ||||
-rw-r--r-- | drivers/lightnvm/gennvm.h | 6 | ||||
-rw-r--r-- | drivers/lightnvm/rrpc.c | 35 | ||||
-rw-r--r-- | drivers/lightnvm/rrpc.h | 1 | ||||
-rw-r--r-- | include/linux/lightnvm.h | 8 |
6 files changed, 116 insertions, 2 deletions
diff --git a/drivers/lightnvm/core.c b/drivers/lightnvm/core.c index 0d1fb6b40c46..2925fd0b82bb 100644 --- a/drivers/lightnvm/core.c +++ b/drivers/lightnvm/core.c | |||
@@ -466,6 +466,7 @@ static int nvm_core_init(struct nvm_dev *dev) | |||
466 | dev->total_secs = dev->nr_luns * dev->sec_per_lun; | 466 | dev->total_secs = dev->nr_luns * dev->sec_per_lun; |
467 | INIT_LIST_HEAD(&dev->online_targets); | 467 | INIT_LIST_HEAD(&dev->online_targets); |
468 | mutex_init(&dev->mlock); | 468 | mutex_init(&dev->mlock); |
469 | spin_lock_init(&dev->lock); | ||
469 | 470 | ||
470 | return 0; | 471 | return 0; |
471 | } | 472 | } |
diff --git a/drivers/lightnvm/gennvm.c b/drivers/lightnvm/gennvm.c index d65ec36a2231..d460b37bb016 100644 --- a/drivers/lightnvm/gennvm.c +++ b/drivers/lightnvm/gennvm.c | |||
@@ -20,6 +20,68 @@ | |||
20 | 20 | ||
21 | #include "gennvm.h" | 21 | #include "gennvm.h" |
22 | 22 | ||
23 | static int gennvm_get_area(struct nvm_dev *dev, sector_t *lba, sector_t len) | ||
24 | { | ||
25 | struct gen_nvm *gn = dev->mp; | ||
26 | struct gennvm_area *area, *prev, *next; | ||
27 | sector_t begin = 0; | ||
28 | sector_t max_sectors = (dev->sec_size * dev->total_secs) >> 9; | ||
29 | |||
30 | if (len > max_sectors) | ||
31 | return -EINVAL; | ||
32 | |||
33 | area = kmalloc(sizeof(struct gennvm_area), GFP_KERNEL); | ||
34 | if (!area) | ||
35 | return -ENOMEM; | ||
36 | |||
37 | prev = NULL; | ||
38 | |||
39 | spin_lock(&dev->lock); | ||
40 | list_for_each_entry(next, &gn->area_list, list) { | ||
41 | if (begin + len > next->begin) { | ||
42 | begin = next->end; | ||
43 | prev = next; | ||
44 | continue; | ||
45 | } | ||
46 | break; | ||
47 | } | ||
48 | |||
49 | if ((begin + len) > max_sectors) { | ||
50 | spin_unlock(&dev->lock); | ||
51 | kfree(area); | ||
52 | return -EINVAL; | ||
53 | } | ||
54 | |||
55 | area->begin = *lba = begin; | ||
56 | area->end = begin + len; | ||
57 | |||
58 | if (prev) /* insert into sorted order */ | ||
59 | list_add(&area->list, &prev->list); | ||
60 | else | ||
61 | list_add(&area->list, &gn->area_list); | ||
62 | spin_unlock(&dev->lock); | ||
63 | |||
64 | return 0; | ||
65 | } | ||
66 | |||
67 | static void gennvm_put_area(struct nvm_dev *dev, sector_t begin) | ||
68 | { | ||
69 | struct gen_nvm *gn = dev->mp; | ||
70 | struct gennvm_area *area; | ||
71 | |||
72 | spin_lock(&dev->lock); | ||
73 | list_for_each_entry(area, &gn->area_list, list) { | ||
74 | if (area->begin != begin) | ||
75 | continue; | ||
76 | |||
77 | list_del(&area->list); | ||
78 | spin_unlock(&dev->lock); | ||
79 | kfree(area); | ||
80 | return; | ||
81 | } | ||
82 | spin_unlock(&dev->lock); | ||
83 | } | ||
84 | |||
23 | static void gennvm_blocks_free(struct nvm_dev *dev) | 85 | static void gennvm_blocks_free(struct nvm_dev *dev) |
24 | { | 86 | { |
25 | struct gen_nvm *gn = dev->mp; | 87 | struct gen_nvm *gn = dev->mp; |
@@ -229,6 +291,7 @@ static int gennvm_register(struct nvm_dev *dev) | |||
229 | 291 | ||
230 | gn->dev = dev; | 292 | gn->dev = dev; |
231 | gn->nr_luns = dev->nr_luns; | 293 | gn->nr_luns = dev->nr_luns; |
294 | INIT_LIST_HEAD(&gn->area_list); | ||
232 | dev->mp = gn; | 295 | dev->mp = gn; |
233 | 296 | ||
234 | ret = gennvm_luns_init(dev, gn); | 297 | ret = gennvm_luns_init(dev, gn); |
@@ -465,6 +528,10 @@ static struct nvmm_type gennvm = { | |||
465 | 528 | ||
466 | .get_lun = gennvm_get_lun, | 529 | .get_lun = gennvm_get_lun, |
467 | .lun_info_print = gennvm_lun_info_print, | 530 | .lun_info_print = gennvm_lun_info_print, |
531 | |||
532 | .get_area = gennvm_get_area, | ||
533 | .put_area = gennvm_put_area, | ||
534 | |||
468 | }; | 535 | }; |
469 | 536 | ||
470 | static int __init gennvm_module_init(void) | 537 | static int __init gennvm_module_init(void) |
diff --git a/drivers/lightnvm/gennvm.h b/drivers/lightnvm/gennvm.h index 9c24b5b32dac..04d7c23cfc61 100644 --- a/drivers/lightnvm/gennvm.h +++ b/drivers/lightnvm/gennvm.h | |||
@@ -39,8 +39,14 @@ struct gen_nvm { | |||
39 | 39 | ||
40 | int nr_luns; | 40 | int nr_luns; |
41 | struct gen_lun *luns; | 41 | struct gen_lun *luns; |
42 | struct list_head area_list; | ||
42 | }; | 43 | }; |
43 | 44 | ||
45 | struct gennvm_area { | ||
46 | struct list_head list; | ||
47 | sector_t begin; | ||
48 | sector_t end; /* end is excluded */ | ||
49 | }; | ||
44 | #define gennvm_for_each_lun(bm, lun, i) \ | 50 | #define gennvm_for_each_lun(bm, lun, i) \ |
45 | for ((i) = 0, lun = &(bm)->luns[0]; \ | 51 | for ((i) = 0, lun = &(bm)->luns[0]; \ |
46 | (i) < (bm)->nr_luns; (i)++, lun = &(bm)->luns[(i)]) | 52 | (i) < (bm)->nr_luns; (i)++, lun = &(bm)->luns[(i)]) |
diff --git a/drivers/lightnvm/rrpc.c b/drivers/lightnvm/rrpc.c index 82343783aa47..c1e3c83f06b3 100644 --- a/drivers/lightnvm/rrpc.c +++ b/drivers/lightnvm/rrpc.c | |||
@@ -1053,8 +1053,11 @@ static int rrpc_map_init(struct rrpc *rrpc) | |||
1053 | { | 1053 | { |
1054 | struct nvm_dev *dev = rrpc->dev; | 1054 | struct nvm_dev *dev = rrpc->dev; |
1055 | sector_t i; | 1055 | sector_t i; |
1056 | u64 slba; | ||
1056 | int ret; | 1057 | int ret; |
1057 | 1058 | ||
1059 | slba = rrpc->soffset >> (ilog2(dev->sec_size) - 9); | ||
1060 | |||
1058 | rrpc->trans_map = vzalloc(sizeof(struct rrpc_addr) * rrpc->nr_sects); | 1061 | rrpc->trans_map = vzalloc(sizeof(struct rrpc_addr) * rrpc->nr_sects); |
1059 | if (!rrpc->trans_map) | 1062 | if (!rrpc->trans_map) |
1060 | return -ENOMEM; | 1063 | return -ENOMEM; |
@@ -1076,7 +1079,7 @@ static int rrpc_map_init(struct rrpc *rrpc) | |||
1076 | return 0; | 1079 | return 0; |
1077 | 1080 | ||
1078 | /* Bring up the mapping table from device */ | 1081 | /* Bring up the mapping table from device */ |
1079 | ret = dev->ops->get_l2p_tbl(dev, 0, dev->total_secs, rrpc_l2p_update, | 1082 | ret = dev->ops->get_l2p_tbl(dev, slba, rrpc->nr_sects, rrpc_l2p_update, |
1080 | rrpc); | 1083 | rrpc); |
1081 | if (ret) { | 1084 | if (ret) { |
1082 | pr_err("nvm: rrpc: could not read L2P table.\n"); | 1085 | pr_err("nvm: rrpc: could not read L2P table.\n"); |
@@ -1086,7 +1089,6 @@ static int rrpc_map_init(struct rrpc *rrpc) | |||
1086 | return 0; | 1089 | return 0; |
1087 | } | 1090 | } |
1088 | 1091 | ||
1089 | |||
1090 | /* Minimum pages needed within a lun */ | 1092 | /* Minimum pages needed within a lun */ |
1091 | #define PAGE_POOL_SIZE 16 | 1093 | #define PAGE_POOL_SIZE 16 |
1092 | #define ADDR_POOL_SIZE 64 | 1094 | #define ADDR_POOL_SIZE 64 |
@@ -1200,12 +1202,33 @@ err: | |||
1200 | return -ENOMEM; | 1202 | return -ENOMEM; |
1201 | } | 1203 | } |
1202 | 1204 | ||
1205 | /* returns 0 on success and stores the beginning address in *begin */ | ||
1206 | static int rrpc_area_init(struct rrpc *rrpc, sector_t *begin) | ||
1207 | { | ||
1208 | struct nvm_dev *dev = rrpc->dev; | ||
1209 | struct nvmm_type *mt = dev->mt; | ||
1210 | sector_t size = rrpc->nr_sects * dev->sec_size; | ||
1211 | |||
1212 | size >>= 9; | ||
1213 | |||
1214 | return mt->get_area(dev, begin, size); | ||
1215 | } | ||
1216 | |||
1217 | static void rrpc_area_free(struct rrpc *rrpc) | ||
1218 | { | ||
1219 | struct nvm_dev *dev = rrpc->dev; | ||
1220 | struct nvmm_type *mt = dev->mt; | ||
1221 | |||
1222 | mt->put_area(dev, rrpc->soffset); | ||
1223 | } | ||
1224 | |||
1203 | static void rrpc_free(struct rrpc *rrpc) | 1225 | static void rrpc_free(struct rrpc *rrpc) |
1204 | { | 1226 | { |
1205 | rrpc_gc_free(rrpc); | 1227 | rrpc_gc_free(rrpc); |
1206 | rrpc_map_free(rrpc); | 1228 | rrpc_map_free(rrpc); |
1207 | rrpc_core_free(rrpc); | 1229 | rrpc_core_free(rrpc); |
1208 | rrpc_luns_free(rrpc); | 1230 | rrpc_luns_free(rrpc); |
1231 | rrpc_area_free(rrpc); | ||
1209 | 1232 | ||
1210 | kfree(rrpc); | 1233 | kfree(rrpc); |
1211 | } | 1234 | } |
@@ -1327,6 +1350,7 @@ static void *rrpc_init(struct nvm_dev *dev, struct gendisk *tdisk, | |||
1327 | struct request_queue *bqueue = dev->q; | 1350 | struct request_queue *bqueue = dev->q; |
1328 | struct request_queue *tqueue = tdisk->queue; | 1351 | struct request_queue *tqueue = tdisk->queue; |
1329 | struct rrpc *rrpc; | 1352 | struct rrpc *rrpc; |
1353 | sector_t soffset; | ||
1330 | int ret; | 1354 | int ret; |
1331 | 1355 | ||
1332 | if (!(dev->identity.dom & NVM_RSP_L2P)) { | 1356 | if (!(dev->identity.dom & NVM_RSP_L2P)) { |
@@ -1352,6 +1376,13 @@ static void *rrpc_init(struct nvm_dev *dev, struct gendisk *tdisk, | |||
1352 | /* simple round-robin strategy */ | 1376 | /* simple round-robin strategy */ |
1353 | atomic_set(&rrpc->next_lun, -1); | 1377 | atomic_set(&rrpc->next_lun, -1); |
1354 | 1378 | ||
1379 | ret = rrpc_area_init(rrpc, &soffset); | ||
1380 | if (ret < 0) { | ||
1381 | pr_err("nvm: rrpc: could not initialize area\n"); | ||
1382 | return ERR_PTR(ret); | ||
1383 | } | ||
1384 | rrpc->soffset = soffset; | ||
1385 | |||
1355 | ret = rrpc_luns_init(rrpc, lun_begin, lun_end); | 1386 | ret = rrpc_luns_init(rrpc, lun_begin, lun_end); |
1356 | if (ret) { | 1387 | if (ret) { |
1357 | pr_err("nvm: rrpc: could not initialize luns\n"); | 1388 | pr_err("nvm: rrpc: could not initialize luns\n"); |
diff --git a/drivers/lightnvm/rrpc.h b/drivers/lightnvm/rrpc.h index 855f4a5ca7dd..2653484a3b40 100644 --- a/drivers/lightnvm/rrpc.h +++ b/drivers/lightnvm/rrpc.h | |||
@@ -97,6 +97,7 @@ struct rrpc { | |||
97 | struct nvm_dev *dev; | 97 | struct nvm_dev *dev; |
98 | struct gendisk *disk; | 98 | struct gendisk *disk; |
99 | 99 | ||
100 | sector_t soffset; /* logical sector offset */ | ||
100 | u64 poffset; /* physical page offset */ | 101 | u64 poffset; /* physical page offset */ |
101 | int lun_offset; | 102 | int lun_offset; |
102 | 103 | ||
diff --git a/include/linux/lightnvm.h b/include/linux/lightnvm.h index c3c43184a787..b466bd9f2cf8 100644 --- a/include/linux/lightnvm.h +++ b/include/linux/lightnvm.h | |||
@@ -355,6 +355,7 @@ struct nvm_dev { | |||
355 | char name[DISK_NAME_LEN]; | 355 | char name[DISK_NAME_LEN]; |
356 | 356 | ||
357 | struct mutex mlock; | 357 | struct mutex mlock; |
358 | spinlock_t lock; | ||
358 | }; | 359 | }; |
359 | 360 | ||
360 | static inline struct ppa_addr generic_to_dev_addr(struct nvm_dev *dev, | 361 | static inline struct ppa_addr generic_to_dev_addr(struct nvm_dev *dev, |
@@ -467,6 +468,9 @@ typedef int (nvmm_erase_blk_fn)(struct nvm_dev *, struct nvm_block *, | |||
467 | typedef struct nvm_lun *(nvmm_get_lun_fn)(struct nvm_dev *, int); | 468 | typedef struct nvm_lun *(nvmm_get_lun_fn)(struct nvm_dev *, int); |
468 | typedef void (nvmm_lun_info_print_fn)(struct nvm_dev *); | 469 | typedef void (nvmm_lun_info_print_fn)(struct nvm_dev *); |
469 | 470 | ||
471 | typedef int (nvmm_get_area_fn)(struct nvm_dev *, sector_t *, sector_t); | ||
472 | typedef void (nvmm_put_area_fn)(struct nvm_dev *, sector_t); | ||
473 | |||
470 | struct nvmm_type { | 474 | struct nvmm_type { |
471 | const char *name; | 475 | const char *name; |
472 | unsigned int version[3]; | 476 | unsigned int version[3]; |
@@ -491,6 +495,10 @@ struct nvmm_type { | |||
491 | 495 | ||
492 | /* Statistics */ | 496 | /* Statistics */ |
493 | nvmm_lun_info_print_fn *lun_info_print; | 497 | nvmm_lun_info_print_fn *lun_info_print; |
498 | |||
499 | nvmm_get_area_fn *get_area; | ||
500 | nvmm_put_area_fn *put_area; | ||
501 | |||
494 | struct list_head list; | 502 | struct list_head list; |
495 | }; | 503 | }; |
496 | 504 | ||