Skip to content

Commit ca5927e

Browse files
MatiasBjorlingaxboe
authored andcommitted
lightnvm: introduce mlc lower page table mappings
NAND MLC memories have both lower and upper pages. When programming, both of these must be written, before data can be read. However, these lower and upper pages might not placed at even and odd flash pages, but can be skipped. Therefore each flash memory has its lower pages defined, which can then be used when programming and to know when padding are necessary. This patch implements the lower page definition in the specification, and exposes it through a simple lookup table at dev->lptbl. Signed-off-by: Matias Bjørling <[email protected]> Signed-off-by: Jens Axboe <[email protected]>
1 parent f9a9995 commit ca5927e

File tree

3 files changed

+101
-2
lines changed

3 files changed

+101
-2
lines changed

drivers/lightnvm/core.c

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,51 @@ int nvm_submit_ppa(struct nvm_dev *dev, struct ppa_addr *ppa, int nr_ppas,
362362
}
363363
EXPORT_SYMBOL(nvm_submit_ppa);
364364

365+
static int nvm_init_slc_tbl(struct nvm_dev *dev, struct nvm_id_group *grp)
366+
{
367+
int i;
368+
369+
dev->lps_per_blk = dev->pgs_per_blk;
370+
dev->lptbl = kcalloc(dev->lps_per_blk, sizeof(int), GFP_KERNEL);
371+
if (!dev->lptbl)
372+
return -ENOMEM;
373+
374+
/* Just a linear array */
375+
for (i = 0; i < dev->lps_per_blk; i++)
376+
dev->lptbl[i] = i;
377+
378+
return 0;
379+
}
380+
381+
static int nvm_init_mlc_tbl(struct nvm_dev *dev, struct nvm_id_group *grp)
382+
{
383+
int i, p;
384+
struct nvm_id_lp_mlc *mlc = &grp->lptbl.mlc;
385+
386+
if (!mlc->num_pairs)
387+
return 0;
388+
389+
dev->lps_per_blk = mlc->num_pairs;
390+
dev->lptbl = kcalloc(dev->lps_per_blk, sizeof(int), GFP_KERNEL);
391+
if (!dev->lptbl)
392+
return -ENOMEM;
393+
394+
/* The lower page table encoding consists of a list of bytes, where each
395+
* has a lower and an upper half. The first half byte maintains the
396+
* increment value and every value after is an offset added to the
397+
* previous incrementation value */
398+
dev->lptbl[0] = mlc->pairs[0] & 0xF;
399+
for (i = 1; i < dev->lps_per_blk; i++) {
400+
p = mlc->pairs[i >> 1];
401+
if (i & 0x1) /* upper */
402+
dev->lptbl[i] = dev->lptbl[i - 1] + ((p & 0xF0) >> 4);
403+
else /* lower */
404+
dev->lptbl[i] = dev->lptbl[i - 1] + (p & 0xF);
405+
}
406+
407+
return 0;
408+
}
409+
365410
static int nvm_core_init(struct nvm_dev *dev)
366411
{
367412
struct nvm_id *id = &dev->identity;
@@ -387,11 +432,23 @@ static int nvm_core_init(struct nvm_dev *dev)
387432
return -EINVAL;
388433
}
389434

390-
if (grp->fmtype != 0 && grp->fmtype != 1) {
435+
switch (grp->fmtype) {
436+
case NVM_ID_FMTYPE_SLC:
437+
if (nvm_init_slc_tbl(dev, grp))
438+
return -ENOMEM;
439+
break;
440+
case NVM_ID_FMTYPE_MLC:
441+
if (nvm_init_mlc_tbl(dev, grp))
442+
return -ENOMEM;
443+
break;
444+
default:
391445
pr_err("nvm: flash type not supported\n");
392446
return -EINVAL;
393447
}
394448

449+
if (!dev->lps_per_blk)
450+
pr_info("nvm: lower page programming table missing\n");
451+
395452
if (grp->mpos & 0x020202)
396453
dev->plane_mode = NVM_PLANE_DOUBLE;
397454
if (grp->mpos & 0x040404)
@@ -420,6 +477,8 @@ static void nvm_free(struct nvm_dev *dev)
420477

421478
if (dev->mt)
422479
dev->mt->unregister_mgr(dev);
480+
481+
kfree(dev->lptbl);
423482
}
424483

425484
static int nvm_init(struct nvm_dev *dev)

drivers/nvme/host/lightnvm.c

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,16 @@ struct nvme_nvm_command {
146146
};
147147
};
148148

149+
struct nvme_nvm_lp_mlc {
150+
__u16 num_pairs;
151+
__u8 pairs[886];
152+
};
153+
154+
struct nvme_nvm_lp_tbl {
155+
__u8 id[8];
156+
struct nvme_nvm_lp_mlc mlc;
157+
};
158+
149159
struct nvme_nvm_id_group {
150160
__u8 mtype;
151161
__u8 fmtype;
@@ -169,7 +179,8 @@ struct nvme_nvm_id_group {
169179
__le32 mpos;
170180
__le32 mccap;
171181
__le16 cpar;
172-
__u8 reserved[906];
182+
__u8 reserved[10];
183+
struct nvme_nvm_lp_tbl lptbl;
173184
} __packed;
174185

175186
struct nvme_nvm_addr_format {
@@ -266,6 +277,15 @@ static int init_grps(struct nvm_id *nvm_id, struct nvme_nvm_id *nvme_nvm_id)
266277
dst->mccap = le32_to_cpu(src->mccap);
267278

268279
dst->cpar = le16_to_cpu(src->cpar);
280+
281+
if (dst->fmtype == NVM_ID_FMTYPE_MLC) {
282+
memcpy(dst->lptbl.id, src->lptbl.id, 8);
283+
dst->lptbl.mlc.num_pairs =
284+
le16_to_cpu(src->lptbl.mlc.num_pairs);
285+
/* 4 bits per pair */
286+
memcpy(dst->lptbl.mlc.pairs, src->lptbl.mlc.pairs,
287+
dst->lptbl.mlc.num_pairs >> 1);
288+
}
269289
}
270290

271291
return 0;

include/linux/lightnvm.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,20 @@ enum {
6767
NVM_ID_CAP_CMD_SUSPEND = 0x2,
6868
NVM_ID_CAP_SCRAMBLE = 0x4,
6969
NVM_ID_CAP_ENCRYPT = 0x8,
70+
71+
/* Memory types */
72+
NVM_ID_FMTYPE_SLC = 0,
73+
NVM_ID_FMTYPE_MLC = 1,
74+
};
75+
76+
struct nvm_id_lp_mlc {
77+
u16 num_pairs;
78+
u8 pairs[886];
79+
};
80+
81+
struct nvm_id_lp_tbl {
82+
__u8 id[8];
83+
struct nvm_id_lp_mlc mlc;
7084
};
7185

7286
struct nvm_id_group {
@@ -89,6 +103,8 @@ struct nvm_id_group {
89103
u32 mpos;
90104
u32 mccap;
91105
u16 cpar;
106+
107+
struct nvm_id_lp_tbl lptbl;
92108
};
93109

94110
struct nvm_addr_format {
@@ -297,6 +313,10 @@ struct nvm_dev {
297313
int sec_per_blk;
298314
int sec_per_lun;
299315

316+
/* lower page table */
317+
int lps_per_blk;
318+
int *lptbl;
319+
300320
unsigned long total_pages;
301321
unsigned long total_blocks;
302322
int nr_luns;

0 commit comments

Comments
 (0)