This patch splits the initialization of the label data into two functions. One for doing the init, and another for reading the actual configuration data. The idea behind this is that by doing this we create a symmetry between the getting and setting of config data in that we have a function for both. In addition it will make it easier for us to identify the bits that are related to init versus the pieces that are a wrapper for reading data from the ACPI interface. So for example by splitting things out like this it becomes much more obvious that we were performing checks that weren't necessarily related to the set/get operations such as relying on ndd->data being present when the set and get ops should not care about a locally cached copy of the label area. Reviewed-by: Toshi Kani <toshi.kani@hpe.com> Signed-off-by: Alexander Duyck <alexander.h.duyck@linux.intel.com> Signed-off-by: Dan Williams <dan.j.williams@intel.com>
143 lines
3.1 KiB
C
143 lines
3.1 KiB
C
/*
|
|
* Copyright(c) 2013-2015 Intel Corporation. All rights reserved.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of version 2 of the GNU General Public License as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* General Public License for more details.
|
|
*/
|
|
#include <linux/vmalloc.h>
|
|
#include <linux/module.h>
|
|
#include <linux/device.h>
|
|
#include <linux/sizes.h>
|
|
#include <linux/ndctl.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/mm.h>
|
|
#include <linux/nd.h>
|
|
#include "label.h"
|
|
#include "nd.h"
|
|
|
|
static int nvdimm_probe(struct device *dev)
|
|
{
|
|
struct nvdimm_drvdata *ndd;
|
|
int rc;
|
|
|
|
rc = nvdimm_check_config_data(dev);
|
|
if (rc) {
|
|
/* not required for non-aliased nvdimm, ex. NVDIMM-N */
|
|
if (rc == -ENOTTY)
|
|
rc = 0;
|
|
return rc;
|
|
}
|
|
|
|
/* reset locked, to be validated below... */
|
|
nvdimm_clear_locked(dev);
|
|
|
|
ndd = kzalloc(sizeof(*ndd), GFP_KERNEL);
|
|
if (!ndd)
|
|
return -ENOMEM;
|
|
|
|
dev_set_drvdata(dev, ndd);
|
|
ndd->dpa.name = dev_name(dev);
|
|
ndd->ns_current = -1;
|
|
ndd->ns_next = -1;
|
|
ndd->dpa.start = 0;
|
|
ndd->dpa.end = -1;
|
|
ndd->dev = dev;
|
|
get_device(dev);
|
|
kref_init(&ndd->kref);
|
|
|
|
/*
|
|
* EACCES failures reading the namespace label-area-properties
|
|
* are interpreted as the DIMM capacity being locked but the
|
|
* namespace labels themselves being accessible.
|
|
*/
|
|
rc = nvdimm_init_nsarea(ndd);
|
|
if (rc == -EACCES) {
|
|
/*
|
|
* See nvdimm_namespace_common_probe() where we fail to
|
|
* allow namespaces to probe while the DIMM is locked,
|
|
* but we do allow for namespace enumeration.
|
|
*/
|
|
nvdimm_set_locked(dev);
|
|
rc = 0;
|
|
}
|
|
if (rc)
|
|
goto err;
|
|
|
|
/*
|
|
* EACCES failures reading the namespace label-data are
|
|
* interpreted as the label area being locked in addition to the
|
|
* DIMM capacity. We fail the dimm probe to prevent regions from
|
|
* attempting to parse the label area.
|
|
*/
|
|
rc = nd_label_data_init(ndd);
|
|
if (rc == -EACCES)
|
|
nvdimm_set_locked(dev);
|
|
if (rc)
|
|
goto err;
|
|
|
|
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)
|
|
nvdimm_set_aliasing(dev);
|
|
}
|
|
nvdimm_bus_unlock(dev);
|
|
|
|
if (rc)
|
|
goto err;
|
|
|
|
return 0;
|
|
|
|
err:
|
|
put_ndd(ndd);
|
|
return rc;
|
|
}
|
|
|
|
static int nvdimm_remove(struct device *dev)
|
|
{
|
|
struct nvdimm_drvdata *ndd = dev_get_drvdata(dev);
|
|
|
|
if (!ndd)
|
|
return 0;
|
|
|
|
nvdimm_bus_lock(dev);
|
|
dev_set_drvdata(dev, NULL);
|
|
nvdimm_bus_unlock(dev);
|
|
put_ndd(ndd);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static struct nd_device_driver nvdimm_driver = {
|
|
.probe = nvdimm_probe,
|
|
.remove = nvdimm_remove,
|
|
.drv = {
|
|
.name = "nvdimm",
|
|
},
|
|
.type = ND_DRIVER_DIMM,
|
|
};
|
|
|
|
int __init nvdimm_init(void)
|
|
{
|
|
return nd_driver_register(&nvdimm_driver);
|
|
}
|
|
|
|
void nvdimm_exit(void)
|
|
{
|
|
driver_unregister(&nvdimm_driver.drv);
|
|
}
|
|
|
|
MODULE_ALIAS_ND_DEVICE(ND_DEVICE_DIMM);
|