summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/lightnvm/core.c1
-rw-r--r--drivers/lightnvm/gennvm.c67
-rw-r--r--drivers/lightnvm/gennvm.h6
-rw-r--r--drivers/lightnvm/rrpc.c35
-rw-r--r--drivers/lightnvm/rrpc.h1
-rw-r--r--include/linux/lightnvm.h8
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
23static 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
67static 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
23static void gennvm_blocks_free(struct nvm_dev *dev) 85static 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
470static int __init gennvm_module_init(void) 537static 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
45struct 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 */
1206static 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
1217static 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
1203static void rrpc_free(struct rrpc *rrpc) 1225static 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
360static inline struct ppa_addr generic_to_dev_addr(struct nvm_dev *dev, 361static 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 *,
467typedef struct nvm_lun *(nvmm_get_lun_fn)(struct nvm_dev *, int); 468typedef struct nvm_lun *(nvmm_get_lun_fn)(struct nvm_dev *, int);
468typedef void (nvmm_lun_info_print_fn)(struct nvm_dev *); 469typedef void (nvmm_lun_info_print_fn)(struct nvm_dev *);
469 470
471typedef int (nvmm_get_area_fn)(struct nvm_dev *, sector_t *, sector_t);
472typedef void (nvmm_put_area_fn)(struct nvm_dev *, sector_t);
473
470struct nvmm_type { 474struct 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