mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-30 03:27:44 -04:00
Merge branch 'for-4.16/dax' into libnvdimm-for-next
This commit is contained in:
commit
d121f07691
1687 changed files with 18295 additions and 11207 deletions
|
|
@ -211,12 +211,12 @@ static int btt_map_read(struct arena_info *arena, u32 lba, u32 *mapping,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int btt_log_read_pair(struct arena_info *arena, u32 lane,
|
||||
struct log_entry *ent)
|
||||
static int btt_log_group_read(struct arena_info *arena, u32 lane,
|
||||
struct log_group *log)
|
||||
{
|
||||
return arena_read_bytes(arena,
|
||||
arena->logoff + (2 * lane * LOG_ENT_SIZE), ent,
|
||||
2 * LOG_ENT_SIZE, 0);
|
||||
arena->logoff + (lane * LOG_GRP_SIZE), log,
|
||||
LOG_GRP_SIZE, 0);
|
||||
}
|
||||
|
||||
static struct dentry *debugfs_root;
|
||||
|
|
@ -256,6 +256,8 @@ static void arena_debugfs_init(struct arena_info *a, struct dentry *parent,
|
|||
debugfs_create_x64("logoff", S_IRUGO, d, &a->logoff);
|
||||
debugfs_create_x64("info2off", S_IRUGO, d, &a->info2off);
|
||||
debugfs_create_x32("flags", S_IRUGO, d, &a->flags);
|
||||
debugfs_create_u32("log_index_0", S_IRUGO, d, &a->log_index[0]);
|
||||
debugfs_create_u32("log_index_1", S_IRUGO, d, &a->log_index[1]);
|
||||
}
|
||||
|
||||
static void btt_debugfs_init(struct btt *btt)
|
||||
|
|
@ -274,6 +276,11 @@ static void btt_debugfs_init(struct btt *btt)
|
|||
}
|
||||
}
|
||||
|
||||
static u32 log_seq(struct log_group *log, int log_idx)
|
||||
{
|
||||
return le32_to_cpu(log->ent[log_idx].seq);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function accepts two log entries, and uses the
|
||||
* sequence number to find the 'older' entry.
|
||||
|
|
@ -283,8 +290,10 @@ static void btt_debugfs_init(struct btt *btt)
|
|||
*
|
||||
* TODO The logic feels a bit kludge-y. make it better..
|
||||
*/
|
||||
static int btt_log_get_old(struct log_entry *ent)
|
||||
static int btt_log_get_old(struct arena_info *a, struct log_group *log)
|
||||
{
|
||||
int idx0 = a->log_index[0];
|
||||
int idx1 = a->log_index[1];
|
||||
int old;
|
||||
|
||||
/*
|
||||
|
|
@ -292,23 +301,23 @@ static int btt_log_get_old(struct log_entry *ent)
|
|||
* the next time, the following logic works out to put this
|
||||
* (next) entry into [1]
|
||||
*/
|
||||
if (ent[0].seq == 0) {
|
||||
ent[0].seq = cpu_to_le32(1);
|
||||
if (log_seq(log, idx0) == 0) {
|
||||
log->ent[idx0].seq = cpu_to_le32(1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ent[0].seq == ent[1].seq)
|
||||
if (log_seq(log, idx0) == log_seq(log, idx1))
|
||||
return -EINVAL;
|
||||
if (le32_to_cpu(ent[0].seq) + le32_to_cpu(ent[1].seq) > 5)
|
||||
if (log_seq(log, idx0) + log_seq(log, idx1) > 5)
|
||||
return -EINVAL;
|
||||
|
||||
if (le32_to_cpu(ent[0].seq) < le32_to_cpu(ent[1].seq)) {
|
||||
if (le32_to_cpu(ent[1].seq) - le32_to_cpu(ent[0].seq) == 1)
|
||||
if (log_seq(log, idx0) < log_seq(log, idx1)) {
|
||||
if ((log_seq(log, idx1) - log_seq(log, idx0)) == 1)
|
||||
old = 0;
|
||||
else
|
||||
old = 1;
|
||||
} else {
|
||||
if (le32_to_cpu(ent[0].seq) - le32_to_cpu(ent[1].seq) == 1)
|
||||
if ((log_seq(log, idx0) - log_seq(log, idx1)) == 1)
|
||||
old = 1;
|
||||
else
|
||||
old = 0;
|
||||
|
|
@ -328,17 +337,18 @@ static int btt_log_read(struct arena_info *arena, u32 lane,
|
|||
{
|
||||
int ret;
|
||||
int old_ent, ret_ent;
|
||||
struct log_entry log[2];
|
||||
struct log_group log;
|
||||
|
||||
ret = btt_log_read_pair(arena, lane, log);
|
||||
ret = btt_log_group_read(arena, lane, &log);
|
||||
if (ret)
|
||||
return -EIO;
|
||||
|
||||
old_ent = btt_log_get_old(log);
|
||||
old_ent = btt_log_get_old(arena, &log);
|
||||
if (old_ent < 0 || old_ent > 1) {
|
||||
dev_err(to_dev(arena),
|
||||
"log corruption (%d): lane %d seq [%d, %d]\n",
|
||||
old_ent, lane, log[0].seq, log[1].seq);
|
||||
old_ent, lane, log.ent[arena->log_index[0]].seq,
|
||||
log.ent[arena->log_index[1]].seq);
|
||||
/* TODO set error state? */
|
||||
return -EIO;
|
||||
}
|
||||
|
|
@ -346,7 +356,7 @@ static int btt_log_read(struct arena_info *arena, u32 lane,
|
|||
ret_ent = (old_flag ? old_ent : (1 - old_ent));
|
||||
|
||||
if (ent != NULL)
|
||||
memcpy(ent, &log[ret_ent], LOG_ENT_SIZE);
|
||||
memcpy(ent, &log.ent[arena->log_index[ret_ent]], LOG_ENT_SIZE);
|
||||
|
||||
return ret_ent;
|
||||
}
|
||||
|
|
@ -360,17 +370,13 @@ static int __btt_log_write(struct arena_info *arena, u32 lane,
|
|||
u32 sub, struct log_entry *ent, unsigned long flags)
|
||||
{
|
||||
int ret;
|
||||
/*
|
||||
* Ignore the padding in log_entry for calculating log_half.
|
||||
* The entry is 'committed' when we write the sequence number,
|
||||
* and we want to ensure that that is the last thing written.
|
||||
* We don't bother writing the padding as that would be extra
|
||||
* media wear and write amplification
|
||||
*/
|
||||
unsigned int log_half = (LOG_ENT_SIZE - 2 * sizeof(u64)) / 2;
|
||||
u64 ns_off = arena->logoff + (((2 * lane) + sub) * LOG_ENT_SIZE);
|
||||
u32 group_slot = arena->log_index[sub];
|
||||
unsigned int log_half = LOG_ENT_SIZE / 2;
|
||||
void *src = ent;
|
||||
u64 ns_off;
|
||||
|
||||
ns_off = arena->logoff + (lane * LOG_GRP_SIZE) +
|
||||
(group_slot * LOG_ENT_SIZE);
|
||||
/* split the 16B write into atomic, durable halves */
|
||||
ret = arena_write_bytes(arena, ns_off, src, log_half, flags);
|
||||
if (ret)
|
||||
|
|
@ -453,7 +459,7 @@ static int btt_log_init(struct arena_info *arena)
|
|||
{
|
||||
size_t logsize = arena->info2off - arena->logoff;
|
||||
size_t chunk_size = SZ_4K, offset = 0;
|
||||
struct log_entry log;
|
||||
struct log_entry ent;
|
||||
void *zerobuf;
|
||||
int ret;
|
||||
u32 i;
|
||||
|
|
@ -485,11 +491,11 @@ static int btt_log_init(struct arena_info *arena)
|
|||
}
|
||||
|
||||
for (i = 0; i < arena->nfree; i++) {
|
||||
log.lba = cpu_to_le32(i);
|
||||
log.old_map = cpu_to_le32(arena->external_nlba + i);
|
||||
log.new_map = cpu_to_le32(arena->external_nlba + i);
|
||||
log.seq = cpu_to_le32(LOG_SEQ_INIT);
|
||||
ret = __btt_log_write(arena, i, 0, &log, 0);
|
||||
ent.lba = cpu_to_le32(i);
|
||||
ent.old_map = cpu_to_le32(arena->external_nlba + i);
|
||||
ent.new_map = cpu_to_le32(arena->external_nlba + i);
|
||||
ent.seq = cpu_to_le32(LOG_SEQ_INIT);
|
||||
ret = __btt_log_write(arena, i, 0, &ent, 0);
|
||||
if (ret)
|
||||
goto free;
|
||||
}
|
||||
|
|
@ -594,6 +600,123 @@ static int btt_freelist_init(struct arena_info *arena)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static bool ent_is_padding(struct log_entry *ent)
|
||||
{
|
||||
return (ent->lba == 0) && (ent->old_map == 0) && (ent->new_map == 0)
|
||||
&& (ent->seq == 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Detecting valid log indices: We read a log group (see the comments in btt.h
|
||||
* for a description of a 'log_group' and its 'slots'), and iterate over its
|
||||
* four slots. We expect that a padding slot will be all-zeroes, and use this
|
||||
* to detect a padding slot vs. an actual entry.
|
||||
*
|
||||
* If a log_group is in the initial state, i.e. hasn't been used since the
|
||||
* creation of this BTT layout, it will have three of the four slots with
|
||||
* zeroes. We skip over these log_groups for the detection of log_index. If
|
||||
* all log_groups are in the initial state (i.e. the BTT has never been
|
||||
* written to), it is safe to assume the 'new format' of log entries in slots
|
||||
* (0, 1).
|
||||
*/
|
||||
static int log_set_indices(struct arena_info *arena)
|
||||
{
|
||||
bool idx_set = false, initial_state = true;
|
||||
int ret, log_index[2] = {-1, -1};
|
||||
u32 i, j, next_idx = 0;
|
||||
struct log_group log;
|
||||
u32 pad_count = 0;
|
||||
|
||||
for (i = 0; i < arena->nfree; i++) {
|
||||
ret = btt_log_group_read(arena, i, &log);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
for (j = 0; j < 4; j++) {
|
||||
if (!idx_set) {
|
||||
if (ent_is_padding(&log.ent[j])) {
|
||||
pad_count++;
|
||||
continue;
|
||||
} else {
|
||||
/* Skip if index has been recorded */
|
||||
if ((next_idx == 1) &&
|
||||
(j == log_index[0]))
|
||||
continue;
|
||||
/* valid entry, record index */
|
||||
log_index[next_idx] = j;
|
||||
next_idx++;
|
||||
}
|
||||
if (next_idx == 2) {
|
||||
/* two valid entries found */
|
||||
idx_set = true;
|
||||
} else if (next_idx > 2) {
|
||||
/* too many valid indices */
|
||||
return -ENXIO;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* once the indices have been set, just verify
|
||||
* that all subsequent log groups are either in
|
||||
* their initial state or follow the same
|
||||
* indices.
|
||||
*/
|
||||
if (j == log_index[0]) {
|
||||
/* entry must be 'valid' */
|
||||
if (ent_is_padding(&log.ent[j]))
|
||||
return -ENXIO;
|
||||
} else if (j == log_index[1]) {
|
||||
;
|
||||
/*
|
||||
* log_index[1] can be padding if the
|
||||
* lane never got used and it is still
|
||||
* in the initial state (three 'padding'
|
||||
* entries)
|
||||
*/
|
||||
} else {
|
||||
/* entry must be invalid (padding) */
|
||||
if (!ent_is_padding(&log.ent[j]))
|
||||
return -ENXIO;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* If any of the log_groups have more than one valid,
|
||||
* non-padding entry, then the we are no longer in the
|
||||
* initial_state
|
||||
*/
|
||||
if (pad_count < 3)
|
||||
initial_state = false;
|
||||
pad_count = 0;
|
||||
}
|
||||
|
||||
if (!initial_state && !idx_set)
|
||||
return -ENXIO;
|
||||
|
||||
/*
|
||||
* If all the entries in the log were in the initial state,
|
||||
* assume new padding scheme
|
||||
*/
|
||||
if (initial_state)
|
||||
log_index[1] = 1;
|
||||
|
||||
/*
|
||||
* Only allow the known permutations of log/padding indices,
|
||||
* i.e. (0, 1), and (0, 2)
|
||||
*/
|
||||
if ((log_index[0] == 0) && ((log_index[1] == 1) || (log_index[1] == 2)))
|
||||
; /* known index possibilities */
|
||||
else {
|
||||
dev_err(to_dev(arena), "Found an unknown padding scheme\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
arena->log_index[0] = log_index[0];
|
||||
arena->log_index[1] = log_index[1];
|
||||
dev_dbg(to_dev(arena), "log_index_0 = %d\n", log_index[0]);
|
||||
dev_dbg(to_dev(arena), "log_index_1 = %d\n", log_index[1]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int btt_rtt_init(struct arena_info *arena)
|
||||
{
|
||||
arena->rtt = kcalloc(arena->nfree, sizeof(u32), GFP_KERNEL);
|
||||
|
|
@ -651,8 +774,7 @@ static struct arena_info *alloc_arena(struct btt *btt, size_t size,
|
|||
available -= 2 * BTT_PG_SIZE;
|
||||
|
||||
/* The log takes a fixed amount of space based on nfree */
|
||||
logsize = roundup(2 * arena->nfree * sizeof(struct log_entry),
|
||||
BTT_PG_SIZE);
|
||||
logsize = roundup(arena->nfree * LOG_GRP_SIZE, BTT_PG_SIZE);
|
||||
available -= logsize;
|
||||
|
||||
/* Calculate optimal split between map and data area */
|
||||
|
|
@ -669,6 +791,10 @@ static struct arena_info *alloc_arena(struct btt *btt, size_t size,
|
|||
arena->mapoff = arena->dataoff + datasize;
|
||||
arena->logoff = arena->mapoff + mapsize;
|
||||
arena->info2off = arena->logoff + logsize;
|
||||
|
||||
/* Default log indices are (0,1) */
|
||||
arena->log_index[0] = 0;
|
||||
arena->log_index[1] = 1;
|
||||
return arena;
|
||||
}
|
||||
|
||||
|
|
@ -759,6 +885,13 @@ static int discover_arenas(struct btt *btt)
|
|||
arena->external_lba_start = cur_nlba;
|
||||
parse_arena_meta(arena, super, cur_off);
|
||||
|
||||
ret = log_set_indices(arena);
|
||||
if (ret) {
|
||||
dev_err(to_dev(arena),
|
||||
"Unable to deduce log/padding indices\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = btt_freelist_init(arena);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
#define MAP_ERR_MASK (1 << MAP_ERR_SHIFT)
|
||||
#define MAP_LBA_MASK (~((1 << MAP_TRIM_SHIFT) | (1 << MAP_ERR_SHIFT)))
|
||||
#define MAP_ENT_NORMAL 0xC0000000
|
||||
#define LOG_GRP_SIZE sizeof(struct log_group)
|
||||
#define LOG_ENT_SIZE sizeof(struct log_entry)
|
||||
#define ARENA_MIN_SIZE (1UL << 24) /* 16 MB */
|
||||
#define ARENA_MAX_SIZE (1ULL << 39) /* 512 GB */
|
||||
|
|
@ -50,12 +51,52 @@ enum btt_init_state {
|
|||
INIT_READY
|
||||
};
|
||||
|
||||
/*
|
||||
* A log group represents one log 'lane', and consists of four log entries.
|
||||
* Two of the four entries are valid entries, and the remaining two are
|
||||
* padding. Due to an old bug in the padding location, we need to perform a
|
||||
* test to determine the padding scheme being used, and use that scheme
|
||||
* thereafter.
|
||||
*
|
||||
* In kernels prior to 4.15, 'log group' would have actual log entries at
|
||||
* indices (0, 2) and padding at indices (1, 3), where as the correct/updated
|
||||
* format has log entries at indices (0, 1) and padding at indices (2, 3).
|
||||
*
|
||||
* Old (pre 4.15) format:
|
||||
* +-----------------+-----------------+
|
||||
* | ent[0] | ent[1] |
|
||||
* | 16B | 16B |
|
||||
* | lba/old/new/seq | pad |
|
||||
* +-----------------------------------+
|
||||
* | ent[2] | ent[3] |
|
||||
* | 16B | 16B |
|
||||
* | lba/old/new/seq | pad |
|
||||
* +-----------------+-----------------+
|
||||
*
|
||||
* New format:
|
||||
* +-----------------+-----------------+
|
||||
* | ent[0] | ent[1] |
|
||||
* | 16B | 16B |
|
||||
* | lba/old/new/seq | lba/old/new/seq |
|
||||
* +-----------------------------------+
|
||||
* | ent[2] | ent[3] |
|
||||
* | 16B | 16B |
|
||||
* | pad | pad |
|
||||
* +-----------------+-----------------+
|
||||
*
|
||||
* We detect during start-up which format is in use, and set
|
||||
* arena->log_index[(0, 1)] with the detected format.
|
||||
*/
|
||||
|
||||
struct log_entry {
|
||||
__le32 lba;
|
||||
__le32 old_map;
|
||||
__le32 new_map;
|
||||
__le32 seq;
|
||||
__le64 padding[2];
|
||||
};
|
||||
|
||||
struct log_group {
|
||||
struct log_entry ent[4];
|
||||
};
|
||||
|
||||
struct btt_sb {
|
||||
|
|
@ -125,6 +166,8 @@ struct aligned_lock {
|
|||
* @list: List head for list of arenas
|
||||
* @debugfs_dir: Debugfs dentry
|
||||
* @flags: Arena flags - may signify error states.
|
||||
* @err_lock: Mutex for synchronizing error clearing.
|
||||
* @log_index: Indices of the valid log entries in a log_group
|
||||
*
|
||||
* arena_info is a per-arena handle. Once an arena is narrowed down for an
|
||||
* IO, this struct is passed around for the duration of the IO.
|
||||
|
|
@ -157,6 +200,7 @@ struct arena_info {
|
|||
/* Arena flags */
|
||||
u32 flags;
|
||||
struct mutex err_lock;
|
||||
int log_index[2];
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -176,6 +220,7 @@ struct arena_info {
|
|||
* @init_lock: Mutex used for the BTT initialization
|
||||
* @init_state: Flag describing the initialization state for the BTT
|
||||
* @num_arenas: Number of arenas in the BTT instance
|
||||
* @phys_bb: Pointer to the namespace's badblocks structure
|
||||
*/
|
||||
struct btt {
|
||||
struct gendisk *btt_disk;
|
||||
|
|
|
|||
|
|
@ -368,15 +368,14 @@ unsigned int pmem_sector_size(struct nd_namespace_common *ndns);
|
|||
void nvdimm_badblocks_populate(struct nd_region *nd_region,
|
||||
struct badblocks *bb, const struct resource *res);
|
||||
#if IS_ENABLED(CONFIG_ND_CLAIM)
|
||||
struct vmem_altmap *nvdimm_setup_pfn(struct nd_pfn *nd_pfn,
|
||||
struct resource *res, struct vmem_altmap *altmap);
|
||||
int nvdimm_setup_pfn(struct nd_pfn *nd_pfn, struct dev_pagemap *pgmap);
|
||||
int devm_nsio_enable(struct device *dev, struct nd_namespace_io *nsio);
|
||||
void devm_nsio_disable(struct device *dev, struct nd_namespace_io *nsio);
|
||||
#else
|
||||
static inline struct vmem_altmap *nvdimm_setup_pfn(struct nd_pfn *nd_pfn,
|
||||
struct resource *res, struct vmem_altmap *altmap)
|
||||
static inline int nvdimm_setup_pfn(struct nd_pfn *nd_pfn,
|
||||
struct dev_pagemap *pgmap)
|
||||
{
|
||||
return ERR_PTR(-ENXIO);
|
||||
return -ENXIO;
|
||||
}
|
||||
static inline int devm_nsio_enable(struct device *dev,
|
||||
struct nd_namespace_io *nsio)
|
||||
|
|
|
|||
|
|
@ -364,9 +364,9 @@ struct device *nd_pfn_create(struct nd_region *nd_region)
|
|||
int nd_pfn_validate(struct nd_pfn *nd_pfn, const char *sig)
|
||||
{
|
||||
u64 checksum, offset;
|
||||
unsigned long align;
|
||||
enum nd_pfn_mode mode;
|
||||
struct nd_namespace_io *nsio;
|
||||
unsigned long align, start_pad;
|
||||
struct nd_pfn_sb *pfn_sb = nd_pfn->pfn_sb;
|
||||
struct nd_namespace_common *ndns = nd_pfn->ndns;
|
||||
const u8 *parent_uuid = nd_dev_to_uuid(&ndns->dev);
|
||||
|
|
@ -410,6 +410,7 @@ int nd_pfn_validate(struct nd_pfn *nd_pfn, const char *sig)
|
|||
|
||||
align = le32_to_cpu(pfn_sb->align);
|
||||
offset = le64_to_cpu(pfn_sb->dataoff);
|
||||
start_pad = le32_to_cpu(pfn_sb->start_pad);
|
||||
if (align == 0)
|
||||
align = 1UL << ilog2(offset);
|
||||
mode = le32_to_cpu(pfn_sb->mode);
|
||||
|
|
@ -468,7 +469,7 @@ int nd_pfn_validate(struct nd_pfn *nd_pfn, const char *sig)
|
|||
return -EBUSY;
|
||||
}
|
||||
|
||||
if ((align && !IS_ALIGNED(offset, align))
|
||||
if ((align && !IS_ALIGNED(nsio->res.start + offset + start_pad, align))
|
||||
|| !IS_ALIGNED(offset, PAGE_SIZE)) {
|
||||
dev_err(&nd_pfn->dev,
|
||||
"bad offset: %#llx dax disabled align: %#lx\n",
|
||||
|
|
@ -541,9 +542,10 @@ static unsigned long init_altmap_reserve(resource_size_t base)
|
|||
return reserve;
|
||||
}
|
||||
|
||||
static struct vmem_altmap *__nvdimm_setup_pfn(struct nd_pfn *nd_pfn,
|
||||
struct resource *res, struct vmem_altmap *altmap)
|
||||
static int __nvdimm_setup_pfn(struct nd_pfn *nd_pfn, struct dev_pagemap *pgmap)
|
||||
{
|
||||
struct resource *res = &pgmap->res;
|
||||
struct vmem_altmap *altmap = &pgmap->altmap;
|
||||
struct nd_pfn_sb *pfn_sb = nd_pfn->pfn_sb;
|
||||
u64 offset = le64_to_cpu(pfn_sb->dataoff);
|
||||
u32 start_pad = __le32_to_cpu(pfn_sb->start_pad);
|
||||
|
|
@ -560,11 +562,13 @@ static struct vmem_altmap *__nvdimm_setup_pfn(struct nd_pfn *nd_pfn,
|
|||
res->start += start_pad;
|
||||
res->end -= end_trunc;
|
||||
|
||||
pgmap->type = MEMORY_DEVICE_HOST;
|
||||
|
||||
if (nd_pfn->mode == PFN_MODE_RAM) {
|
||||
if (offset < SZ_8K)
|
||||
return ERR_PTR(-EINVAL);
|
||||
return -EINVAL;
|
||||
nd_pfn->npfns = le64_to_cpu(pfn_sb->npfns);
|
||||
altmap = NULL;
|
||||
pgmap->altmap_valid = false;
|
||||
} else if (nd_pfn->mode == PFN_MODE_PMEM) {
|
||||
nd_pfn->npfns = PFN_SECTION_ALIGN_UP((resource_size(res)
|
||||
- offset) / PAGE_SIZE);
|
||||
|
|
@ -576,10 +580,17 @@ static struct vmem_altmap *__nvdimm_setup_pfn(struct nd_pfn *nd_pfn,
|
|||
memcpy(altmap, &__altmap, sizeof(*altmap));
|
||||
altmap->free = PHYS_PFN(offset - SZ_8K);
|
||||
altmap->alloc = 0;
|
||||
pgmap->altmap_valid = true;
|
||||
} else
|
||||
return ERR_PTR(-ENXIO);
|
||||
return -ENXIO;
|
||||
|
||||
return altmap;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u64 phys_pmem_align_down(struct nd_pfn *nd_pfn, u64 phys)
|
||||
{
|
||||
return min_t(u64, PHYS_SECTION_ALIGN_DOWN(phys),
|
||||
ALIGN_DOWN(phys, nd_pfn->align));
|
||||
}
|
||||
|
||||
static int nd_pfn_init(struct nd_pfn *nd_pfn)
|
||||
|
|
@ -637,13 +648,16 @@ static int nd_pfn_init(struct nd_pfn *nd_pfn)
|
|||
start = nsio->res.start;
|
||||
size = PHYS_SECTION_ALIGN_UP(start + size) - start;
|
||||
if (region_intersects(start, size, IORESOURCE_SYSTEM_RAM,
|
||||
IORES_DESC_NONE) == REGION_MIXED) {
|
||||
IORES_DESC_NONE) == REGION_MIXED
|
||||
|| !IS_ALIGNED(start + resource_size(&nsio->res),
|
||||
nd_pfn->align)) {
|
||||
size = resource_size(&nsio->res);
|
||||
end_trunc = start + size - PHYS_SECTION_ALIGN_DOWN(start + size);
|
||||
end_trunc = start + size - phys_pmem_align_down(nd_pfn,
|
||||
start + size);
|
||||
}
|
||||
|
||||
if (start_pad + end_trunc)
|
||||
dev_info(&nd_pfn->dev, "%s section collision, truncate %d bytes\n",
|
||||
dev_info(&nd_pfn->dev, "%s alignment collision, truncate %d bytes\n",
|
||||
dev_name(&ndns->dev), start_pad + end_trunc);
|
||||
|
||||
/*
|
||||
|
|
@ -698,19 +712,18 @@ static int nd_pfn_init(struct nd_pfn *nd_pfn)
|
|||
* Determine the effective resource range and vmem_altmap from an nd_pfn
|
||||
* instance.
|
||||
*/
|
||||
struct vmem_altmap *nvdimm_setup_pfn(struct nd_pfn *nd_pfn,
|
||||
struct resource *res, struct vmem_altmap *altmap)
|
||||
int nvdimm_setup_pfn(struct nd_pfn *nd_pfn, struct dev_pagemap *pgmap)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (!nd_pfn->uuid || !nd_pfn->ndns)
|
||||
return ERR_PTR(-ENODEV);
|
||||
return -ENODEV;
|
||||
|
||||
rc = nd_pfn_init(nd_pfn);
|
||||
if (rc)
|
||||
return ERR_PTR(rc);
|
||||
return rc;
|
||||
|
||||
/* we need a valid pfn_sb before we can init a vmem_altmap */
|
||||
return __nvdimm_setup_pfn(nd_pfn, res, altmap);
|
||||
/* we need a valid pfn_sb before we can init a dev_pagemap */
|
||||
return __nvdimm_setup_pfn(nd_pfn, pgmap);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nvdimm_setup_pfn);
|
||||
|
|
|
|||
|
|
@ -298,34 +298,34 @@ static int pmem_attach_disk(struct device *dev,
|
|||
{
|
||||
struct nd_namespace_io *nsio = to_nd_namespace_io(&ndns->dev);
|
||||
struct nd_region *nd_region = to_nd_region(dev->parent);
|
||||
struct vmem_altmap __altmap, *altmap = NULL;
|
||||
int nid = dev_to_node(dev), fua, wbc;
|
||||
struct resource *res = &nsio->res;
|
||||
struct resource bb_res;
|
||||
struct nd_pfn *nd_pfn = NULL;
|
||||
struct dax_device *dax_dev;
|
||||
struct nd_pfn_sb *pfn_sb;
|
||||
struct pmem_device *pmem;
|
||||
struct resource pfn_res;
|
||||
struct request_queue *q;
|
||||
struct device *gendev;
|
||||
struct gendisk *disk;
|
||||
void *addr;
|
||||
|
||||
/* while nsio_rw_bytes is active, parse a pfn info block if present */
|
||||
if (is_nd_pfn(dev)) {
|
||||
nd_pfn = to_nd_pfn(dev);
|
||||
altmap = nvdimm_setup_pfn(nd_pfn, &pfn_res, &__altmap);
|
||||
if (IS_ERR(altmap))
|
||||
return PTR_ERR(altmap);
|
||||
}
|
||||
|
||||
/* we're attaching a block device, disable raw namespace access */
|
||||
devm_nsio_disable(dev, nsio);
|
||||
int rc;
|
||||
|
||||
pmem = devm_kzalloc(dev, sizeof(*pmem), GFP_KERNEL);
|
||||
if (!pmem)
|
||||
return -ENOMEM;
|
||||
|
||||
/* while nsio_rw_bytes is active, parse a pfn info block if present */
|
||||
if (is_nd_pfn(dev)) {
|
||||
nd_pfn = to_nd_pfn(dev);
|
||||
rc = nvdimm_setup_pfn(nd_pfn, &pmem->pgmap);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* we're attaching a block device, disable raw namespace access */
|
||||
devm_nsio_disable(dev, nsio);
|
||||
|
||||
dev_set_drvdata(dev, pmem);
|
||||
pmem->phys_addr = res->start;
|
||||
pmem->size = resource_size(res);
|
||||
|
|
@ -350,19 +350,22 @@ static int pmem_attach_disk(struct device *dev,
|
|||
return -ENOMEM;
|
||||
|
||||
pmem->pfn_flags = PFN_DEV;
|
||||
pmem->pgmap.ref = &q->q_usage_counter;
|
||||
if (is_nd_pfn(dev)) {
|
||||
addr = devm_memremap_pages(dev, &pfn_res, &q->q_usage_counter,
|
||||
altmap);
|
||||
addr = devm_memremap_pages(dev, &pmem->pgmap);
|
||||
pfn_sb = nd_pfn->pfn_sb;
|
||||
pmem->data_offset = le64_to_cpu(pfn_sb->dataoff);
|
||||
pmem->pfn_pad = resource_size(res) - resource_size(&pfn_res);
|
||||
pmem->pfn_pad = resource_size(res) -
|
||||
resource_size(&pmem->pgmap.res);
|
||||
pmem->pfn_flags |= PFN_MAP;
|
||||
res = &pfn_res; /* for badblocks populate */
|
||||
res->start += pmem->data_offset;
|
||||
memcpy(&bb_res, &pmem->pgmap.res, sizeof(bb_res));
|
||||
bb_res.start += pmem->data_offset;
|
||||
} else if (pmem_should_map_pages(dev)) {
|
||||
addr = devm_memremap_pages(dev, &nsio->res,
|
||||
&q->q_usage_counter, NULL);
|
||||
memcpy(&pmem->pgmap.res, &nsio->res, sizeof(pmem->pgmap.res));
|
||||
pmem->pgmap.altmap_valid = false;
|
||||
addr = devm_memremap_pages(dev, &pmem->pgmap);
|
||||
pmem->pfn_flags |= PFN_MAP;
|
||||
memcpy(&bb_res, &pmem->pgmap.res, sizeof(bb_res));
|
||||
} else
|
||||
addr = devm_memremap(dev, pmem->phys_addr,
|
||||
pmem->size, ARCH_MEMREMAP_PMEM);
|
||||
|
|
@ -401,7 +404,7 @@ static int pmem_attach_disk(struct device *dev,
|
|||
/ 512);
|
||||
if (devm_init_badblocks(dev, &pmem->bb))
|
||||
return -ENOMEM;
|
||||
nvdimm_badblocks_populate(nd_region, &pmem->bb, res);
|
||||
nvdimm_badblocks_populate(nd_region, &pmem->bb, &bb_res);
|
||||
disk->bb = &pmem->bb;
|
||||
|
||||
dax_dev = alloc_dax(pmem, disk->disk_name, &pmem_dax_ops);
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ struct pmem_device {
|
|||
struct badblocks bb;
|
||||
struct dax_device *dax_dev;
|
||||
struct gendisk *disk;
|
||||
struct dev_pagemap pgmap;
|
||||
};
|
||||
|
||||
long __pmem_direct_access(struct pmem_device *pmem, pgoff_t pgoff,
|
||||
|
|
|
|||
Loading…
Reference in a new issue