Skip to content

Commit

Permalink
Merge branch 'for-5.1/libnvdimm' into libnvdimm-for-next
Browse files Browse the repository at this point in the history
Merge miscellaneous libnvdimm sub-system updates for v5.1. Highlights
include:

* Support for the Hyper-V family of device-specific-methods (DSMs)
* Several fixes and workarounds for Hyper-V compatibility.
* Fix for the support to cache the dirty-shutdown-count at init.
  • Loading branch information
djbw committed Mar 11, 2019
2 parents ebe9f6f + 075c3fd commit 451fed2
Show file tree
Hide file tree
Showing 13 changed files with 158 additions and 59 deletions.
17 changes: 8 additions & 9 deletions MAINTAINERS
Original file line number Diff line number Diff line change
Expand Up @@ -4536,20 +4536,21 @@ S: Maintained
F: drivers/i2c/busses/i2c-diolan-u2c.c

FILESYSTEM DIRECT ACCESS (DAX)
M: Matthew Wilcox <[email protected]>
M: Ross Zwisler <zwisler@kernel.org>
M: Jan Kara <[email protected]>
M: Dan Williams <[email protected]>
R: Matthew Wilcox <willy@infradead.org>
R: Jan Kara <[email protected]>
L: [email protected]
L: [email protected]
S: Supported
F: fs/dax.c
F: include/linux/dax.h
F: include/trace/events/fs_dax.h

DEVICE DIRECT ACCESS (DAX)
M: Dan Williams <[email protected]>
M: Dave Jiang <[email protected]>
M: Ross Zwisler <[email protected]>
M: Vishal Verma <[email protected]>
M: Keith Busch <[email protected]>
M: Dave Jiang <[email protected]>
L: [email protected]
S: Supported
F: drivers/dax/
Expand Down Expand Up @@ -8643,7 +8644,6 @@ S: Maintained
F: tools/lib/lockdep/

LIBNVDIMM BLK: MMIO-APERTURE DRIVER
M: Ross Zwisler <[email protected]>
M: Dan Williams <[email protected]>
M: Vishal Verma <[email protected]>
M: Dave Jiang <[email protected]>
Expand All @@ -8656,15 +8656,13 @@ F: drivers/nvdimm/region_devs.c
LIBNVDIMM BTT: BLOCK TRANSLATION TABLE
M: Vishal Verma <[email protected]>
M: Dan Williams <[email protected]>
M: Ross Zwisler <[email protected]>
M: Dave Jiang <[email protected]>
L: [email protected]
Q: https://patchwork.kernel.org/project/linux-nvdimm/list/
S: Supported
F: drivers/nvdimm/btt*

LIBNVDIMM PMEM: PERSISTENT MEMORY DRIVER
M: Ross Zwisler <[email protected]>
M: Dan Williams <[email protected]>
M: Vishal Verma <[email protected]>
M: Dave Jiang <[email protected]>
Expand All @@ -8683,9 +8681,10 @@ F: Documentation/devicetree/bindings/pmem/pmem-region.txt

LIBNVDIMM: NON-VOLATILE MEMORY DEVICE SUBSYSTEM
M: Dan Williams <[email protected]>
M: Ross Zwisler <[email protected]>
M: Vishal Verma <[email protected]>
M: Dave Jiang <[email protected]>
M: Keith Busch <[email protected]>
M: Ira Weiny <[email protected]>
L: [email protected]
Q: https://patchwork.kernel.org/project/linux-nvdimm/list/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/nvdimm/nvdimm.git
Expand Down
93 changes: 66 additions & 27 deletions drivers/acpi/nfit/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ static bool no_init_ars;
module_param(no_init_ars, bool, 0644);
MODULE_PARM_DESC(no_init_ars, "Skip ARS run at nfit init time");

static bool force_labels;
module_param(force_labels, bool, 0444);
MODULE_PARM_DESC(force_labels, "Opt-in to labels despite missing methods");

LIST_HEAD(acpi_descs);
DEFINE_MUTEX(acpi_desc_lock);

Expand Down Expand Up @@ -556,6 +560,13 @@ int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm,
return -EINVAL;
}

if (out_obj->type != ACPI_TYPE_BUFFER) {
dev_dbg(dev, "%s unexpected output object type cmd: %s type: %d\n",
dimm_name, cmd_name, out_obj->type);
rc = -EINVAL;
goto out;
}

if (call_pkg) {
call_pkg->nd_fw_size = out_obj->buffer.length;
memcpy(call_pkg->nd_payload + call_pkg->nd_size_in,
Expand All @@ -574,13 +585,6 @@ int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm,
return 0;
}

if (out_obj->package.type != ACPI_TYPE_BUFFER) {
dev_dbg(dev, "%s unexpected output object type cmd: %s type: %d\n",
dimm_name, cmd_name, out_obj->type);
rc = -EINVAL;
goto out;
}

dev_dbg(dev, "%s cmd: %s output length: %d\n", dimm_name,
cmd_name, out_obj->buffer.length);
print_hex_dump_debug(cmd_name, DUMP_PREFIX_OFFSET, 4, 4,
Expand Down Expand Up @@ -1761,14 +1765,14 @@ static bool acpi_nvdimm_has_method(struct acpi_device *adev, char *method)

__weak void nfit_intel_shutdown_status(struct nfit_mem *nfit_mem)
{
struct device *dev = &nfit_mem->adev->dev;
struct nd_intel_smart smart = { 0 };
union acpi_object in_buf = {
.type = ACPI_TYPE_BUFFER,
.buffer.pointer = (char *) &smart,
.buffer.length = sizeof(smart),
.buffer.type = ACPI_TYPE_BUFFER,
.buffer.length = 0,
};
union acpi_object in_obj = {
.type = ACPI_TYPE_PACKAGE,
.package.type = ACPI_TYPE_PACKAGE,
.package.count = 1,
.package.elements = &in_buf,
};
Expand All @@ -1783,8 +1787,15 @@ __weak void nfit_intel_shutdown_status(struct nfit_mem *nfit_mem)
return;

out_obj = acpi_evaluate_dsm(handle, guid, revid, func, &in_obj);
if (!out_obj)
if (!out_obj || out_obj->type != ACPI_TYPE_BUFFER
|| out_obj->buffer.length < sizeof(smart)) {
dev_dbg(dev->parent, "%s: failed to retrieve initial health\n",
dev_name(dev));
ACPI_FREE(out_obj);
return;
}
memcpy(&smart, out_obj->buffer.pointer, sizeof(smart));
ACPI_FREE(out_obj);

if (smart.flags & ND_INTEL_SMART_SHUTDOWN_VALID) {
if (smart.shutdown_state)
Expand All @@ -1795,7 +1806,6 @@ __weak void nfit_intel_shutdown_status(struct nfit_mem *nfit_mem)
set_bit(NFIT_MEM_DIRTY_COUNT, &nfit_mem->flags);
nfit_mem->dirty_shutdown = smart.shutdown_count;
}
ACPI_FREE(out_obj);
}

static void populate_shutdown_status(struct nfit_mem *nfit_mem)
Expand Down Expand Up @@ -1863,9 +1873,17 @@ static int acpi_nfit_add_dimm(struct acpi_nfit_desc *acpi_desc,
dev_set_drvdata(&adev_dimm->dev, nfit_mem);

/*
* Until standardization materializes we need to consider 4
* different command sets. Note, that checking for function0 (bit0)
* tells us if any commands are reachable through this GUID.
* There are 4 "legacy" NVDIMM command sets
* (NVDIMM_FAMILY_{INTEL,MSFT,HPE1,HPE2}) that were created before
* an EFI working group was established to constrain this
* proliferation. The nfit driver probes for the supported command
* set by GUID. Note, if you're a platform developer looking to add
* a new command set to this probe, consider using an existing set,
* or otherwise seek approval to publish the command set at
* http://www.uefi.org/RFIC_LIST.
*
* Note, that checking for function0 (bit0) tells us if any commands
* are reachable through this GUID.
*/
for (i = 0; i <= NVDIMM_FAMILY_MAX; i++)
if (acpi_check_dsm(adev_dimm->handle, to_nfit_uuid(i), 1, 1))
Expand All @@ -1888,6 +1906,8 @@ static int acpi_nfit_add_dimm(struct acpi_nfit_desc *acpi_desc,
dsm_mask &= ~(1 << 8);
} else if (nfit_mem->family == NVDIMM_FAMILY_MSFT) {
dsm_mask = 0xffffffff;
} else if (nfit_mem->family == NVDIMM_FAMILY_HYPERV) {
dsm_mask = 0x1f;
} else {
dev_dbg(dev, "unknown dimm command family\n");
nfit_mem->family = -1;
Expand Down Expand Up @@ -1917,18 +1937,32 @@ static int acpi_nfit_add_dimm(struct acpi_nfit_desc *acpi_desc,
| 1 << ND_CMD_SET_CONFIG_DATA;
if (family == NVDIMM_FAMILY_INTEL
&& (dsm_mask & label_mask) == label_mask)
return 0;
/* skip _LS{I,R,W} enabling */;
else {
if (acpi_nvdimm_has_method(adev_dimm, "_LSI")
&& acpi_nvdimm_has_method(adev_dimm, "_LSR")) {
dev_dbg(dev, "%s: has _LSR\n", dev_name(&adev_dimm->dev));
set_bit(NFIT_MEM_LSR, &nfit_mem->flags);
}

if (acpi_nvdimm_has_method(adev_dimm, "_LSI")
&& acpi_nvdimm_has_method(adev_dimm, "_LSR")) {
dev_dbg(dev, "%s: has _LSR\n", dev_name(&adev_dimm->dev));
set_bit(NFIT_MEM_LSR, &nfit_mem->flags);
}
if (test_bit(NFIT_MEM_LSR, &nfit_mem->flags)
&& acpi_nvdimm_has_method(adev_dimm, "_LSW")) {
dev_dbg(dev, "%s: has _LSW\n", dev_name(&adev_dimm->dev));
set_bit(NFIT_MEM_LSW, &nfit_mem->flags);
}

if (test_bit(NFIT_MEM_LSR, &nfit_mem->flags)
&& acpi_nvdimm_has_method(adev_dimm, "_LSW")) {
dev_dbg(dev, "%s: has _LSW\n", dev_name(&adev_dimm->dev));
set_bit(NFIT_MEM_LSW, &nfit_mem->flags);
/*
* Quirk read-only label configurations to preserve
* access to label-less namespaces by default.
*/
if (!test_bit(NFIT_MEM_LSW, &nfit_mem->flags)
&& !force_labels) {
dev_dbg(dev, "%s: No _LSW, disable labels\n",
dev_name(&adev_dimm->dev));
clear_bit(NFIT_MEM_LSR, &nfit_mem->flags);
} else
dev_dbg(dev, "%s: Force enable labels\n",
dev_name(&adev_dimm->dev));
}

populate_shutdown_status(nfit_mem);
Expand Down Expand Up @@ -2029,6 +2063,10 @@ static int acpi_nfit_register_dimms(struct acpi_nfit_desc *acpi_desc)
cmd_mask |= nfit_mem->dsm_mask & NVDIMM_STANDARD_CMDMASK;
}

/* Quirk to ignore LOCAL for labels on HYPERV DIMMs */
if (nfit_mem->family == NVDIMM_FAMILY_HYPERV)
set_bit(NDD_NOBLK, &flags);

if (test_bit(NFIT_MEM_LSR, &nfit_mem->flags)) {
set_bit(ND_CMD_GET_CONFIG_SIZE, &cmd_mask);
set_bit(ND_CMD_GET_CONFIG_DATA, &cmd_mask);
Expand All @@ -2052,7 +2090,7 @@ static int acpi_nfit_register_dimms(struct acpi_nfit_desc *acpi_desc)
if ((mem_flags & ACPI_NFIT_MEM_FAILED_MASK) == 0)
continue;

dev_info(acpi_desc->dev, "%s flags:%s%s%s%s%s\n",
dev_err(acpi_desc->dev, "Error found in NVDIMM %s flags:%s%s%s%s%s\n",
nvdimm_name(nvdimm),
mem_flags & ACPI_NFIT_MEM_SAVE_FAILED ? " save_fail" : "",
mem_flags & ACPI_NFIT_MEM_RESTORE_FAILED ? " restore_fail":"",
Expand Down Expand Up @@ -3731,6 +3769,7 @@ static __init int nfit_init(void)
guid_parse(UUID_NFIT_DIMM_N_HPE1, &nfit_uuid[NFIT_DEV_DIMM_N_HPE1]);
guid_parse(UUID_NFIT_DIMM_N_HPE2, &nfit_uuid[NFIT_DEV_DIMM_N_HPE2]);
guid_parse(UUID_NFIT_DIMM_N_MSFT, &nfit_uuid[NFIT_DEV_DIMM_N_MSFT]);
guid_parse(UUID_NFIT_DIMM_N_HYPERV, &nfit_uuid[NFIT_DEV_DIMM_N_HYPERV]);

nfit_wq = create_singlethread_workqueue("nfit");
if (!nfit_wq)
Expand Down
6 changes: 5 additions & 1 deletion drivers/acpi/nfit/nfit.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,14 @@
/* https://msdn.microsoft.com/library/windows/hardware/mt604741 */
#define UUID_NFIT_DIMM_N_MSFT "1ee68b36-d4bd-4a1a-9a16-4f8e53d46e05"

/* http://www.uefi.org/RFIC_LIST (see "Virtual NVDIMM 0x1901") */
#define UUID_NFIT_DIMM_N_HYPERV "5746c5f2-a9a2-4264-ad0e-e4ddc9e09e80"

#define ACPI_NFIT_MEM_FAILED_MASK (ACPI_NFIT_MEM_SAVE_FAILED \
| ACPI_NFIT_MEM_RESTORE_FAILED | ACPI_NFIT_MEM_FLUSH_FAILED \
| ACPI_NFIT_MEM_NOT_ARMED | ACPI_NFIT_MEM_MAP_FAILED)

#define NVDIMM_FAMILY_MAX NVDIMM_FAMILY_MSFT
#define NVDIMM_FAMILY_MAX NVDIMM_FAMILY_HYPERV

#define NVDIMM_STANDARD_CMDMASK \
(1 << ND_CMD_SMART | 1 << ND_CMD_SMART_THRESHOLD | 1 << ND_CMD_DIMM_FLAGS \
Expand Down Expand Up @@ -94,6 +97,7 @@ enum nfit_uuids {
NFIT_DEV_DIMM_N_HPE1 = NVDIMM_FAMILY_HPE1,
NFIT_DEV_DIMM_N_HPE2 = NVDIMM_FAMILY_HPE2,
NFIT_DEV_DIMM_N_MSFT = NVDIMM_FAMILY_MSFT,
NFIT_DEV_DIMM_N_HYPERV = NVDIMM_FAMILY_HYPERV,
NFIT_SPA_VOLATILE,
NFIT_SPA_PM,
NFIT_SPA_DCR,
Expand Down
33 changes: 21 additions & 12 deletions drivers/nvdimm/btt.c
Original file line number Diff line number Diff line change
Expand Up @@ -541,51 +541,60 @@ static int arena_clear_freelist_error(struct arena_info *arena, u32 lane)

static int btt_freelist_init(struct arena_info *arena)
{
int old, new, ret;
u32 i, map_entry;
struct log_entry log_new, log_old;
int new, ret;
struct log_entry log_new;
u32 i, map_entry, log_oldmap, log_newmap;

arena->freelist = kcalloc(arena->nfree, sizeof(struct free_entry),
GFP_KERNEL);
if (!arena->freelist)
return -ENOMEM;

for (i = 0; i < arena->nfree; i++) {
old = btt_log_read(arena, i, &log_old, LOG_OLD_ENT);
if (old < 0)
return old;

new = btt_log_read(arena, i, &log_new, LOG_NEW_ENT);
if (new < 0)
return new;

/* old and new map entries with any flags stripped out */
log_oldmap = ent_lba(le32_to_cpu(log_new.old_map));
log_newmap = ent_lba(le32_to_cpu(log_new.new_map));

/* sub points to the next one to be overwritten */
arena->freelist[i].sub = 1 - new;
arena->freelist[i].seq = nd_inc_seq(le32_to_cpu(log_new.seq));
arena->freelist[i].block = le32_to_cpu(log_new.old_map);
arena->freelist[i].block = log_oldmap;

/*
* FIXME: if error clearing fails during init, we want to make
* the BTT read-only
*/
if (ent_e_flag(log_new.old_map)) {
if (ent_e_flag(log_new.old_map) &&
!ent_normal(log_new.old_map)) {
arena->freelist[i].has_err = 1;
ret = arena_clear_freelist_error(arena, i);
if (ret)
dev_err_ratelimited(to_dev(arena),
"Unable to clear known errors\n");
}

/* This implies a newly created or untouched flog entry */
if (log_new.old_map == log_new.new_map)
if (log_oldmap == log_newmap)
continue;

/* Check if map recovery is needed */
ret = btt_map_read(arena, le32_to_cpu(log_new.lba), &map_entry,
NULL, NULL, 0);
if (ret)
return ret;
if ((le32_to_cpu(log_new.new_map) != map_entry) &&
(le32_to_cpu(log_new.old_map) == map_entry)) {

/*
* The map_entry from btt_read_map is stripped of any flag bits,
* so use the stripped out versions from the log as well for
* testing whether recovery is needed. For restoration, use the
* 'raw' version of the log entries as that captured what we
* were going to write originally.
*/
if ((log_newmap != map_entry) && (log_oldmap == map_entry)) {
/*
* Last transaction wrote the flog, but wasn't able
* to complete the map write. So fix up the map.
Expand Down
2 changes: 2 additions & 0 deletions drivers/nvdimm/btt.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@
#define ent_e_flag(ent) (!!(ent & MAP_ERR_MASK))
#define ent_z_flag(ent) (!!(ent & MAP_TRIM_MASK))
#define set_e_flag(ent) (ent |= MAP_ERR_MASK)
/* 'normal' is both e and z flags set */
#define ent_normal(ent) (ent_e_flag(ent) && ent_z_flag(ent))

enum btt_init_state {
INIT_UNCHECKED = 0,
Expand Down
8 changes: 8 additions & 0 deletions drivers/nvdimm/btt_devs.c
Original file line number Diff line number Diff line change
Expand Up @@ -159,11 +159,19 @@ static ssize_t size_show(struct device *dev,
}
static DEVICE_ATTR_RO(size);

static ssize_t log_zero_flags_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return sprintf(buf, "Y\n");
}
static DEVICE_ATTR_RO(log_zero_flags);

static struct attribute *nd_btt_attributes[] = {
&dev_attr_sector_size.attr,
&dev_attr_namespace.attr,
&dev_attr_uuid.attr,
&dev_attr_size.attr,
&dev_attr_log_zero_flags.attr,
NULL,
};

Expand Down
Loading

0 comments on commit 451fed2

Please sign in to comment.