Skip to content

Commit

Permalink
Merge tag 'libnvdimm-for-4.20' of git://git.kernel.org/pub/scm/linux/…
Browse files Browse the repository at this point in the history
…kernel/git/nvdimm/nvdimm

Pull libnvdimm updates from Dan Williams:

 - Improve the efficiency and performance of reading nvdimm-namespace
   labels. Reduce the amount of label data read at driver load time by a
   few orders of magnitude. Reduce heavyweight call-outs to
   platform-firmware routines.

 - Handle media errors located in the 'struct page' array stored on a
   persistent memory namespace. Let the kernel clear these errors rather
   than an awkward userspace workaround.

 - Fix Address Range Scrub (ARS) completion tracking. Correct occasions
   where the kernel indicates completion of ARS before submission.

 - Fix asynchronous device registration reference counting.

 - Add support for reporting an nvdimm dirty-shutdown-count via sysfs.

 - Fix various small libnvdimm core and uapi issues.

* tag 'libnvdimm-for-4.20' of git://git.kernel.org/pub/scm/linux/kernel/git/nvdimm/nvdimm: (21 commits)
  acpi, nfit: Further restrict userspace ARS start requests
  acpi, nfit: Fix Address Range Scrub completion tracking
  UAPI: ndctl: Remove use of PAGE_SIZE
  UAPI: ndctl: Fix g++-unsupported initialisation in headers
  tools/testing/nvdimm: Populate dirty shutdown data
  acpi, nfit: Collect shutdown status
  acpi, nfit: Introduce nfit_mem flags
  libnvdimm, label: Fix sparse warning
  nvdimm: Use namespace index data to reduce number of label reads needed
  nvdimm: Split label init out from the logic for getting config data
  nvdimm: Remove empty if statement
  nvdimm: Clarify comment in sizeof_namespace_index
  nvdimm: Sanity check labeloff
  libnvdimm, dimm: Maximize label transfer size
  libnvdimm, pmem: Fix badblocks population for 'raw' namespaces
  libnvdimm, namespace: Drop the repeat assignment for variable dev->parent
  libnvdimm, region: Fail badblocks listing for inactive regions
  libnvdimm, pfn: during init, clear errors in the metadata area
  libnvdimm: Set device node in nd_device_register
  libnvdimm: Hold reference on parent while scheduling async init
  ...
  • Loading branch information
Linus Torvalds committed Oct 25, 2018
2 parents df132e4 + 5948612 commit 6078e07
Show file tree
Hide file tree
Showing 20 changed files with 564 additions and 217 deletions.
297 changes: 206 additions & 91 deletions drivers/acpi/nfit/core.c

Large diffs are not rendered by default.

38 changes: 38 additions & 0 deletions drivers/acpi/nfit/intel.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright(c) 2018 Intel Corporation. All rights reserved.
* Intel specific definitions for NVDIMM Firmware Interface Table - NFIT
*/
#ifndef _NFIT_INTEL_H_
#define _NFIT_INTEL_H_

#define ND_INTEL_SMART 1

#define ND_INTEL_SMART_SHUTDOWN_COUNT_VALID (1 << 5)
#define ND_INTEL_SMART_SHUTDOWN_VALID (1 << 10)

struct nd_intel_smart {
u32 status;
union {
struct {
u32 flags;
u8 reserved0[4];
u8 health;
u8 spares;
u8 life_used;
u8 alarm_flags;
u16 media_temperature;
u16 ctrl_temperature;
u32 shutdown_count;
u8 ait_status;
u16 pmic_temperature;
u8 reserved1[8];
u8 shutdown_state;
u32 vendor_size;
u8 vendor_data[92];
} __packed;
u8 data[128];
};
} __packed;

#endif
21 changes: 14 additions & 7 deletions drivers/acpi/nfit/nfit.h
Original file line number Diff line number Diff line change
Expand Up @@ -118,10 +118,8 @@ enum nfit_dimm_notifiers {
};

enum nfit_ars_state {
ARS_REQ,
ARS_REQ_REDO,
ARS_DONE,
ARS_SHORT,
ARS_REQ_SHORT,
ARS_REQ_LONG,
ARS_FAILED,
};

Expand Down Expand Up @@ -159,6 +157,13 @@ struct nfit_memdev {
struct acpi_nfit_memory_map memdev[0];
};

enum nfit_mem_flags {
NFIT_MEM_LSR,
NFIT_MEM_LSW,
NFIT_MEM_DIRTY,
NFIT_MEM_DIRTY_COUNT,
};

/* assembled tables for a given dimm/memory-device */
struct nfit_mem {
struct nvdimm *nvdimm;
Expand All @@ -178,9 +183,9 @@ struct nfit_mem {
struct acpi_nfit_desc *acpi_desc;
struct resource *flush_wpq;
unsigned long dsm_mask;
unsigned long flags;
u32 dirty_shutdown;
int family;
bool has_lsr;
bool has_lsw;
};

struct acpi_nfit_desc {
Expand All @@ -198,6 +203,7 @@ struct acpi_nfit_desc {
struct device *dev;
u8 ars_start_flags;
struct nd_cmd_ars_status *ars_status;
struct nfit_spa *scrub_spa;
struct delayed_work dwork;
struct list_head list;
struct kernfs_node *scrub_count_state;
Expand Down Expand Up @@ -252,7 +258,8 @@ struct nfit_blk {

extern struct list_head acpi_descs;
extern struct mutex acpi_desc_lock;
int acpi_nfit_ars_rescan(struct acpi_nfit_desc *acpi_desc, unsigned long flags);
int acpi_nfit_ars_rescan(struct acpi_nfit_desc *acpi_desc,
enum nfit_ars_state req_type);

#ifdef CONFIG_X86_MCE
void nfit_mce_register(void);
Expand Down
20 changes: 14 additions & 6 deletions drivers/nvdimm/bus.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,6 @@ static int to_nd_device_type(struct device *dev)

static int nvdimm_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
{
/*
* Ensure that region devices always have their numa node set as
* early as possible.
*/
if (is_nd_region(dev))
set_dev_node(dev, to_nd_region(dev)->numa_node);
return add_uevent_var(env, "MODALIAS=" ND_DEVICE_MODALIAS_FMT,
to_nd_device_type(dev));
}
Expand Down Expand Up @@ -488,6 +482,8 @@ static void nd_async_device_register(void *d, async_cookie_t cookie)
put_device(dev);
}
put_device(dev);
if (dev->parent)
put_device(dev->parent);
}

static void nd_async_device_unregister(void *d, async_cookie_t cookie)
Expand All @@ -506,7 +502,19 @@ void __nd_device_register(struct device *dev)
{
if (!dev)
return;

/*
* Ensure that region devices always have their NUMA node set as
* early as possible. This way we are able to make certain that
* any memory associated with the creation and the creation
* itself of the region is associated with the correct node.
*/
if (is_nd_region(dev))
set_dev_node(dev, to_nd_region(dev)->numa_node);

dev->bus = &nvdimm_bus_type;
if (dev->parent)
get_device(dev->parent);
get_device(dev);
async_schedule_domain(nd_async_device_register, dev,
&nd_async_domain);
Expand Down
6 changes: 1 addition & 5 deletions drivers/nvdimm/dimm.c
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ static int nvdimm_probe(struct device *dev)
* DIMM capacity. We fail the dimm probe to prevent regions from
* attempting to parse the label area.
*/
rc = nvdimm_init_config_data(ndd);
rc = nd_label_data_init(ndd);
if (rc == -EACCES)
nvdimm_set_locked(dev);
if (rc)
Expand All @@ -84,10 +84,6 @@ static int nvdimm_probe(struct device *dev)
dev_dbg(dev, "config data size: %d\n", ndd->nsarea.config_size);

nvdimm_bus_lock(dev);
ndd->ns_current = nd_label_validate(ndd);
ndd->ns_next = nd_label_next_nsindex(ndd->ns_current);
nd_label_copy(ndd, to_next_namespace_index(ndd),
to_current_namespace_index(ndd));
if (ndd->ns_current >= 0) {
rc = nd_label_reserve_dpa(ndd);
if (rc == 0)
Expand Down
60 changes: 24 additions & 36 deletions drivers/nvdimm/dimm_devs.c
Original file line number Diff line number Diff line change
Expand Up @@ -85,56 +85,48 @@ int nvdimm_init_nsarea(struct nvdimm_drvdata *ndd)
return cmd_rc;
}

int nvdimm_init_config_data(struct nvdimm_drvdata *ndd)
int nvdimm_get_config_data(struct nvdimm_drvdata *ndd, void *buf,
size_t offset, size_t len)
{
struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(ndd->dev);
struct nvdimm_bus_descriptor *nd_desc = nvdimm_bus->nd_desc;
int rc = validate_dimm(ndd), cmd_rc = 0;
struct nd_cmd_get_config_data_hdr *cmd;
struct nvdimm_bus_descriptor *nd_desc;
u32 max_cmd_size, config_size;
size_t offset;
size_t max_cmd_size, buf_offset;

if (rc)
return rc;

if (ndd->data)
return 0;

if (ndd->nsarea.status || ndd->nsarea.max_xfer == 0
|| ndd->nsarea.config_size < ND_LABEL_MIN_SIZE) {
dev_dbg(ndd->dev, "failed to init config data area: (%d:%d)\n",
ndd->nsarea.max_xfer, ndd->nsarea.config_size);
if (offset + len > ndd->nsarea.config_size)
return -ENXIO;
}

ndd->data = kvmalloc(ndd->nsarea.config_size, GFP_KERNEL);
if (!ndd->data)
return -ENOMEM;

max_cmd_size = min_t(u32, PAGE_SIZE, ndd->nsarea.max_xfer);
cmd = kzalloc(max_cmd_size + sizeof(*cmd), GFP_KERNEL);
max_cmd_size = min_t(u32, len, ndd->nsarea.max_xfer);
cmd = kvzalloc(max_cmd_size + sizeof(*cmd), GFP_KERNEL);
if (!cmd)
return -ENOMEM;

nd_desc = nvdimm_bus->nd_desc;
for (config_size = ndd->nsarea.config_size, offset = 0;
config_size; config_size -= cmd->in_length,
offset += cmd->in_length) {
cmd->in_length = min(config_size, max_cmd_size);
cmd->in_offset = offset;
for (buf_offset = 0; len;
len -= cmd->in_length, buf_offset += cmd->in_length) {
size_t cmd_size;

cmd->in_offset = offset + buf_offset;
cmd->in_length = min(max_cmd_size, len);

cmd_size = sizeof(*cmd) + cmd->in_length;

rc = nd_desc->ndctl(nd_desc, to_nvdimm(ndd->dev),
ND_CMD_GET_CONFIG_DATA, cmd,
cmd->in_length + sizeof(*cmd), &cmd_rc);
ND_CMD_GET_CONFIG_DATA, cmd, cmd_size, &cmd_rc);
if (rc < 0)
break;
if (cmd_rc < 0) {
rc = cmd_rc;
break;
}
memcpy(ndd->data + offset, cmd->out_buf, cmd->in_length);

/* out_buf should be valid, copy it into our output buffer */
memcpy(buf + buf_offset, cmd->out_buf, cmd->in_length);
}
dev_dbg(ndd->dev, "len: %zu rc: %d\n", offset, rc);
kfree(cmd);
kvfree(cmd);

return rc;
}
Expand All @@ -151,15 +143,11 @@ int nvdimm_set_config_data(struct nvdimm_drvdata *ndd, size_t offset,
if (rc)
return rc;

if (!ndd->data)
return -ENXIO;

if (offset + len > ndd->nsarea.config_size)
return -ENXIO;

max_cmd_size = min_t(u32, PAGE_SIZE, len);
max_cmd_size = min_t(u32, max_cmd_size, ndd->nsarea.max_xfer);
cmd = kzalloc(max_cmd_size + sizeof(*cmd) + sizeof(u32), GFP_KERNEL);
max_cmd_size = min_t(u32, len, ndd->nsarea.max_xfer);
cmd = kvzalloc(max_cmd_size + sizeof(*cmd) + sizeof(u32), GFP_KERNEL);
if (!cmd)
return -ENOMEM;

Expand All @@ -183,7 +171,7 @@ int nvdimm_set_config_data(struct nvdimm_drvdata *ndd, size_t offset,
break;
}
}
kfree(cmd);
kvfree(cmd);

return rc;
}
Expand Down
Loading

0 comments on commit 6078e07

Please sign in to comment.