Commit d5d30d5a authored by Dan Williams's avatar Dan Williams

libnvdimm/dimm: Add a no-BLK quirk based on NVDIMM family

As Dexuan reports the NVDIMM_FAMILY_HYPERV platform is incompatible with
the existing Linux namespace implementation because it uses
NSLABEL_FLAG_LOCAL for x1-width PMEM interleave sets. Quirk it as an
platform / DIMM that does not provide BLK-aperture access. Allow the
libnvdimm core to assume no potential for aliasing. In case other
implementations make the same mistake, provide a "noblk" module
parameter to force-enable the quirk.

Link: https://lkml.kernel.org/r/PU1P153MB0169977604493B82B662A01CBF920@PU1P153MB0169.APCP153.PROD.OUTLOOK.COMReported-by: default avatarDexuan Cui <decui@microsoft.com>
Tested-by: default avatarDexuan Cui <decui@microsoft.com>
Signed-off-by: default avatarDan Williams <dan.j.williams@intel.com>
parent 6ee977de
...@@ -2016,6 +2016,10 @@ static int acpi_nfit_register_dimms(struct acpi_nfit_desc *acpi_desc) ...@@ -2016,6 +2016,10 @@ static int acpi_nfit_register_dimms(struct acpi_nfit_desc *acpi_desc)
cmd_mask |= nfit_mem->dsm_mask & NVDIMM_STANDARD_CMDMASK; 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)) { if (test_bit(NFIT_MEM_LSR, &nfit_mem->flags)) {
set_bit(ND_CMD_GET_CONFIG_SIZE, &cmd_mask); set_bit(ND_CMD_GET_CONFIG_SIZE, &cmd_mask);
set_bit(ND_CMD_GET_CONFIG_DATA, &cmd_mask); set_bit(ND_CMD_GET_CONFIG_DATA, &cmd_mask);
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
* General Public License for more details. * General Public License for more details.
*/ */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/moduleparam.h>
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/ndctl.h> #include <linux/ndctl.h>
...@@ -25,6 +26,10 @@ ...@@ -25,6 +26,10 @@
static DEFINE_IDA(dimm_ida); static DEFINE_IDA(dimm_ida);
static bool noblk;
module_param(noblk, bool, 0444);
MODULE_PARM_DESC(noblk, "force disable BLK / local alias support");
/* /*
* Retrieve bus and dimm handle and return if this bus supports * Retrieve bus and dimm handle and return if this bus supports
* get_config_data commands * get_config_data commands
...@@ -551,6 +556,8 @@ struct nvdimm *__nvdimm_create(struct nvdimm_bus *nvdimm_bus, ...@@ -551,6 +556,8 @@ struct nvdimm *__nvdimm_create(struct nvdimm_bus *nvdimm_bus,
nvdimm->dimm_id = dimm_id; nvdimm->dimm_id = dimm_id;
nvdimm->provider_data = provider_data; nvdimm->provider_data = provider_data;
if (noblk)
flags |= 1 << NDD_NOBLK;
nvdimm->flags = flags; nvdimm->flags = flags;
nvdimm->cmd_mask = cmd_mask; nvdimm->cmd_mask = cmd_mask;
nvdimm->num_flush = num_flush; nvdimm->num_flush = num_flush;
......
...@@ -392,6 +392,7 @@ int nd_label_reserve_dpa(struct nvdimm_drvdata *ndd) ...@@ -392,6 +392,7 @@ int nd_label_reserve_dpa(struct nvdimm_drvdata *ndd)
return 0; /* no label, nothing to reserve */ return 0; /* no label, nothing to reserve */
for_each_clear_bit_le(slot, free, nslot) { for_each_clear_bit_le(slot, free, nslot) {
struct nvdimm *nvdimm = to_nvdimm(ndd->dev);
struct nd_namespace_label *nd_label; struct nd_namespace_label *nd_label;
struct nd_region *nd_region = NULL; struct nd_region *nd_region = NULL;
u8 label_uuid[NSLABEL_UUID_LEN]; u8 label_uuid[NSLABEL_UUID_LEN];
...@@ -406,6 +407,8 @@ int nd_label_reserve_dpa(struct nvdimm_drvdata *ndd) ...@@ -406,6 +407,8 @@ int nd_label_reserve_dpa(struct nvdimm_drvdata *ndd)
memcpy(label_uuid, nd_label->uuid, NSLABEL_UUID_LEN); memcpy(label_uuid, nd_label->uuid, NSLABEL_UUID_LEN);
flags = __le32_to_cpu(nd_label->flags); flags = __le32_to_cpu(nd_label->flags);
if (test_bit(NDD_NOBLK, &nvdimm->flags))
flags &= ~NSLABEL_FLAG_LOCAL;
nd_label_gen_id(&label_id, label_uuid, flags); nd_label_gen_id(&label_id, label_uuid, flags);
res = nvdimm_allocate_dpa(ndd, &label_id, res = nvdimm_allocate_dpa(ndd, &label_id,
__le64_to_cpu(nd_label->dpa), __le64_to_cpu(nd_label->dpa),
......
...@@ -2492,6 +2492,12 @@ static int init_active_labels(struct nd_region *nd_region) ...@@ -2492,6 +2492,12 @@ static int init_active_labels(struct nd_region *nd_region)
if (!label_ent) if (!label_ent)
break; break;
label = nd_label_active(ndd, j); label = nd_label_active(ndd, j);
if (test_bit(NDD_NOBLK, &nvdimm->flags)) {
u32 flags = __le32_to_cpu(label->flags);
flags &= ~NSLABEL_FLAG_LOCAL;
label->flags = __cpu_to_le32(flags);
}
label_ent->label = label; label_ent->label = label;
mutex_lock(&nd_mapping->lock); mutex_lock(&nd_mapping->lock);
......
...@@ -1003,6 +1003,13 @@ static struct nd_region *nd_region_create(struct nvdimm_bus *nvdimm_bus, ...@@ -1003,6 +1003,13 @@ static struct nd_region *nd_region_create(struct nvdimm_bus *nvdimm_bus,
if (test_bit(NDD_UNARMED, &nvdimm->flags)) if (test_bit(NDD_UNARMED, &nvdimm->flags))
ro = 1; ro = 1;
if (test_bit(NDD_NOBLK, &nvdimm->flags)
&& dev_type == &nd_blk_device_type) {
dev_err(&nvdimm_bus->dev, "%s: %s mapping%d is not BLK capable\n",
caller, dev_name(&nvdimm->dev), i);
return NULL;
}
} }
if (dev_type == &nd_blk_device_type) { if (dev_type == &nd_blk_device_type) {
......
...@@ -42,6 +42,8 @@ enum { ...@@ -42,6 +42,8 @@ enum {
NDD_SECURITY_OVERWRITE = 3, NDD_SECURITY_OVERWRITE = 3,
/* tracking whether or not there is a pending device reference */ /* tracking whether or not there is a pending device reference */
NDD_WORK_PENDING = 4, NDD_WORK_PENDING = 4,
/* ignore / filter NSLABEL_FLAG_LOCAL for this DIMM, i.e. no aliasing */
NDD_NOBLK = 5,
/* need to set a limit somewhere, but yes, this is likely overkill */ /* need to set a limit somewhere, but yes, this is likely overkill */
ND_IOCTL_MAX_BUFLEN = SZ_4M, ND_IOCTL_MAX_BUFLEN = SZ_4M,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment