2019-05-29 22:18:09 +08:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-only
|
libnvdimm, nfit: regions (block-data-window, persistent memory, volatile memory)
A "region" device represents the maximum capacity of a BLK range (mmio
block-data-window(s)), or a PMEM range (DAX-capable persistent memory or
volatile memory), without regard for aliasing. Aliasing, in the
dimm-local address space (DPA), is resolved by metadata on a dimm to
designate which exclusive interface will access the aliased DPA ranges.
Support for the per-dimm metadata/label arrvies is in a subsequent
patch.
The name format of "region" devices is "regionN" where, like dimms, N is
a global ida index assigned at discovery time. This id is not reliable
across reboots nor in the presence of hotplug. Look to attributes of
the region or static id-data of the sub-namespace to generate a
persistent name. However, if the platform configuration does not change
it is reasonable to expect the same region id to be assigned at the next
boot.
"region"s have 2 generic attributes "size", and "mapping"s where:
- size: the BLK accessible capacity or the span of the
system physical address range in the case of PMEM.
- mappingN: a tuple describing a dimm's contribution to the region's
capacity in the format (<nmemX>,<dpa>,<size>). For a PMEM-region
there will be at least one mapping per dimm in the interleave set. For
a BLK-region there is only "mapping0" listing the starting DPA of the
BLK-region and the available DPA capacity of that space (matches "size"
above).
The max number of mappings per "region" is hard coded per the
constraints of sysfs attribute groups. That said the number of mappings
per region should never exceed the maximum number of possible dimms in
the system. If the current number turns out to not be enough then the
"mappings" attribute clarifies how many there are supposed to be. "32
should be enough for anybody...".
Cc: Neil Brown <neilb@suse.de>
Cc: <linux-acpi@vger.kernel.org>
Cc: Greg KH <gregkh@linuxfoundation.org>
Cc: Robert Moore <robert.moore@intel.com>
Cc: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Acked-by: Christoph Hellwig <hch@lst.de>
Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Tested-by: Toshi Kani <toshi.kani@hp.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
2015-06-10 08:13:14 +08:00
|
|
|
/*
|
|
|
|
* Copyright(c) 2013-2015 Intel Corporation. All rights reserved.
|
|
|
|
*/
|
2015-05-02 01:11:27 +08:00
|
|
|
#include <linux/scatterlist.h>
|
2019-11-07 09:43:31 +08:00
|
|
|
#include <linux/memregion.h>
|
2015-06-25 16:21:02 +08:00
|
|
|
#include <linux/highmem.h>
|
2015-05-02 01:11:27 +08:00
|
|
|
#include <linux/sched.h>
|
libnvdimm, nfit: regions (block-data-window, persistent memory, volatile memory)
A "region" device represents the maximum capacity of a BLK range (mmio
block-data-window(s)), or a PMEM range (DAX-capable persistent memory or
volatile memory), without regard for aliasing. Aliasing, in the
dimm-local address space (DPA), is resolved by metadata on a dimm to
designate which exclusive interface will access the aliased DPA ranges.
Support for the per-dimm metadata/label arrvies is in a subsequent
patch.
The name format of "region" devices is "regionN" where, like dimms, N is
a global ida index assigned at discovery time. This id is not reliable
across reboots nor in the presence of hotplug. Look to attributes of
the region or static id-data of the sub-namespace to generate a
persistent name. However, if the platform configuration does not change
it is reasonable to expect the same region id to be assigned at the next
boot.
"region"s have 2 generic attributes "size", and "mapping"s where:
- size: the BLK accessible capacity or the span of the
system physical address range in the case of PMEM.
- mappingN: a tuple describing a dimm's contribution to the region's
capacity in the format (<nmemX>,<dpa>,<size>). For a PMEM-region
there will be at least one mapping per dimm in the interleave set. For
a BLK-region there is only "mapping0" listing the starting DPA of the
BLK-region and the available DPA capacity of that space (matches "size"
above).
The max number of mappings per "region" is hard coded per the
constraints of sysfs attribute groups. That said the number of mappings
per region should never exceed the maximum number of possible dimms in
the system. If the current number turns out to not be enough then the
"mappings" attribute clarifies how many there are supposed to be. "32
should be enough for anybody...".
Cc: Neil Brown <neilb@suse.de>
Cc: <linux-acpi@vger.kernel.org>
Cc: Greg KH <gregkh@linuxfoundation.org>
Cc: Robert Moore <robert.moore@intel.com>
Cc: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Acked-by: Christoph Hellwig <hch@lst.de>
Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Tested-by: Toshi Kani <toshi.kani@hp.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
2015-06-10 08:13:14 +08:00
|
|
|
#include <linux/slab.h>
|
2016-05-28 00:23:01 +08:00
|
|
|
#include <linux/hash.h>
|
2015-05-02 01:11:27 +08:00
|
|
|
#include <linux/sort.h>
|
libnvdimm, nfit: regions (block-data-window, persistent memory, volatile memory)
A "region" device represents the maximum capacity of a BLK range (mmio
block-data-window(s)), or a PMEM range (DAX-capable persistent memory or
volatile memory), without regard for aliasing. Aliasing, in the
dimm-local address space (DPA), is resolved by metadata on a dimm to
designate which exclusive interface will access the aliased DPA ranges.
Support for the per-dimm metadata/label arrvies is in a subsequent
patch.
The name format of "region" devices is "regionN" where, like dimms, N is
a global ida index assigned at discovery time. This id is not reliable
across reboots nor in the presence of hotplug. Look to attributes of
the region or static id-data of the sub-namespace to generate a
persistent name. However, if the platform configuration does not change
it is reasonable to expect the same region id to be assigned at the next
boot.
"region"s have 2 generic attributes "size", and "mapping"s where:
- size: the BLK accessible capacity or the span of the
system physical address range in the case of PMEM.
- mappingN: a tuple describing a dimm's contribution to the region's
capacity in the format (<nmemX>,<dpa>,<size>). For a PMEM-region
there will be at least one mapping per dimm in the interleave set. For
a BLK-region there is only "mapping0" listing the starting DPA of the
BLK-region and the available DPA capacity of that space (matches "size"
above).
The max number of mappings per "region" is hard coded per the
constraints of sysfs attribute groups. That said the number of mappings
per region should never exceed the maximum number of possible dimms in
the system. If the current number turns out to not be enough then the
"mappings" attribute clarifies how many there are supposed to be. "32
should be enough for anybody...".
Cc: Neil Brown <neilb@suse.de>
Cc: <linux-acpi@vger.kernel.org>
Cc: Greg KH <gregkh@linuxfoundation.org>
Cc: Robert Moore <robert.moore@intel.com>
Cc: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Acked-by: Christoph Hellwig <hch@lst.de>
Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Tested-by: Toshi Kani <toshi.kani@hp.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
2015-06-10 08:13:14 +08:00
|
|
|
#include <linux/io.h>
|
2015-06-18 05:14:46 +08:00
|
|
|
#include <linux/nd.h>
|
libnvdimm, nfit: regions (block-data-window, persistent memory, volatile memory)
A "region" device represents the maximum capacity of a BLK range (mmio
block-data-window(s)), or a PMEM range (DAX-capable persistent memory or
volatile memory), without regard for aliasing. Aliasing, in the
dimm-local address space (DPA), is resolved by metadata on a dimm to
designate which exclusive interface will access the aliased DPA ranges.
Support for the per-dimm metadata/label arrvies is in a subsequent
patch.
The name format of "region" devices is "regionN" where, like dimms, N is
a global ida index assigned at discovery time. This id is not reliable
across reboots nor in the presence of hotplug. Look to attributes of
the region or static id-data of the sub-namespace to generate a
persistent name. However, if the platform configuration does not change
it is reasonable to expect the same region id to be assigned at the next
boot.
"region"s have 2 generic attributes "size", and "mapping"s where:
- size: the BLK accessible capacity or the span of the
system physical address range in the case of PMEM.
- mappingN: a tuple describing a dimm's contribution to the region's
capacity in the format (<nmemX>,<dpa>,<size>). For a PMEM-region
there will be at least one mapping per dimm in the interleave set. For
a BLK-region there is only "mapping0" listing the starting DPA of the
BLK-region and the available DPA capacity of that space (matches "size"
above).
The max number of mappings per "region" is hard coded per the
constraints of sysfs attribute groups. That said the number of mappings
per region should never exceed the maximum number of possible dimms in
the system. If the current number turns out to not be enough then the
"mappings" attribute clarifies how many there are supposed to be. "32
should be enough for anybody...".
Cc: Neil Brown <neilb@suse.de>
Cc: <linux-acpi@vger.kernel.org>
Cc: Greg KH <gregkh@linuxfoundation.org>
Cc: Robert Moore <robert.moore@intel.com>
Cc: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Acked-by: Christoph Hellwig <hch@lst.de>
Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Tested-by: Toshi Kani <toshi.kani@hp.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
2015-06-10 08:13:14 +08:00
|
|
|
#include "nd-core.h"
|
|
|
|
#include "nd.h"
|
|
|
|
|
2016-07-08 10:44:50 +08:00
|
|
|
/*
|
|
|
|
* For readq() and writeq() on 32-bit builds, the hi-lo, lo-hi order is
|
|
|
|
* irrelevant.
|
|
|
|
*/
|
|
|
|
#include <linux/io-64-nonatomic-hi-lo.h>
|
|
|
|
|
2016-05-28 00:23:01 +08:00
|
|
|
static DEFINE_PER_CPU(int, flush_idx);
|
libnvdimm, nfit: regions (block-data-window, persistent memory, volatile memory)
A "region" device represents the maximum capacity of a BLK range (mmio
block-data-window(s)), or a PMEM range (DAX-capable persistent memory or
volatile memory), without regard for aliasing. Aliasing, in the
dimm-local address space (DPA), is resolved by metadata on a dimm to
designate which exclusive interface will access the aliased DPA ranges.
Support for the per-dimm metadata/label arrvies is in a subsequent
patch.
The name format of "region" devices is "regionN" where, like dimms, N is
a global ida index assigned at discovery time. This id is not reliable
across reboots nor in the presence of hotplug. Look to attributes of
the region or static id-data of the sub-namespace to generate a
persistent name. However, if the platform configuration does not change
it is reasonable to expect the same region id to be assigned at the next
boot.
"region"s have 2 generic attributes "size", and "mapping"s where:
- size: the BLK accessible capacity or the span of the
system physical address range in the case of PMEM.
- mappingN: a tuple describing a dimm's contribution to the region's
capacity in the format (<nmemX>,<dpa>,<size>). For a PMEM-region
there will be at least one mapping per dimm in the interleave set. For
a BLK-region there is only "mapping0" listing the starting DPA of the
BLK-region and the available DPA capacity of that space (matches "size"
above).
The max number of mappings per "region" is hard coded per the
constraints of sysfs attribute groups. That said the number of mappings
per region should never exceed the maximum number of possible dimms in
the system. If the current number turns out to not be enough then the
"mappings" attribute clarifies how many there are supposed to be. "32
should be enough for anybody...".
Cc: Neil Brown <neilb@suse.de>
Cc: <linux-acpi@vger.kernel.org>
Cc: Greg KH <gregkh@linuxfoundation.org>
Cc: Robert Moore <robert.moore@intel.com>
Cc: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Acked-by: Christoph Hellwig <hch@lst.de>
Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Tested-by: Toshi Kani <toshi.kani@hp.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
2015-06-10 08:13:14 +08:00
|
|
|
|
2016-06-08 08:00:04 +08:00
|
|
|
static int nvdimm_map_flush(struct device *dev, struct nvdimm *nvdimm, int dimm,
|
|
|
|
struct nd_region_data *ndrd)
|
|
|
|
{
|
|
|
|
int i, j;
|
|
|
|
|
|
|
|
dev_dbg(dev, "%s: map %d flush address%s\n", nvdimm_name(nvdimm),
|
|
|
|
nvdimm->num_flush, nvdimm->num_flush == 1 ? "" : "es");
|
2016-09-24 08:53:52 +08:00
|
|
|
for (i = 0; i < (1 << ndrd->hints_shift); i++) {
|
2016-06-08 08:00:04 +08:00
|
|
|
struct resource *res = &nvdimm->flush_wpq[i];
|
|
|
|
unsigned long pfn = PHYS_PFN(res->start);
|
|
|
|
void __iomem *flush_page;
|
|
|
|
|
|
|
|
/* check if flush hints share a page */
|
|
|
|
for (j = 0; j < i; j++) {
|
|
|
|
struct resource *res_j = &nvdimm->flush_wpq[j];
|
|
|
|
unsigned long pfn_j = PHYS_PFN(res_j->start);
|
|
|
|
|
|
|
|
if (pfn == pfn_j)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (j < i)
|
|
|
|
flush_page = (void __iomem *) ((unsigned long)
|
2016-09-24 08:53:52 +08:00
|
|
|
ndrd_get_flush_wpq(ndrd, dimm, j)
|
|
|
|
& PAGE_MASK);
|
2016-06-08 08:00:04 +08:00
|
|
|
else
|
|
|
|
flush_page = devm_nvdimm_ioremap(dev,
|
2016-09-19 18:19:00 +08:00
|
|
|
PFN_PHYS(pfn), PAGE_SIZE);
|
2016-06-08 08:00:04 +08:00
|
|
|
if (!flush_page)
|
|
|
|
return -ENXIO;
|
2016-09-24 08:53:52 +08:00
|
|
|
ndrd_set_flush_wpq(ndrd, dimm, i, flush_page
|
|
|
|
+ (res->start & ~PAGE_MASK));
|
2016-06-08 08:00:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int nd_region_activate(struct nd_region *nd_region)
|
|
|
|
{
|
2016-09-27 02:06:50 +08:00
|
|
|
int i, j, num_flush = 0;
|
2016-06-08 08:00:04 +08:00
|
|
|
struct nd_region_data *ndrd;
|
|
|
|
struct device *dev = &nd_region->dev;
|
|
|
|
size_t flush_data_size = sizeof(void *);
|
|
|
|
|
|
|
|
nvdimm_bus_lock(&nd_region->dev);
|
|
|
|
for (i = 0; i < nd_region->ndr_mappings; i++) {
|
|
|
|
struct nd_mapping *nd_mapping = &nd_region->mapping[i];
|
|
|
|
struct nvdimm *nvdimm = nd_mapping->nvdimm;
|
|
|
|
|
2018-12-14 06:36:18 +08:00
|
|
|
if (test_bit(NDD_SECURITY_OVERWRITE, &nvdimm->flags)) {
|
|
|
|
nvdimm_bus_unlock(&nd_region->dev);
|
|
|
|
return -EBUSY;
|
|
|
|
}
|
|
|
|
|
2016-06-08 08:00:04 +08:00
|
|
|
/* at least one null hint slot per-dimm for the "no-hint" case */
|
|
|
|
flush_data_size += sizeof(void *);
|
2016-05-28 00:23:01 +08:00
|
|
|
num_flush = min_not_zero(num_flush, nvdimm->num_flush);
|
2016-06-08 08:00:04 +08:00
|
|
|
if (!nvdimm->num_flush)
|
|
|
|
continue;
|
|
|
|
flush_data_size += nvdimm->num_flush * sizeof(void *);
|
|
|
|
}
|
|
|
|
nvdimm_bus_unlock(&nd_region->dev);
|
|
|
|
|
|
|
|
ndrd = devm_kzalloc(dev, sizeof(*ndrd) + flush_data_size, GFP_KERNEL);
|
|
|
|
if (!ndrd)
|
|
|
|
return -ENOMEM;
|
|
|
|
dev_set_drvdata(dev, ndrd);
|
|
|
|
|
2016-09-24 08:53:52 +08:00
|
|
|
if (!num_flush)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
ndrd->hints_shift = ilog2(num_flush);
|
2016-06-08 08:00:04 +08:00
|
|
|
for (i = 0; i < nd_region->ndr_mappings; i++) {
|
|
|
|
struct nd_mapping *nd_mapping = &nd_region->mapping[i];
|
|
|
|
struct nvdimm *nvdimm = nd_mapping->nvdimm;
|
|
|
|
int rc = nvdimm_map_flush(&nd_region->dev, nvdimm, i, ndrd);
|
|
|
|
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2016-09-27 02:06:50 +08:00
|
|
|
/*
|
|
|
|
* Clear out entries that are duplicates. This should prevent the
|
|
|
|
* extra flushings.
|
|
|
|
*/
|
|
|
|
for (i = 0; i < nd_region->ndr_mappings - 1; i++) {
|
|
|
|
/* ignore if NULL already */
|
|
|
|
if (!ndrd_get_flush_wpq(ndrd, i, 0))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
for (j = i + 1; j < nd_region->ndr_mappings; j++)
|
|
|
|
if (ndrd_get_flush_wpq(ndrd, i, 0) ==
|
|
|
|
ndrd_get_flush_wpq(ndrd, j, 0))
|
|
|
|
ndrd_set_flush_wpq(ndrd, j, 0, NULL);
|
|
|
|
}
|
|
|
|
|
2016-06-08 08:00:04 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
libnvdimm, nfit: regions (block-data-window, persistent memory, volatile memory)
A "region" device represents the maximum capacity of a BLK range (mmio
block-data-window(s)), or a PMEM range (DAX-capable persistent memory or
volatile memory), without regard for aliasing. Aliasing, in the
dimm-local address space (DPA), is resolved by metadata on a dimm to
designate which exclusive interface will access the aliased DPA ranges.
Support for the per-dimm metadata/label arrvies is in a subsequent
patch.
The name format of "region" devices is "regionN" where, like dimms, N is
a global ida index assigned at discovery time. This id is not reliable
across reboots nor in the presence of hotplug. Look to attributes of
the region or static id-data of the sub-namespace to generate a
persistent name. However, if the platform configuration does not change
it is reasonable to expect the same region id to be assigned at the next
boot.
"region"s have 2 generic attributes "size", and "mapping"s where:
- size: the BLK accessible capacity or the span of the
system physical address range in the case of PMEM.
- mappingN: a tuple describing a dimm's contribution to the region's
capacity in the format (<nmemX>,<dpa>,<size>). For a PMEM-region
there will be at least one mapping per dimm in the interleave set. For
a BLK-region there is only "mapping0" listing the starting DPA of the
BLK-region and the available DPA capacity of that space (matches "size"
above).
The max number of mappings per "region" is hard coded per the
constraints of sysfs attribute groups. That said the number of mappings
per region should never exceed the maximum number of possible dimms in
the system. If the current number turns out to not be enough then the
"mappings" attribute clarifies how many there are supposed to be. "32
should be enough for anybody...".
Cc: Neil Brown <neilb@suse.de>
Cc: <linux-acpi@vger.kernel.org>
Cc: Greg KH <gregkh@linuxfoundation.org>
Cc: Robert Moore <robert.moore@intel.com>
Cc: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Acked-by: Christoph Hellwig <hch@lst.de>
Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Tested-by: Toshi Kani <toshi.kani@hp.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
2015-06-10 08:13:14 +08:00
|
|
|
static void nd_region_release(struct device *dev)
|
|
|
|
{
|
|
|
|
struct nd_region *nd_region = to_nd_region(dev);
|
|
|
|
u16 i;
|
|
|
|
|
|
|
|
for (i = 0; i < nd_region->ndr_mappings; i++) {
|
|
|
|
struct nd_mapping *nd_mapping = &nd_region->mapping[i];
|
|
|
|
struct nvdimm *nvdimm = nd_mapping->nvdimm;
|
|
|
|
|
|
|
|
put_device(&nvdimm->dev);
|
|
|
|
}
|
nd_btt: atomic sector updates
BTT stands for Block Translation Table, and is a way to provide power
fail sector atomicity semantics for block devices that have the ability
to perform byte granularity IO. It relies on the capability of libnvdimm
namespace devices to do byte aligned IO.
The BTT works as a stacked blocked device, and reserves a chunk of space
from the backing device for its accounting metadata. It is a bio-based
driver because all IO is done synchronously, and there is no queuing or
asynchronous completions at either the device or the driver level.
The BTT uses 'lanes' to index into various 'on-disk' data structures,
and lanes also act as a synchronization mechanism in case there are more
CPUs than available lanes. We did a comparison between two lane lock
strategies - first where we kept an atomic counter around that tracked
which was the last lane that was used, and 'our' lane was determined by
atomically incrementing that. That way, for the nr_cpus > nr_lanes case,
theoretically, no CPU would be blocked waiting for a lane. The other
strategy was to use the cpu number we're scheduled on to and hash it to
a lane number. Theoretically, this could block an IO that could've
otherwise run using a different, free lane. But some fio workloads
showed that the direct cpu -> lane hash performed faster than tracking
'last lane' - my reasoning is the cache thrash caused by moving the
atomic variable made that approach slower than simply waiting out the
in-progress IO. This supports the conclusion that the driver can be a
very simple bio-based one that does synchronous IOs instead of queuing.
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Boaz Harrosh <boaz@plexistor.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Jens Axboe <axboe@fb.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Neil Brown <neilb@suse.de>
Cc: Jeff Moyer <jmoyer@redhat.com>
Cc: Dave Chinner <david@fromorbit.com>
Cc: Greg KH <gregkh@linuxfoundation.org>
[jmoyer: fix nmi watchdog timeout in btt_map_init]
[jmoyer: move btt initialization to module load path]
[jmoyer: fix memory leak in the btt initialization path]
[jmoyer: Don't overwrite corrupted arenas]
Signed-off-by: Vishal Verma <vishal.l.verma@linux.intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
2015-06-25 16:20:32 +08:00
|
|
|
free_percpu(nd_region->lane);
|
2019-11-07 09:43:31 +08:00
|
|
|
memregion_free(nd_region->id);
|
2022-03-10 11:49:48 +08:00
|
|
|
kfree(nd_region);
|
libnvdimm, nfit: regions (block-data-window, persistent memory, volatile memory)
A "region" device represents the maximum capacity of a BLK range (mmio
block-data-window(s)), or a PMEM range (DAX-capable persistent memory or
volatile memory), without regard for aliasing. Aliasing, in the
dimm-local address space (DPA), is resolved by metadata on a dimm to
designate which exclusive interface will access the aliased DPA ranges.
Support for the per-dimm metadata/label arrvies is in a subsequent
patch.
The name format of "region" devices is "regionN" where, like dimms, N is
a global ida index assigned at discovery time. This id is not reliable
across reboots nor in the presence of hotplug. Look to attributes of
the region or static id-data of the sub-namespace to generate a
persistent name. However, if the platform configuration does not change
it is reasonable to expect the same region id to be assigned at the next
boot.
"region"s have 2 generic attributes "size", and "mapping"s where:
- size: the BLK accessible capacity or the span of the
system physical address range in the case of PMEM.
- mappingN: a tuple describing a dimm's contribution to the region's
capacity in the format (<nmemX>,<dpa>,<size>). For a PMEM-region
there will be at least one mapping per dimm in the interleave set. For
a BLK-region there is only "mapping0" listing the starting DPA of the
BLK-region and the available DPA capacity of that space (matches "size"
above).
The max number of mappings per "region" is hard coded per the
constraints of sysfs attribute groups. That said the number of mappings
per region should never exceed the maximum number of possible dimms in
the system. If the current number turns out to not be enough then the
"mappings" attribute clarifies how many there are supposed to be. "32
should be enough for anybody...".
Cc: Neil Brown <neilb@suse.de>
Cc: <linux-acpi@vger.kernel.org>
Cc: Greg KH <gregkh@linuxfoundation.org>
Cc: Robert Moore <robert.moore@intel.com>
Cc: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Acked-by: Christoph Hellwig <hch@lst.de>
Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Tested-by: Toshi Kani <toshi.kani@hp.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
2015-06-10 08:13:14 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
struct nd_region *to_nd_region(struct device *dev)
|
|
|
|
{
|
|
|
|
struct nd_region *nd_region = container_of(dev, struct nd_region, dev);
|
|
|
|
|
|
|
|
WARN_ON(dev->type->release != nd_region_release);
|
|
|
|
return nd_region;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(to_nd_region);
|
|
|
|
|
2018-04-03 04:14:25 +08:00
|
|
|
struct device *nd_region_dev(struct nd_region *nd_region)
|
|
|
|
{
|
|
|
|
if (!nd_region)
|
|
|
|
return NULL;
|
|
|
|
return &nd_region->dev;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(nd_region_dev);
|
|
|
|
|
2015-06-25 16:21:02 +08:00
|
|
|
void *nd_region_provider_data(struct nd_region *nd_region)
|
|
|
|
{
|
|
|
|
return nd_region->provider_data;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(nd_region_provider_data);
|
|
|
|
|
2015-06-01 03:02:11 +08:00
|
|
|
/**
|
|
|
|
* nd_region_to_nstype() - region to an integer namespace type
|
|
|
|
* @nd_region: region-device to interrogate
|
|
|
|
*
|
|
|
|
* This is the 'nstype' attribute of a region as well, an input to the
|
|
|
|
* MODALIAS for namespace devices, and bit number for a nvdimm_bus to match
|
|
|
|
* namespace devices with namespace drivers.
|
|
|
|
*/
|
|
|
|
int nd_region_to_nstype(struct nd_region *nd_region)
|
|
|
|
{
|
2017-05-30 14:12:19 +08:00
|
|
|
if (is_memory(&nd_region->dev)) {
|
2020-01-31 04:06:18 +08:00
|
|
|
u16 i, label;
|
2015-06-01 03:02:11 +08:00
|
|
|
|
2020-01-31 04:06:18 +08:00
|
|
|
for (i = 0, label = 0; i < nd_region->ndr_mappings; i++) {
|
2015-06-01 03:02:11 +08:00
|
|
|
struct nd_mapping *nd_mapping = &nd_region->mapping[i];
|
|
|
|
struct nvdimm *nvdimm = nd_mapping->nvdimm;
|
|
|
|
|
2020-01-31 04:06:18 +08:00
|
|
|
if (test_bit(NDD_LABELING, &nvdimm->flags))
|
|
|
|
label++;
|
2015-06-01 03:02:11 +08:00
|
|
|
}
|
2020-01-31 04:06:18 +08:00
|
|
|
if (label)
|
2015-06-01 03:02:11 +08:00
|
|
|
return ND_DEVICE_NAMESPACE_PMEM;
|
|
|
|
else
|
|
|
|
return ND_DEVICE_NAMESPACE_IO;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2015-06-18 05:14:46 +08:00
|
|
|
EXPORT_SYMBOL(nd_region_to_nstype);
|
|
|
|
|
2020-01-31 04:06:23 +08:00
|
|
|
static unsigned long long region_size(struct nd_region *nd_region)
|
libnvdimm, nfit: regions (block-data-window, persistent memory, volatile memory)
A "region" device represents the maximum capacity of a BLK range (mmio
block-data-window(s)), or a PMEM range (DAX-capable persistent memory or
volatile memory), without regard for aliasing. Aliasing, in the
dimm-local address space (DPA), is resolved by metadata on a dimm to
designate which exclusive interface will access the aliased DPA ranges.
Support for the per-dimm metadata/label arrvies is in a subsequent
patch.
The name format of "region" devices is "regionN" where, like dimms, N is
a global ida index assigned at discovery time. This id is not reliable
across reboots nor in the presence of hotplug. Look to attributes of
the region or static id-data of the sub-namespace to generate a
persistent name. However, if the platform configuration does not change
it is reasonable to expect the same region id to be assigned at the next
boot.
"region"s have 2 generic attributes "size", and "mapping"s where:
- size: the BLK accessible capacity or the span of the
system physical address range in the case of PMEM.
- mappingN: a tuple describing a dimm's contribution to the region's
capacity in the format (<nmemX>,<dpa>,<size>). For a PMEM-region
there will be at least one mapping per dimm in the interleave set. For
a BLK-region there is only "mapping0" listing the starting DPA of the
BLK-region and the available DPA capacity of that space (matches "size"
above).
The max number of mappings per "region" is hard coded per the
constraints of sysfs attribute groups. That said the number of mappings
per region should never exceed the maximum number of possible dimms in
the system. If the current number turns out to not be enough then the
"mappings" attribute clarifies how many there are supposed to be. "32
should be enough for anybody...".
Cc: Neil Brown <neilb@suse.de>
Cc: <linux-acpi@vger.kernel.org>
Cc: Greg KH <gregkh@linuxfoundation.org>
Cc: Robert Moore <robert.moore@intel.com>
Cc: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Acked-by: Christoph Hellwig <hch@lst.de>
Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Tested-by: Toshi Kani <toshi.kani@hp.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
2015-06-10 08:13:14 +08:00
|
|
|
{
|
2020-01-31 04:06:23 +08:00
|
|
|
if (is_memory(&nd_region->dev)) {
|
|
|
|
return nd_region->ndr_size;
|
libnvdimm, nfit: regions (block-data-window, persistent memory, volatile memory)
A "region" device represents the maximum capacity of a BLK range (mmio
block-data-window(s)), or a PMEM range (DAX-capable persistent memory or
volatile memory), without regard for aliasing. Aliasing, in the
dimm-local address space (DPA), is resolved by metadata on a dimm to
designate which exclusive interface will access the aliased DPA ranges.
Support for the per-dimm metadata/label arrvies is in a subsequent
patch.
The name format of "region" devices is "regionN" where, like dimms, N is
a global ida index assigned at discovery time. This id is not reliable
across reboots nor in the presence of hotplug. Look to attributes of
the region or static id-data of the sub-namespace to generate a
persistent name. However, if the platform configuration does not change
it is reasonable to expect the same region id to be assigned at the next
boot.
"region"s have 2 generic attributes "size", and "mapping"s where:
- size: the BLK accessible capacity or the span of the
system physical address range in the case of PMEM.
- mappingN: a tuple describing a dimm's contribution to the region's
capacity in the format (<nmemX>,<dpa>,<size>). For a PMEM-region
there will be at least one mapping per dimm in the interleave set. For
a BLK-region there is only "mapping0" listing the starting DPA of the
BLK-region and the available DPA capacity of that space (matches "size"
above).
The max number of mappings per "region" is hard coded per the
constraints of sysfs attribute groups. That said the number of mappings
per region should never exceed the maximum number of possible dimms in
the system. If the current number turns out to not be enough then the
"mappings" attribute clarifies how many there are supposed to be. "32
should be enough for anybody...".
Cc: Neil Brown <neilb@suse.de>
Cc: <linux-acpi@vger.kernel.org>
Cc: Greg KH <gregkh@linuxfoundation.org>
Cc: Robert Moore <robert.moore@intel.com>
Cc: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Acked-by: Christoph Hellwig <hch@lst.de>
Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Tested-by: Toshi Kani <toshi.kani@hp.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
2015-06-10 08:13:14 +08:00
|
|
|
} else if (nd_region->ndr_mappings == 1) {
|
|
|
|
struct nd_mapping *nd_mapping = &nd_region->mapping[0];
|
|
|
|
|
2020-01-31 04:06:23 +08:00
|
|
|
return nd_mapping->size;
|
libnvdimm, nfit: regions (block-data-window, persistent memory, volatile memory)
A "region" device represents the maximum capacity of a BLK range (mmio
block-data-window(s)), or a PMEM range (DAX-capable persistent memory or
volatile memory), without regard for aliasing. Aliasing, in the
dimm-local address space (DPA), is resolved by metadata on a dimm to
designate which exclusive interface will access the aliased DPA ranges.
Support for the per-dimm metadata/label arrvies is in a subsequent
patch.
The name format of "region" devices is "regionN" where, like dimms, N is
a global ida index assigned at discovery time. This id is not reliable
across reboots nor in the presence of hotplug. Look to attributes of
the region or static id-data of the sub-namespace to generate a
persistent name. However, if the platform configuration does not change
it is reasonable to expect the same region id to be assigned at the next
boot.
"region"s have 2 generic attributes "size", and "mapping"s where:
- size: the BLK accessible capacity or the span of the
system physical address range in the case of PMEM.
- mappingN: a tuple describing a dimm's contribution to the region's
capacity in the format (<nmemX>,<dpa>,<size>). For a PMEM-region
there will be at least one mapping per dimm in the interleave set. For
a BLK-region there is only "mapping0" listing the starting DPA of the
BLK-region and the available DPA capacity of that space (matches "size"
above).
The max number of mappings per "region" is hard coded per the
constraints of sysfs attribute groups. That said the number of mappings
per region should never exceed the maximum number of possible dimms in
the system. If the current number turns out to not be enough then the
"mappings" attribute clarifies how many there are supposed to be. "32
should be enough for anybody...".
Cc: Neil Brown <neilb@suse.de>
Cc: <linux-acpi@vger.kernel.org>
Cc: Greg KH <gregkh@linuxfoundation.org>
Cc: Robert Moore <robert.moore@intel.com>
Cc: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Acked-by: Christoph Hellwig <hch@lst.de>
Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Tested-by: Toshi Kani <toshi.kani@hp.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
2015-06-10 08:13:14 +08:00
|
|
|
}
|
|
|
|
|
2020-01-31 04:06:23 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static ssize_t size_show(struct device *dev,
|
|
|
|
struct device_attribute *attr, char *buf)
|
|
|
|
{
|
|
|
|
struct nd_region *nd_region = to_nd_region(dev);
|
|
|
|
|
|
|
|
return sprintf(buf, "%llu\n", region_size(nd_region));
|
libnvdimm, nfit: regions (block-data-window, persistent memory, volatile memory)
A "region" device represents the maximum capacity of a BLK range (mmio
block-data-window(s)), or a PMEM range (DAX-capable persistent memory or
volatile memory), without regard for aliasing. Aliasing, in the
dimm-local address space (DPA), is resolved by metadata on a dimm to
designate which exclusive interface will access the aliased DPA ranges.
Support for the per-dimm metadata/label arrvies is in a subsequent
patch.
The name format of "region" devices is "regionN" where, like dimms, N is
a global ida index assigned at discovery time. This id is not reliable
across reboots nor in the presence of hotplug. Look to attributes of
the region or static id-data of the sub-namespace to generate a
persistent name. However, if the platform configuration does not change
it is reasonable to expect the same region id to be assigned at the next
boot.
"region"s have 2 generic attributes "size", and "mapping"s where:
- size: the BLK accessible capacity or the span of the
system physical address range in the case of PMEM.
- mappingN: a tuple describing a dimm's contribution to the region's
capacity in the format (<nmemX>,<dpa>,<size>). For a PMEM-region
there will be at least one mapping per dimm in the interleave set. For
a BLK-region there is only "mapping0" listing the starting DPA of the
BLK-region and the available DPA capacity of that space (matches "size"
above).
The max number of mappings per "region" is hard coded per the
constraints of sysfs attribute groups. That said the number of mappings
per region should never exceed the maximum number of possible dimms in
the system. If the current number turns out to not be enough then the
"mappings" attribute clarifies how many there are supposed to be. "32
should be enough for anybody...".
Cc: Neil Brown <neilb@suse.de>
Cc: <linux-acpi@vger.kernel.org>
Cc: Greg KH <gregkh@linuxfoundation.org>
Cc: Robert Moore <robert.moore@intel.com>
Cc: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Acked-by: Christoph Hellwig <hch@lst.de>
Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Tested-by: Toshi Kani <toshi.kani@hp.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
2015-06-10 08:13:14 +08:00
|
|
|
}
|
|
|
|
static DEVICE_ATTR_RO(size);
|
|
|
|
|
2017-04-22 04:28:12 +08:00
|
|
|
static ssize_t deep_flush_show(struct device *dev,
|
|
|
|
struct device_attribute *attr, char *buf)
|
|
|
|
{
|
|
|
|
struct nd_region *nd_region = to_nd_region(dev);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* NOTE: in the nvdimm_has_flush() error case this attribute is
|
|
|
|
* not visible.
|
|
|
|
*/
|
|
|
|
return sprintf(buf, "%d\n", nvdimm_has_flush(nd_region));
|
|
|
|
}
|
|
|
|
|
|
|
|
static ssize_t deep_flush_store(struct device *dev, struct device_attribute *attr,
|
|
|
|
const char *buf, size_t len)
|
|
|
|
{
|
|
|
|
bool flush;
|
|
|
|
int rc = strtobool(buf, &flush);
|
|
|
|
struct nd_region *nd_region = to_nd_region(dev);
|
|
|
|
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
if (!flush)
|
|
|
|
return -EINVAL;
|
2019-07-05 22:03:22 +08:00
|
|
|
rc = nvdimm_flush(nd_region, NULL);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
2017-04-22 04:28:12 +08:00
|
|
|
|
|
|
|
return len;
|
|
|
|
}
|
|
|
|
static DEVICE_ATTR_RW(deep_flush);
|
|
|
|
|
libnvdimm, nfit: regions (block-data-window, persistent memory, volatile memory)
A "region" device represents the maximum capacity of a BLK range (mmio
block-data-window(s)), or a PMEM range (DAX-capable persistent memory or
volatile memory), without regard for aliasing. Aliasing, in the
dimm-local address space (DPA), is resolved by metadata on a dimm to
designate which exclusive interface will access the aliased DPA ranges.
Support for the per-dimm metadata/label arrvies is in a subsequent
patch.
The name format of "region" devices is "regionN" where, like dimms, N is
a global ida index assigned at discovery time. This id is not reliable
across reboots nor in the presence of hotplug. Look to attributes of
the region or static id-data of the sub-namespace to generate a
persistent name. However, if the platform configuration does not change
it is reasonable to expect the same region id to be assigned at the next
boot.
"region"s have 2 generic attributes "size", and "mapping"s where:
- size: the BLK accessible capacity or the span of the
system physical address range in the case of PMEM.
- mappingN: a tuple describing a dimm's contribution to the region's
capacity in the format (<nmemX>,<dpa>,<size>). For a PMEM-region
there will be at least one mapping per dimm in the interleave set. For
a BLK-region there is only "mapping0" listing the starting DPA of the
BLK-region and the available DPA capacity of that space (matches "size"
above).
The max number of mappings per "region" is hard coded per the
constraints of sysfs attribute groups. That said the number of mappings
per region should never exceed the maximum number of possible dimms in
the system. If the current number turns out to not be enough then the
"mappings" attribute clarifies how many there are supposed to be. "32
should be enough for anybody...".
Cc: Neil Brown <neilb@suse.de>
Cc: <linux-acpi@vger.kernel.org>
Cc: Greg KH <gregkh@linuxfoundation.org>
Cc: Robert Moore <robert.moore@intel.com>
Cc: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Acked-by: Christoph Hellwig <hch@lst.de>
Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Tested-by: Toshi Kani <toshi.kani@hp.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
2015-06-10 08:13:14 +08:00
|
|
|
static ssize_t mappings_show(struct device *dev,
|
|
|
|
struct device_attribute *attr, char *buf)
|
|
|
|
{
|
|
|
|
struct nd_region *nd_region = to_nd_region(dev);
|
|
|
|
|
|
|
|
return sprintf(buf, "%d\n", nd_region->ndr_mappings);
|
|
|
|
}
|
|
|
|
static DEVICE_ATTR_RO(mappings);
|
|
|
|
|
2015-06-01 03:02:11 +08:00
|
|
|
static ssize_t nstype_show(struct device *dev,
|
|
|
|
struct device_attribute *attr, char *buf)
|
|
|
|
{
|
|
|
|
struct nd_region *nd_region = to_nd_region(dev);
|
|
|
|
|
|
|
|
return sprintf(buf, "%d\n", nd_region_to_nstype(nd_region));
|
|
|
|
}
|
|
|
|
static DEVICE_ATTR_RO(nstype);
|
|
|
|
|
2015-05-02 01:11:27 +08:00
|
|
|
static ssize_t set_cookie_show(struct device *dev,
|
|
|
|
struct device_attribute *attr, char *buf)
|
|
|
|
{
|
|
|
|
struct nd_region *nd_region = to_nd_region(dev);
|
|
|
|
struct nd_interleave_set *nd_set = nd_region->nd_set;
|
2017-06-04 09:59:15 +08:00
|
|
|
ssize_t rc = 0;
|
2015-05-02 01:11:27 +08:00
|
|
|
|
2017-05-30 14:12:19 +08:00
|
|
|
if (is_memory(dev) && nd_set)
|
2015-05-02 01:11:27 +08:00
|
|
|
/* pass, should be precluded by region_visible */;
|
|
|
|
else
|
|
|
|
return -ENXIO;
|
|
|
|
|
2017-06-04 09:59:15 +08:00
|
|
|
/*
|
|
|
|
* The cookie to show depends on which specification of the
|
|
|
|
* labels we are using. If there are not labels then default to
|
|
|
|
* the v1.1 namespace label cookie definition. To read all this
|
|
|
|
* data we need to wait for probing to settle.
|
|
|
|
*/
|
2022-04-21 23:33:39 +08:00
|
|
|
device_lock(dev);
|
2017-06-04 09:59:15 +08:00
|
|
|
nvdimm_bus_lock(dev);
|
|
|
|
wait_nvdimm_bus_probe_idle(dev);
|
|
|
|
if (nd_region->ndr_mappings) {
|
|
|
|
struct nd_mapping *nd_mapping = &nd_region->mapping[0];
|
|
|
|
struct nvdimm_drvdata *ndd = to_ndd(nd_mapping);
|
|
|
|
|
|
|
|
if (ndd) {
|
|
|
|
struct nd_namespace_index *nsindex;
|
|
|
|
|
|
|
|
nsindex = to_namespace_index(ndd, ndd->ns_current);
|
|
|
|
rc = sprintf(buf, "%#llx\n",
|
|
|
|
nd_region_interleave_set_cookie(nd_region,
|
|
|
|
nsindex));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
nvdimm_bus_unlock(dev);
|
2022-04-21 23:33:39 +08:00
|
|
|
device_unlock(dev);
|
2017-06-04 09:59:15 +08:00
|
|
|
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
return sprintf(buf, "%#llx\n", nd_set->cookie1);
|
2015-05-02 01:11:27 +08:00
|
|
|
}
|
|
|
|
static DEVICE_ATTR_RO(set_cookie);
|
|
|
|
|
2015-06-18 05:14:46 +08:00
|
|
|
resource_size_t nd_region_available_dpa(struct nd_region *nd_region)
|
|
|
|
{
|
2022-03-10 11:49:48 +08:00
|
|
|
resource_size_t available;
|
2015-06-18 05:14:46 +08:00
|
|
|
int i;
|
|
|
|
|
|
|
|
WARN_ON(!is_nvdimm_bus_locked(&nd_region->dev));
|
|
|
|
|
|
|
|
available = 0;
|
|
|
|
for (i = 0; i < nd_region->ndr_mappings; i++) {
|
|
|
|
struct nd_mapping *nd_mapping = &nd_region->mapping[i];
|
|
|
|
struct nvdimm_drvdata *ndd = to_ndd(nd_mapping);
|
|
|
|
|
|
|
|
/* if a dimm is disabled the available capacity is zero */
|
|
|
|
if (!ndd)
|
|
|
|
return 0;
|
|
|
|
|
2022-03-10 11:49:48 +08:00
|
|
|
available += nd_pmem_available_dpa(nd_region, nd_mapping);
|
2015-06-18 05:14:46 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return available;
|
|
|
|
}
|
|
|
|
|
2018-07-25 05:07:57 +08:00
|
|
|
resource_size_t nd_region_allocatable_dpa(struct nd_region *nd_region)
|
|
|
|
{
|
2022-03-10 11:49:48 +08:00
|
|
|
resource_size_t avail = 0;
|
2018-07-25 05:07:57 +08:00
|
|
|
int i;
|
|
|
|
|
|
|
|
WARN_ON(!is_nvdimm_bus_locked(&nd_region->dev));
|
|
|
|
for (i = 0; i < nd_region->ndr_mappings; i++) {
|
|
|
|
struct nd_mapping *nd_mapping = &nd_region->mapping[i];
|
|
|
|
|
2022-03-10 11:49:48 +08:00
|
|
|
avail = min_not_zero(avail, nd_pmem_max_contiguous_dpa(
|
|
|
|
nd_region, nd_mapping));
|
2018-07-25 05:07:57 +08:00
|
|
|
}
|
2022-03-10 11:49:48 +08:00
|
|
|
return avail * nd_region->ndr_mappings;
|
2018-07-25 05:07:57 +08:00
|
|
|
}
|
|
|
|
|
2015-06-18 05:14:46 +08:00
|
|
|
static ssize_t available_size_show(struct device *dev,
|
|
|
|
struct device_attribute *attr, char *buf)
|
|
|
|
{
|
|
|
|
struct nd_region *nd_region = to_nd_region(dev);
|
|
|
|
unsigned long long available = 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Flush in-flight updates and grab a snapshot of the available
|
|
|
|
* size. Of course, this value is potentially invalidated the
|
|
|
|
* memory nvdimm_bus_lock() is dropped, but that's userspace's
|
|
|
|
* problem to not race itself.
|
|
|
|
*/
|
2022-04-21 23:33:39 +08:00
|
|
|
device_lock(dev);
|
2015-06-18 05:14:46 +08:00
|
|
|
nvdimm_bus_lock(dev);
|
|
|
|
wait_nvdimm_bus_probe_idle(dev);
|
|
|
|
available = nd_region_available_dpa(nd_region);
|
|
|
|
nvdimm_bus_unlock(dev);
|
2022-04-21 23:33:39 +08:00
|
|
|
device_unlock(dev);
|
2015-06-18 05:14:46 +08:00
|
|
|
|
|
|
|
return sprintf(buf, "%llu\n", available);
|
|
|
|
}
|
|
|
|
static DEVICE_ATTR_RO(available_size);
|
|
|
|
|
2018-07-25 05:07:58 +08:00
|
|
|
static ssize_t max_available_extent_show(struct device *dev,
|
|
|
|
struct device_attribute *attr, char *buf)
|
|
|
|
{
|
|
|
|
struct nd_region *nd_region = to_nd_region(dev);
|
|
|
|
unsigned long long available = 0;
|
|
|
|
|
2022-04-21 23:33:39 +08:00
|
|
|
device_lock(dev);
|
2018-07-25 05:07:58 +08:00
|
|
|
nvdimm_bus_lock(dev);
|
|
|
|
wait_nvdimm_bus_probe_idle(dev);
|
|
|
|
available = nd_region_allocatable_dpa(nd_region);
|
|
|
|
nvdimm_bus_unlock(dev);
|
2022-04-21 23:33:39 +08:00
|
|
|
device_unlock(dev);
|
2018-07-25 05:07:58 +08:00
|
|
|
|
|
|
|
return sprintf(buf, "%llu\n", available);
|
|
|
|
}
|
|
|
|
static DEVICE_ATTR_RO(max_available_extent);
|
|
|
|
|
2015-06-01 03:02:11 +08:00
|
|
|
static ssize_t init_namespaces_show(struct device *dev,
|
|
|
|
struct device_attribute *attr, char *buf)
|
|
|
|
{
|
2016-06-08 08:00:04 +08:00
|
|
|
struct nd_region_data *ndrd = dev_get_drvdata(dev);
|
2015-06-01 03:02:11 +08:00
|
|
|
ssize_t rc;
|
|
|
|
|
|
|
|
nvdimm_bus_lock(dev);
|
2016-06-08 08:00:04 +08:00
|
|
|
if (ndrd)
|
|
|
|
rc = sprintf(buf, "%d/%d\n", ndrd->ns_active, ndrd->ns_count);
|
2015-06-01 03:02:11 +08:00
|
|
|
else
|
|
|
|
rc = -ENXIO;
|
|
|
|
nvdimm_bus_unlock(dev);
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
static DEVICE_ATTR_RO(init_namespaces);
|
|
|
|
|
2015-06-18 05:14:46 +08:00
|
|
|
static ssize_t namespace_seed_show(struct device *dev,
|
|
|
|
struct device_attribute *attr, char *buf)
|
|
|
|
{
|
|
|
|
struct nd_region *nd_region = to_nd_region(dev);
|
|
|
|
ssize_t rc;
|
|
|
|
|
|
|
|
nvdimm_bus_lock(dev);
|
|
|
|
if (nd_region->ns_seed)
|
|
|
|
rc = sprintf(buf, "%s\n", dev_name(nd_region->ns_seed));
|
|
|
|
else
|
|
|
|
rc = sprintf(buf, "\n");
|
|
|
|
nvdimm_bus_unlock(dev);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
static DEVICE_ATTR_RO(namespace_seed);
|
|
|
|
|
2015-06-25 16:20:04 +08:00
|
|
|
static ssize_t btt_seed_show(struct device *dev,
|
|
|
|
struct device_attribute *attr, char *buf)
|
|
|
|
{
|
|
|
|
struct nd_region *nd_region = to_nd_region(dev);
|
|
|
|
ssize_t rc;
|
|
|
|
|
|
|
|
nvdimm_bus_lock(dev);
|
|
|
|
if (nd_region->btt_seed)
|
|
|
|
rc = sprintf(buf, "%s\n", dev_name(nd_region->btt_seed));
|
|
|
|
else
|
|
|
|
rc = sprintf(buf, "\n");
|
|
|
|
nvdimm_bus_unlock(dev);
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
static DEVICE_ATTR_RO(btt_seed);
|
|
|
|
|
2015-07-31 05:57:47 +08:00
|
|
|
static ssize_t pfn_seed_show(struct device *dev,
|
|
|
|
struct device_attribute *attr, char *buf)
|
|
|
|
{
|
|
|
|
struct nd_region *nd_region = to_nd_region(dev);
|
|
|
|
ssize_t rc;
|
|
|
|
|
|
|
|
nvdimm_bus_lock(dev);
|
|
|
|
if (nd_region->pfn_seed)
|
|
|
|
rc = sprintf(buf, "%s\n", dev_name(nd_region->pfn_seed));
|
|
|
|
else
|
|
|
|
rc = sprintf(buf, "\n");
|
|
|
|
nvdimm_bus_unlock(dev);
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
static DEVICE_ATTR_RO(pfn_seed);
|
|
|
|
|
2016-03-12 02:15:36 +08:00
|
|
|
static ssize_t dax_seed_show(struct device *dev,
|
|
|
|
struct device_attribute *attr, char *buf)
|
|
|
|
{
|
|
|
|
struct nd_region *nd_region = to_nd_region(dev);
|
|
|
|
ssize_t rc;
|
|
|
|
|
|
|
|
nvdimm_bus_lock(dev);
|
|
|
|
if (nd_region->dax_seed)
|
|
|
|
rc = sprintf(buf, "%s\n", dev_name(nd_region->dax_seed));
|
|
|
|
else
|
|
|
|
rc = sprintf(buf, "\n");
|
|
|
|
nvdimm_bus_unlock(dev);
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
static DEVICE_ATTR_RO(dax_seed);
|
|
|
|
|
2015-06-24 08:08:34 +08:00
|
|
|
static ssize_t read_only_show(struct device *dev,
|
|
|
|
struct device_attribute *attr, char *buf)
|
|
|
|
{
|
|
|
|
struct nd_region *nd_region = to_nd_region(dev);
|
|
|
|
|
|
|
|
return sprintf(buf, "%d\n", nd_region->ro);
|
|
|
|
}
|
|
|
|
|
2021-03-10 09:43:38 +08:00
|
|
|
static int revalidate_read_only(struct device *dev, void *data)
|
|
|
|
{
|
|
|
|
nd_device_notify(dev, NVDIMM_REVALIDATE_REGION);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-06-24 08:08:34 +08:00
|
|
|
static ssize_t read_only_store(struct device *dev,
|
|
|
|
struct device_attribute *attr, const char *buf, size_t len)
|
|
|
|
{
|
|
|
|
bool ro;
|
|
|
|
int rc = strtobool(buf, &ro);
|
|
|
|
struct nd_region *nd_region = to_nd_region(dev);
|
|
|
|
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
nd_region->ro = ro;
|
2021-03-10 09:43:38 +08:00
|
|
|
device_for_each_child(dev, NULL, revalidate_read_only);
|
2015-06-24 08:08:34 +08:00
|
|
|
return len;
|
|
|
|
}
|
|
|
|
static DEVICE_ATTR_RW(read_only);
|
|
|
|
|
2020-01-31 04:06:23 +08:00
|
|
|
static ssize_t align_show(struct device *dev,
|
|
|
|
struct device_attribute *attr, char *buf)
|
|
|
|
{
|
|
|
|
struct nd_region *nd_region = to_nd_region(dev);
|
|
|
|
|
|
|
|
return sprintf(buf, "%#lx\n", nd_region->align);
|
|
|
|
}
|
|
|
|
|
|
|
|
static ssize_t align_store(struct device *dev,
|
|
|
|
struct device_attribute *attr, const char *buf, size_t len)
|
|
|
|
{
|
|
|
|
struct nd_region *nd_region = to_nd_region(dev);
|
|
|
|
unsigned long val, dpa;
|
|
|
|
u32 remainder;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
rc = kstrtoul(buf, 0, &val);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
if (!nd_region->ndr_mappings)
|
|
|
|
return -ENXIO;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Ensure space-align is evenly divisible by the region
|
|
|
|
* interleave-width because the kernel typically has no facility
|
|
|
|
* to determine which DIMM(s), dimm-physical-addresses, would
|
|
|
|
* contribute to the tail capacity in system-physical-address
|
|
|
|
* space for the namespace.
|
|
|
|
*/
|
2020-03-31 19:50:24 +08:00
|
|
|
dpa = div_u64_rem(val, nd_region->ndr_mappings, &remainder);
|
2020-01-31 04:06:23 +08:00
|
|
|
if (!is_power_of_2(dpa) || dpa < PAGE_SIZE
|
|
|
|
|| val > region_size(nd_region) || remainder)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Given that space allocation consults this value multiple
|
|
|
|
* times ensure it does not change for the duration of the
|
|
|
|
* allocation.
|
|
|
|
*/
|
|
|
|
nvdimm_bus_lock(dev);
|
|
|
|
nd_region->align = val;
|
|
|
|
nvdimm_bus_unlock(dev);
|
|
|
|
|
|
|
|
return len;
|
|
|
|
}
|
|
|
|
static DEVICE_ATTR_RW(align);
|
|
|
|
|
2017-04-30 06:24:03 +08:00
|
|
|
static ssize_t region_badblocks_show(struct device *dev,
|
2017-04-08 06:33:20 +08:00
|
|
|
struct device_attribute *attr, char *buf)
|
|
|
|
{
|
|
|
|
struct nd_region *nd_region = to_nd_region(dev);
|
2018-09-28 06:01:55 +08:00
|
|
|
ssize_t rc;
|
2017-04-08 06:33:20 +08:00
|
|
|
|
2022-04-21 23:33:39 +08:00
|
|
|
device_lock(dev);
|
2018-09-28 06:01:55 +08:00
|
|
|
if (dev->driver)
|
|
|
|
rc = badblocks_show(&nd_region->bb, buf, 0);
|
|
|
|
else
|
|
|
|
rc = -ENXIO;
|
2022-04-21 23:33:39 +08:00
|
|
|
device_unlock(dev);
|
2017-04-30 06:24:03 +08:00
|
|
|
|
2018-09-28 06:01:55 +08:00
|
|
|
return rc;
|
|
|
|
}
|
2017-04-30 06:24:03 +08:00
|
|
|
static DEVICE_ATTR(badblocks, 0444, region_badblocks_show, NULL);
|
2017-04-08 06:33:20 +08:00
|
|
|
|
2017-04-08 06:33:25 +08:00
|
|
|
static ssize_t resource_show(struct device *dev,
|
|
|
|
struct device_attribute *attr, char *buf)
|
|
|
|
{
|
|
|
|
struct nd_region *nd_region = to_nd_region(dev);
|
|
|
|
|
|
|
|
return sprintf(buf, "%#llx\n", nd_region->ndr_start);
|
|
|
|
}
|
2020-07-21 06:08:13 +08:00
|
|
|
static DEVICE_ATTR_ADMIN_RO(resource);
|
2017-04-08 06:33:25 +08:00
|
|
|
|
2018-02-01 03:45:49 +08:00
|
|
|
static ssize_t persistence_domain_show(struct device *dev,
|
|
|
|
struct device_attribute *attr, char *buf)
|
|
|
|
{
|
|
|
|
struct nd_region *nd_region = to_nd_region(dev);
|
|
|
|
|
2018-03-22 06:12:07 +08:00
|
|
|
if (test_bit(ND_REGION_PERSIST_CACHE, &nd_region->flags))
|
|
|
|
return sprintf(buf, "cpu_cache\n");
|
|
|
|
else if (test_bit(ND_REGION_PERSIST_MEMCTRL, &nd_region->flags))
|
|
|
|
return sprintf(buf, "memory_controller\n");
|
|
|
|
else
|
|
|
|
return sprintf(buf, "\n");
|
2018-02-01 03:45:49 +08:00
|
|
|
}
|
|
|
|
static DEVICE_ATTR_RO(persistence_domain);
|
|
|
|
|
libnvdimm, nfit: regions (block-data-window, persistent memory, volatile memory)
A "region" device represents the maximum capacity of a BLK range (mmio
block-data-window(s)), or a PMEM range (DAX-capable persistent memory or
volatile memory), without regard for aliasing. Aliasing, in the
dimm-local address space (DPA), is resolved by metadata on a dimm to
designate which exclusive interface will access the aliased DPA ranges.
Support for the per-dimm metadata/label arrvies is in a subsequent
patch.
The name format of "region" devices is "regionN" where, like dimms, N is
a global ida index assigned at discovery time. This id is not reliable
across reboots nor in the presence of hotplug. Look to attributes of
the region or static id-data of the sub-namespace to generate a
persistent name. However, if the platform configuration does not change
it is reasonable to expect the same region id to be assigned at the next
boot.
"region"s have 2 generic attributes "size", and "mapping"s where:
- size: the BLK accessible capacity or the span of the
system physical address range in the case of PMEM.
- mappingN: a tuple describing a dimm's contribution to the region's
capacity in the format (<nmemX>,<dpa>,<size>). For a PMEM-region
there will be at least one mapping per dimm in the interleave set. For
a BLK-region there is only "mapping0" listing the starting DPA of the
BLK-region and the available DPA capacity of that space (matches "size"
above).
The max number of mappings per "region" is hard coded per the
constraints of sysfs attribute groups. That said the number of mappings
per region should never exceed the maximum number of possible dimms in
the system. If the current number turns out to not be enough then the
"mappings" attribute clarifies how many there are supposed to be. "32
should be enough for anybody...".
Cc: Neil Brown <neilb@suse.de>
Cc: <linux-acpi@vger.kernel.org>
Cc: Greg KH <gregkh@linuxfoundation.org>
Cc: Robert Moore <robert.moore@intel.com>
Cc: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Acked-by: Christoph Hellwig <hch@lst.de>
Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Tested-by: Toshi Kani <toshi.kani@hp.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
2015-06-10 08:13:14 +08:00
|
|
|
static struct attribute *nd_region_attributes[] = {
|
|
|
|
&dev_attr_size.attr,
|
2020-01-31 04:06:23 +08:00
|
|
|
&dev_attr_align.attr,
|
2015-06-01 03:02:11 +08:00
|
|
|
&dev_attr_nstype.attr,
|
libnvdimm, nfit: regions (block-data-window, persistent memory, volatile memory)
A "region" device represents the maximum capacity of a BLK range (mmio
block-data-window(s)), or a PMEM range (DAX-capable persistent memory or
volatile memory), without regard for aliasing. Aliasing, in the
dimm-local address space (DPA), is resolved by metadata on a dimm to
designate which exclusive interface will access the aliased DPA ranges.
Support for the per-dimm metadata/label arrvies is in a subsequent
patch.
The name format of "region" devices is "regionN" where, like dimms, N is
a global ida index assigned at discovery time. This id is not reliable
across reboots nor in the presence of hotplug. Look to attributes of
the region or static id-data of the sub-namespace to generate a
persistent name. However, if the platform configuration does not change
it is reasonable to expect the same region id to be assigned at the next
boot.
"region"s have 2 generic attributes "size", and "mapping"s where:
- size: the BLK accessible capacity or the span of the
system physical address range in the case of PMEM.
- mappingN: a tuple describing a dimm's contribution to the region's
capacity in the format (<nmemX>,<dpa>,<size>). For a PMEM-region
there will be at least one mapping per dimm in the interleave set. For
a BLK-region there is only "mapping0" listing the starting DPA of the
BLK-region and the available DPA capacity of that space (matches "size"
above).
The max number of mappings per "region" is hard coded per the
constraints of sysfs attribute groups. That said the number of mappings
per region should never exceed the maximum number of possible dimms in
the system. If the current number turns out to not be enough then the
"mappings" attribute clarifies how many there are supposed to be. "32
should be enough for anybody...".
Cc: Neil Brown <neilb@suse.de>
Cc: <linux-acpi@vger.kernel.org>
Cc: Greg KH <gregkh@linuxfoundation.org>
Cc: Robert Moore <robert.moore@intel.com>
Cc: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Acked-by: Christoph Hellwig <hch@lst.de>
Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Tested-by: Toshi Kani <toshi.kani@hp.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
2015-06-10 08:13:14 +08:00
|
|
|
&dev_attr_mappings.attr,
|
2015-06-25 16:20:04 +08:00
|
|
|
&dev_attr_btt_seed.attr,
|
2015-07-31 05:57:47 +08:00
|
|
|
&dev_attr_pfn_seed.attr,
|
2016-03-12 02:15:36 +08:00
|
|
|
&dev_attr_dax_seed.attr,
|
2017-04-22 04:28:12 +08:00
|
|
|
&dev_attr_deep_flush.attr,
|
2015-06-24 08:08:34 +08:00
|
|
|
&dev_attr_read_only.attr,
|
2015-05-02 01:11:27 +08:00
|
|
|
&dev_attr_set_cookie.attr,
|
2015-06-18 05:14:46 +08:00
|
|
|
&dev_attr_available_size.attr,
|
2018-07-25 05:07:58 +08:00
|
|
|
&dev_attr_max_available_extent.attr,
|
2015-06-18 05:14:46 +08:00
|
|
|
&dev_attr_namespace_seed.attr,
|
2015-06-01 03:02:11 +08:00
|
|
|
&dev_attr_init_namespaces.attr,
|
2017-04-30 06:24:03 +08:00
|
|
|
&dev_attr_badblocks.attr,
|
2017-04-08 06:33:25 +08:00
|
|
|
&dev_attr_resource.attr,
|
2018-02-01 03:45:49 +08:00
|
|
|
&dev_attr_persistence_domain.attr,
|
libnvdimm, nfit: regions (block-data-window, persistent memory, volatile memory)
A "region" device represents the maximum capacity of a BLK range (mmio
block-data-window(s)), or a PMEM range (DAX-capable persistent memory or
volatile memory), without regard for aliasing. Aliasing, in the
dimm-local address space (DPA), is resolved by metadata on a dimm to
designate which exclusive interface will access the aliased DPA ranges.
Support for the per-dimm metadata/label arrvies is in a subsequent
patch.
The name format of "region" devices is "regionN" where, like dimms, N is
a global ida index assigned at discovery time. This id is not reliable
across reboots nor in the presence of hotplug. Look to attributes of
the region or static id-data of the sub-namespace to generate a
persistent name. However, if the platform configuration does not change
it is reasonable to expect the same region id to be assigned at the next
boot.
"region"s have 2 generic attributes "size", and "mapping"s where:
- size: the BLK accessible capacity or the span of the
system physical address range in the case of PMEM.
- mappingN: a tuple describing a dimm's contribution to the region's
capacity in the format (<nmemX>,<dpa>,<size>). For a PMEM-region
there will be at least one mapping per dimm in the interleave set. For
a BLK-region there is only "mapping0" listing the starting DPA of the
BLK-region and the available DPA capacity of that space (matches "size"
above).
The max number of mappings per "region" is hard coded per the
constraints of sysfs attribute groups. That said the number of mappings
per region should never exceed the maximum number of possible dimms in
the system. If the current number turns out to not be enough then the
"mappings" attribute clarifies how many there are supposed to be. "32
should be enough for anybody...".
Cc: Neil Brown <neilb@suse.de>
Cc: <linux-acpi@vger.kernel.org>
Cc: Greg KH <gregkh@linuxfoundation.org>
Cc: Robert Moore <robert.moore@intel.com>
Cc: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Acked-by: Christoph Hellwig <hch@lst.de>
Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Tested-by: Toshi Kani <toshi.kani@hp.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
2015-06-10 08:13:14 +08:00
|
|
|
NULL,
|
|
|
|
};
|
|
|
|
|
2015-05-02 01:11:27 +08:00
|
|
|
static umode_t region_visible(struct kobject *kobj, struct attribute *a, int n)
|
|
|
|
{
|
|
|
|
struct device *dev = container_of(kobj, typeof(*dev), kobj);
|
|
|
|
struct nd_region *nd_region = to_nd_region(dev);
|
|
|
|
struct nd_interleave_set *nd_set = nd_region->nd_set;
|
2015-06-18 05:14:46 +08:00
|
|
|
int type = nd_region_to_nstype(nd_region);
|
2015-05-02 01:11:27 +08:00
|
|
|
|
2017-05-30 14:12:19 +08:00
|
|
|
if (!is_memory(dev) && a == &dev_attr_pfn_seed.attr)
|
2015-12-02 14:39:29 +08:00
|
|
|
return 0;
|
|
|
|
|
2017-05-30 14:12:19 +08:00
|
|
|
if (!is_memory(dev) && a == &dev_attr_dax_seed.attr)
|
2016-03-12 02:15:36 +08:00
|
|
|
return 0;
|
|
|
|
|
2019-09-19 16:33:55 +08:00
|
|
|
if (!is_memory(dev) && a == &dev_attr_badblocks.attr)
|
2017-04-08 06:33:20 +08:00
|
|
|
return 0;
|
|
|
|
|
2019-11-13 09:13:14 +08:00
|
|
|
if (a == &dev_attr_resource.attr && !is_memory(dev))
|
|
|
|
return 0;
|
2017-04-08 06:33:25 +08:00
|
|
|
|
2017-04-22 04:28:12 +08:00
|
|
|
if (a == &dev_attr_deep_flush.attr) {
|
|
|
|
int has_flush = nvdimm_has_flush(nd_region);
|
|
|
|
|
|
|
|
if (has_flush == 1)
|
|
|
|
return a->mode;
|
|
|
|
else if (has_flush == 0)
|
|
|
|
return 0444;
|
|
|
|
else
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-03-22 05:06:23 +08:00
|
|
|
if (a == &dev_attr_persistence_domain.attr) {
|
|
|
|
if ((nd_region->flags & (BIT(ND_REGION_PERSIST_CACHE)
|
|
|
|
| BIT(ND_REGION_PERSIST_MEMCTRL))) == 0)
|
|
|
|
return 0;
|
|
|
|
return a->mode;
|
|
|
|
}
|
|
|
|
|
2020-05-21 06:50:26 +08:00
|
|
|
if (a == &dev_attr_align.attr)
|
|
|
|
return a->mode;
|
2020-01-31 04:06:23 +08:00
|
|
|
|
2015-06-18 05:14:46 +08:00
|
|
|
if (a != &dev_attr_set_cookie.attr
|
|
|
|
&& a != &dev_attr_available_size.attr)
|
2015-05-02 01:11:27 +08:00
|
|
|
return a->mode;
|
|
|
|
|
2022-03-10 11:49:48 +08:00
|
|
|
if (type == ND_DEVICE_NAMESPACE_PMEM &&
|
|
|
|
a == &dev_attr_available_size.attr)
|
2015-06-18 05:14:46 +08:00
|
|
|
return a->mode;
|
2017-05-30 14:12:19 +08:00
|
|
|
else if (is_memory(dev) && nd_set)
|
2015-06-18 05:14:46 +08:00
|
|
|
return a->mode;
|
2015-05-02 01:11:27 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
libnvdimm, nfit: regions (block-data-window, persistent memory, volatile memory)
A "region" device represents the maximum capacity of a BLK range (mmio
block-data-window(s)), or a PMEM range (DAX-capable persistent memory or
volatile memory), without regard for aliasing. Aliasing, in the
dimm-local address space (DPA), is resolved by metadata on a dimm to
designate which exclusive interface will access the aliased DPA ranges.
Support for the per-dimm metadata/label arrvies is in a subsequent
patch.
The name format of "region" devices is "regionN" where, like dimms, N is
a global ida index assigned at discovery time. This id is not reliable
across reboots nor in the presence of hotplug. Look to attributes of
the region or static id-data of the sub-namespace to generate a
persistent name. However, if the platform configuration does not change
it is reasonable to expect the same region id to be assigned at the next
boot.
"region"s have 2 generic attributes "size", and "mapping"s where:
- size: the BLK accessible capacity or the span of the
system physical address range in the case of PMEM.
- mappingN: a tuple describing a dimm's contribution to the region's
capacity in the format (<nmemX>,<dpa>,<size>). For a PMEM-region
there will be at least one mapping per dimm in the interleave set. For
a BLK-region there is only "mapping0" listing the starting DPA of the
BLK-region and the available DPA capacity of that space (matches "size"
above).
The max number of mappings per "region" is hard coded per the
constraints of sysfs attribute groups. That said the number of mappings
per region should never exceed the maximum number of possible dimms in
the system. If the current number turns out to not be enough then the
"mappings" attribute clarifies how many there are supposed to be. "32
should be enough for anybody...".
Cc: Neil Brown <neilb@suse.de>
Cc: <linux-acpi@vger.kernel.org>
Cc: Greg KH <gregkh@linuxfoundation.org>
Cc: Robert Moore <robert.moore@intel.com>
Cc: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Acked-by: Christoph Hellwig <hch@lst.de>
Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Tested-by: Toshi Kani <toshi.kani@hp.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
2015-06-10 08:13:14 +08:00
|
|
|
static ssize_t mappingN(struct device *dev, char *buf, int n)
|
|
|
|
{
|
|
|
|
struct nd_region *nd_region = to_nd_region(dev);
|
|
|
|
struct nd_mapping *nd_mapping;
|
|
|
|
struct nvdimm *nvdimm;
|
|
|
|
|
|
|
|
if (n >= nd_region->ndr_mappings)
|
|
|
|
return -ENXIO;
|
|
|
|
nd_mapping = &nd_region->mapping[n];
|
|
|
|
nvdimm = nd_mapping->nvdimm;
|
|
|
|
|
2017-08-05 08:20:16 +08:00
|
|
|
return sprintf(buf, "%s,%llu,%llu,%d\n", dev_name(&nvdimm->dev),
|
|
|
|
nd_mapping->start, nd_mapping->size,
|
|
|
|
nd_mapping->position);
|
libnvdimm, nfit: regions (block-data-window, persistent memory, volatile memory)
A "region" device represents the maximum capacity of a BLK range (mmio
block-data-window(s)), or a PMEM range (DAX-capable persistent memory or
volatile memory), without regard for aliasing. Aliasing, in the
dimm-local address space (DPA), is resolved by metadata on a dimm to
designate which exclusive interface will access the aliased DPA ranges.
Support for the per-dimm metadata/label arrvies is in a subsequent
patch.
The name format of "region" devices is "regionN" where, like dimms, N is
a global ida index assigned at discovery time. This id is not reliable
across reboots nor in the presence of hotplug. Look to attributes of
the region or static id-data of the sub-namespace to generate a
persistent name. However, if the platform configuration does not change
it is reasonable to expect the same region id to be assigned at the next
boot.
"region"s have 2 generic attributes "size", and "mapping"s where:
- size: the BLK accessible capacity or the span of the
system physical address range in the case of PMEM.
- mappingN: a tuple describing a dimm's contribution to the region's
capacity in the format (<nmemX>,<dpa>,<size>). For a PMEM-region
there will be at least one mapping per dimm in the interleave set. For
a BLK-region there is only "mapping0" listing the starting DPA of the
BLK-region and the available DPA capacity of that space (matches "size"
above).
The max number of mappings per "region" is hard coded per the
constraints of sysfs attribute groups. That said the number of mappings
per region should never exceed the maximum number of possible dimms in
the system. If the current number turns out to not be enough then the
"mappings" attribute clarifies how many there are supposed to be. "32
should be enough for anybody...".
Cc: Neil Brown <neilb@suse.de>
Cc: <linux-acpi@vger.kernel.org>
Cc: Greg KH <gregkh@linuxfoundation.org>
Cc: Robert Moore <robert.moore@intel.com>
Cc: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Acked-by: Christoph Hellwig <hch@lst.de>
Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Tested-by: Toshi Kani <toshi.kani@hp.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
2015-06-10 08:13:14 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
#define REGION_MAPPING(idx) \
|
|
|
|
static ssize_t mapping##idx##_show(struct device *dev, \
|
|
|
|
struct device_attribute *attr, char *buf) \
|
|
|
|
{ \
|
|
|
|
return mappingN(dev, buf, idx); \
|
|
|
|
} \
|
|
|
|
static DEVICE_ATTR_RO(mapping##idx)
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 32 should be enough for a while, even in the presence of socket
|
|
|
|
* interleave a 32-way interleave set is a degenerate case.
|
|
|
|
*/
|
|
|
|
REGION_MAPPING(0);
|
|
|
|
REGION_MAPPING(1);
|
|
|
|
REGION_MAPPING(2);
|
|
|
|
REGION_MAPPING(3);
|
|
|
|
REGION_MAPPING(4);
|
|
|
|
REGION_MAPPING(5);
|
|
|
|
REGION_MAPPING(6);
|
|
|
|
REGION_MAPPING(7);
|
|
|
|
REGION_MAPPING(8);
|
|
|
|
REGION_MAPPING(9);
|
|
|
|
REGION_MAPPING(10);
|
|
|
|
REGION_MAPPING(11);
|
|
|
|
REGION_MAPPING(12);
|
|
|
|
REGION_MAPPING(13);
|
|
|
|
REGION_MAPPING(14);
|
|
|
|
REGION_MAPPING(15);
|
|
|
|
REGION_MAPPING(16);
|
|
|
|
REGION_MAPPING(17);
|
|
|
|
REGION_MAPPING(18);
|
|
|
|
REGION_MAPPING(19);
|
|
|
|
REGION_MAPPING(20);
|
|
|
|
REGION_MAPPING(21);
|
|
|
|
REGION_MAPPING(22);
|
|
|
|
REGION_MAPPING(23);
|
|
|
|
REGION_MAPPING(24);
|
|
|
|
REGION_MAPPING(25);
|
|
|
|
REGION_MAPPING(26);
|
|
|
|
REGION_MAPPING(27);
|
|
|
|
REGION_MAPPING(28);
|
|
|
|
REGION_MAPPING(29);
|
|
|
|
REGION_MAPPING(30);
|
|
|
|
REGION_MAPPING(31);
|
|
|
|
|
|
|
|
static umode_t mapping_visible(struct kobject *kobj, struct attribute *a, int n)
|
|
|
|
{
|
|
|
|
struct device *dev = container_of(kobj, struct device, kobj);
|
|
|
|
struct nd_region *nd_region = to_nd_region(dev);
|
|
|
|
|
|
|
|
if (n < nd_region->ndr_mappings)
|
|
|
|
return a->mode;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct attribute *mapping_attributes[] = {
|
|
|
|
&dev_attr_mapping0.attr,
|
|
|
|
&dev_attr_mapping1.attr,
|
|
|
|
&dev_attr_mapping2.attr,
|
|
|
|
&dev_attr_mapping3.attr,
|
|
|
|
&dev_attr_mapping4.attr,
|
|
|
|
&dev_attr_mapping5.attr,
|
|
|
|
&dev_attr_mapping6.attr,
|
|
|
|
&dev_attr_mapping7.attr,
|
|
|
|
&dev_attr_mapping8.attr,
|
|
|
|
&dev_attr_mapping9.attr,
|
|
|
|
&dev_attr_mapping10.attr,
|
|
|
|
&dev_attr_mapping11.attr,
|
|
|
|
&dev_attr_mapping12.attr,
|
|
|
|
&dev_attr_mapping13.attr,
|
|
|
|
&dev_attr_mapping14.attr,
|
|
|
|
&dev_attr_mapping15.attr,
|
|
|
|
&dev_attr_mapping16.attr,
|
|
|
|
&dev_attr_mapping17.attr,
|
|
|
|
&dev_attr_mapping18.attr,
|
|
|
|
&dev_attr_mapping19.attr,
|
|
|
|
&dev_attr_mapping20.attr,
|
|
|
|
&dev_attr_mapping21.attr,
|
|
|
|
&dev_attr_mapping22.attr,
|
|
|
|
&dev_attr_mapping23.attr,
|
|
|
|
&dev_attr_mapping24.attr,
|
|
|
|
&dev_attr_mapping25.attr,
|
|
|
|
&dev_attr_mapping26.attr,
|
|
|
|
&dev_attr_mapping27.attr,
|
|
|
|
&dev_attr_mapping28.attr,
|
|
|
|
&dev_attr_mapping29.attr,
|
|
|
|
&dev_attr_mapping30.attr,
|
|
|
|
&dev_attr_mapping31.attr,
|
|
|
|
NULL,
|
|
|
|
};
|
|
|
|
|
2019-11-13 09:07:39 +08:00
|
|
|
static const struct attribute_group nd_mapping_attribute_group = {
|
libnvdimm, nfit: regions (block-data-window, persistent memory, volatile memory)
A "region" device represents the maximum capacity of a BLK range (mmio
block-data-window(s)), or a PMEM range (DAX-capable persistent memory or
volatile memory), without regard for aliasing. Aliasing, in the
dimm-local address space (DPA), is resolved by metadata on a dimm to
designate which exclusive interface will access the aliased DPA ranges.
Support for the per-dimm metadata/label arrvies is in a subsequent
patch.
The name format of "region" devices is "regionN" where, like dimms, N is
a global ida index assigned at discovery time. This id is not reliable
across reboots nor in the presence of hotplug. Look to attributes of
the region or static id-data of the sub-namespace to generate a
persistent name. However, if the platform configuration does not change
it is reasonable to expect the same region id to be assigned at the next
boot.
"region"s have 2 generic attributes "size", and "mapping"s where:
- size: the BLK accessible capacity or the span of the
system physical address range in the case of PMEM.
- mappingN: a tuple describing a dimm's contribution to the region's
capacity in the format (<nmemX>,<dpa>,<size>). For a PMEM-region
there will be at least one mapping per dimm in the interleave set. For
a BLK-region there is only "mapping0" listing the starting DPA of the
BLK-region and the available DPA capacity of that space (matches "size"
above).
The max number of mappings per "region" is hard coded per the
constraints of sysfs attribute groups. That said the number of mappings
per region should never exceed the maximum number of possible dimms in
the system. If the current number turns out to not be enough then the
"mappings" attribute clarifies how many there are supposed to be. "32
should be enough for anybody...".
Cc: Neil Brown <neilb@suse.de>
Cc: <linux-acpi@vger.kernel.org>
Cc: Greg KH <gregkh@linuxfoundation.org>
Cc: Robert Moore <robert.moore@intel.com>
Cc: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Acked-by: Christoph Hellwig <hch@lst.de>
Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Tested-by: Toshi Kani <toshi.kani@hp.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
2015-06-10 08:13:14 +08:00
|
|
|
.is_visible = mapping_visible,
|
|
|
|
.attrs = mapping_attributes,
|
|
|
|
};
|
|
|
|
|
2019-11-13 09:07:16 +08:00
|
|
|
static const struct attribute_group nd_region_attribute_group = {
|
2019-11-07 11:56:46 +08:00
|
|
|
.attrs = nd_region_attributes,
|
|
|
|
.is_visible = region_visible,
|
|
|
|
};
|
|
|
|
|
2019-11-13 09:00:24 +08:00
|
|
|
static const struct attribute_group *nd_region_attribute_groups[] = {
|
|
|
|
&nd_device_attribute_group,
|
2019-11-13 09:07:16 +08:00
|
|
|
&nd_region_attribute_group,
|
2019-11-20 01:51:54 +08:00
|
|
|
&nd_numa_attribute_group,
|
2019-11-13 09:07:39 +08:00
|
|
|
&nd_mapping_attribute_group,
|
2019-11-13 09:00:24 +08:00
|
|
|
NULL,
|
|
|
|
};
|
|
|
|
|
|
|
|
static const struct device_type nd_pmem_device_type = {
|
2019-11-07 11:56:46 +08:00
|
|
|
.name = "nd_pmem",
|
|
|
|
.release = nd_region_release,
|
2019-11-13 09:00:24 +08:00
|
|
|
.groups = nd_region_attribute_groups,
|
2019-11-07 11:56:46 +08:00
|
|
|
};
|
|
|
|
|
2019-11-13 09:00:24 +08:00
|
|
|
static const struct device_type nd_volatile_device_type = {
|
2019-11-07 11:56:46 +08:00
|
|
|
.name = "nd_volatile",
|
|
|
|
.release = nd_region_release,
|
2019-11-13 09:00:24 +08:00
|
|
|
.groups = nd_region_attribute_groups,
|
2019-11-07 11:56:46 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
bool is_nd_pmem(struct device *dev)
|
|
|
|
{
|
|
|
|
return dev ? dev->type == &nd_pmem_device_type : false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool is_nd_volatile(struct device *dev)
|
|
|
|
{
|
|
|
|
return dev ? dev->type == &nd_volatile_device_type : false;
|
|
|
|
}
|
|
|
|
|
|
|
|
u64 nd_region_interleave_set_cookie(struct nd_region *nd_region,
|
|
|
|
struct nd_namespace_index *nsindex)
|
|
|
|
{
|
|
|
|
struct nd_interleave_set *nd_set = nd_region->nd_set;
|
|
|
|
|
|
|
|
if (!nd_set)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (nsindex && __le16_to_cpu(nsindex->major) == 1
|
|
|
|
&& __le16_to_cpu(nsindex->minor) == 1)
|
|
|
|
return nd_set->cookie1;
|
|
|
|
return nd_set->cookie2;
|
|
|
|
}
|
|
|
|
|
|
|
|
u64 nd_region_interleave_set_altcookie(struct nd_region *nd_region)
|
|
|
|
{
|
|
|
|
struct nd_interleave_set *nd_set = nd_region->nd_set;
|
|
|
|
|
|
|
|
if (nd_set)
|
|
|
|
return nd_set->altcookie;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void nd_mapping_free_labels(struct nd_mapping *nd_mapping)
|
|
|
|
{
|
|
|
|
struct nd_label_ent *label_ent, *e;
|
|
|
|
|
|
|
|
lockdep_assert_held(&nd_mapping->lock);
|
|
|
|
list_for_each_entry_safe(label_ent, e, &nd_mapping->labels, list) {
|
|
|
|
list_del(&label_ent->list);
|
|
|
|
kfree(label_ent);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* When a namespace is activated create new seeds for the next
|
|
|
|
* namespace, or namespace-personality to be configured.
|
|
|
|
*/
|
|
|
|
void nd_region_advance_seeds(struct nd_region *nd_region, struct device *dev)
|
|
|
|
{
|
|
|
|
nvdimm_bus_lock(dev);
|
|
|
|
if (nd_region->ns_seed == dev) {
|
|
|
|
nd_region_create_ns_seed(nd_region);
|
|
|
|
} else if (is_nd_btt(dev)) {
|
|
|
|
struct nd_btt *nd_btt = to_nd_btt(dev);
|
|
|
|
|
|
|
|
if (nd_region->btt_seed == dev)
|
|
|
|
nd_region_create_btt_seed(nd_region);
|
|
|
|
if (nd_region->ns_seed == &nd_btt->ndns->dev)
|
|
|
|
nd_region_create_ns_seed(nd_region);
|
|
|
|
} else if (is_nd_pfn(dev)) {
|
|
|
|
struct nd_pfn *nd_pfn = to_nd_pfn(dev);
|
|
|
|
|
|
|
|
if (nd_region->pfn_seed == dev)
|
|
|
|
nd_region_create_pfn_seed(nd_region);
|
|
|
|
if (nd_region->ns_seed == &nd_pfn->ndns->dev)
|
|
|
|
nd_region_create_ns_seed(nd_region);
|
|
|
|
} else if (is_nd_dax(dev)) {
|
|
|
|
struct nd_dax *nd_dax = to_nd_dax(dev);
|
|
|
|
|
|
|
|
if (nd_region->dax_seed == dev)
|
|
|
|
nd_region_create_dax_seed(nd_region);
|
|
|
|
if (nd_region->ns_seed == &nd_dax->nd_pfn.ndns->dev)
|
|
|
|
nd_region_create_ns_seed(nd_region);
|
|
|
|
}
|
|
|
|
nvdimm_bus_unlock(dev);
|
|
|
|
}
|
libnvdimm, nfit: regions (block-data-window, persistent memory, volatile memory)
A "region" device represents the maximum capacity of a BLK range (mmio
block-data-window(s)), or a PMEM range (DAX-capable persistent memory or
volatile memory), without regard for aliasing. Aliasing, in the
dimm-local address space (DPA), is resolved by metadata on a dimm to
designate which exclusive interface will access the aliased DPA ranges.
Support for the per-dimm metadata/label arrvies is in a subsequent
patch.
The name format of "region" devices is "regionN" where, like dimms, N is
a global ida index assigned at discovery time. This id is not reliable
across reboots nor in the presence of hotplug. Look to attributes of
the region or static id-data of the sub-namespace to generate a
persistent name. However, if the platform configuration does not change
it is reasonable to expect the same region id to be assigned at the next
boot.
"region"s have 2 generic attributes "size", and "mapping"s where:
- size: the BLK accessible capacity or the span of the
system physical address range in the case of PMEM.
- mappingN: a tuple describing a dimm's contribution to the region's
capacity in the format (<nmemX>,<dpa>,<size>). For a PMEM-region
there will be at least one mapping per dimm in the interleave set. For
a BLK-region there is only "mapping0" listing the starting DPA of the
BLK-region and the available DPA capacity of that space (matches "size"
above).
The max number of mappings per "region" is hard coded per the
constraints of sysfs attribute groups. That said the number of mappings
per region should never exceed the maximum number of possible dimms in
the system. If the current number turns out to not be enough then the
"mappings" attribute clarifies how many there are supposed to be. "32
should be enough for anybody...".
Cc: Neil Brown <neilb@suse.de>
Cc: <linux-acpi@vger.kernel.org>
Cc: Greg KH <gregkh@linuxfoundation.org>
Cc: Robert Moore <robert.moore@intel.com>
Cc: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Acked-by: Christoph Hellwig <hch@lst.de>
Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Tested-by: Toshi Kani <toshi.kani@hp.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
2015-06-10 08:13:14 +08:00
|
|
|
|
nd_btt: atomic sector updates
BTT stands for Block Translation Table, and is a way to provide power
fail sector atomicity semantics for block devices that have the ability
to perform byte granularity IO. It relies on the capability of libnvdimm
namespace devices to do byte aligned IO.
The BTT works as a stacked blocked device, and reserves a chunk of space
from the backing device for its accounting metadata. It is a bio-based
driver because all IO is done synchronously, and there is no queuing or
asynchronous completions at either the device or the driver level.
The BTT uses 'lanes' to index into various 'on-disk' data structures,
and lanes also act as a synchronization mechanism in case there are more
CPUs than available lanes. We did a comparison between two lane lock
strategies - first where we kept an atomic counter around that tracked
which was the last lane that was used, and 'our' lane was determined by
atomically incrementing that. That way, for the nr_cpus > nr_lanes case,
theoretically, no CPU would be blocked waiting for a lane. The other
strategy was to use the cpu number we're scheduled on to and hash it to
a lane number. Theoretically, this could block an IO that could've
otherwise run using a different, free lane. But some fio workloads
showed that the direct cpu -> lane hash performed faster than tracking
'last lane' - my reasoning is the cache thrash caused by moving the
atomic variable made that approach slower than simply waiting out the
in-progress IO. This supports the conclusion that the driver can be a
very simple bio-based one that does synchronous IOs instead of queuing.
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Boaz Harrosh <boaz@plexistor.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Jens Axboe <axboe@fb.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Neil Brown <neilb@suse.de>
Cc: Jeff Moyer <jmoyer@redhat.com>
Cc: Dave Chinner <david@fromorbit.com>
Cc: Greg KH <gregkh@linuxfoundation.org>
[jmoyer: fix nmi watchdog timeout in btt_map_init]
[jmoyer: move btt initialization to module load path]
[jmoyer: fix memory leak in the btt initialization path]
[jmoyer: Don't overwrite corrupted arenas]
Signed-off-by: Vishal Verma <vishal.l.verma@linux.intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
2015-06-25 16:20:32 +08:00
|
|
|
/**
|
|
|
|
* nd_region_acquire_lane - allocate and lock a lane
|
|
|
|
* @nd_region: region id and number of lanes possible
|
|
|
|
*
|
|
|
|
* A lane correlates to a BLK-data-window and/or a log slot in the BTT.
|
|
|
|
* We optimize for the common case where there are 256 lanes, one
|
|
|
|
* per-cpu. For larger systems we need to lock to share lanes. For now
|
|
|
|
* this implementation assumes the cost of maintaining an allocator for
|
|
|
|
* free lanes is on the order of the lock hold time, so it implements a
|
|
|
|
* static lane = cpu % num_lanes mapping.
|
|
|
|
*
|
|
|
|
* In the case of a BTT instance on top of a BLK namespace a lane may be
|
|
|
|
* acquired recursively. We lock on the first instance.
|
|
|
|
*
|
|
|
|
* In the case of a BTT instance on top of PMEM, we only acquire a lane
|
|
|
|
* for the BTT metadata updates.
|
|
|
|
*/
|
|
|
|
unsigned int nd_region_acquire_lane(struct nd_region *nd_region)
|
|
|
|
{
|
|
|
|
unsigned int cpu, lane;
|
|
|
|
|
|
|
|
cpu = get_cpu();
|
|
|
|
if (nd_region->num_lanes < nr_cpu_ids) {
|
|
|
|
struct nd_percpu_lane *ndl_lock, *ndl_count;
|
|
|
|
|
|
|
|
lane = cpu % nd_region->num_lanes;
|
|
|
|
ndl_count = per_cpu_ptr(nd_region->lane, cpu);
|
|
|
|
ndl_lock = per_cpu_ptr(nd_region->lane, lane);
|
|
|
|
if (ndl_count->count++ == 0)
|
|
|
|
spin_lock(&ndl_lock->lock);
|
|
|
|
} else
|
|
|
|
lane = cpu;
|
|
|
|
|
|
|
|
return lane;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(nd_region_acquire_lane);
|
|
|
|
|
|
|
|
void nd_region_release_lane(struct nd_region *nd_region, unsigned int lane)
|
|
|
|
{
|
|
|
|
if (nd_region->num_lanes < nr_cpu_ids) {
|
|
|
|
unsigned int cpu = get_cpu();
|
|
|
|
struct nd_percpu_lane *ndl_lock, *ndl_count;
|
|
|
|
|
|
|
|
ndl_count = per_cpu_ptr(nd_region->lane, cpu);
|
|
|
|
ndl_lock = per_cpu_ptr(nd_region->lane, lane);
|
|
|
|
if (--ndl_count->count == 0)
|
|
|
|
spin_unlock(&ndl_lock->lock);
|
|
|
|
put_cpu();
|
|
|
|
}
|
|
|
|
put_cpu();
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(nd_region_release_lane);
|
|
|
|
|
2020-01-31 04:06:23 +08:00
|
|
|
/*
|
|
|
|
* PowerPC requires this alignment for memremap_pages(). All other archs
|
|
|
|
* should be ok with SUBSECTION_SIZE (see memremap_compat_align()).
|
|
|
|
*/
|
|
|
|
#define MEMREMAP_COMPAT_ALIGN_MAX SZ_16M
|
|
|
|
|
|
|
|
static unsigned long default_align(struct nd_region *nd_region)
|
|
|
|
{
|
2020-03-31 19:50:24 +08:00
|
|
|
unsigned long align;
|
2020-01-31 04:06:23 +08:00
|
|
|
u32 remainder;
|
2022-03-10 11:49:48 +08:00
|
|
|
int mappings;
|
2020-01-31 04:06:23 +08:00
|
|
|
|
2022-03-10 11:49:48 +08:00
|
|
|
align = MEMREMAP_COMPAT_ALIGN_MAX;
|
2022-03-10 11:49:21 +08:00
|
|
|
if (nd_region->ndr_size < MEMREMAP_COMPAT_ALIGN_MAX)
|
|
|
|
align = PAGE_SIZE;
|
|
|
|
|
2020-01-31 04:06:23 +08:00
|
|
|
mappings = max_t(u16, 1, nd_region->ndr_mappings);
|
2020-03-31 19:50:24 +08:00
|
|
|
div_u64_rem(align, mappings, &remainder);
|
2020-01-31 04:06:23 +08:00
|
|
|
if (remainder)
|
|
|
|
align *= mappings;
|
|
|
|
|
|
|
|
return align;
|
|
|
|
}
|
|
|
|
|
2022-04-21 23:33:29 +08:00
|
|
|
static struct lock_class_key nvdimm_region_key;
|
|
|
|
|
libnvdimm, nfit: regions (block-data-window, persistent memory, volatile memory)
A "region" device represents the maximum capacity of a BLK range (mmio
block-data-window(s)), or a PMEM range (DAX-capable persistent memory or
volatile memory), without regard for aliasing. Aliasing, in the
dimm-local address space (DPA), is resolved by metadata on a dimm to
designate which exclusive interface will access the aliased DPA ranges.
Support for the per-dimm metadata/label arrvies is in a subsequent
patch.
The name format of "region" devices is "regionN" where, like dimms, N is
a global ida index assigned at discovery time. This id is not reliable
across reboots nor in the presence of hotplug. Look to attributes of
the region or static id-data of the sub-namespace to generate a
persistent name. However, if the platform configuration does not change
it is reasonable to expect the same region id to be assigned at the next
boot.
"region"s have 2 generic attributes "size", and "mapping"s where:
- size: the BLK accessible capacity or the span of the
system physical address range in the case of PMEM.
- mappingN: a tuple describing a dimm's contribution to the region's
capacity in the format (<nmemX>,<dpa>,<size>). For a PMEM-region
there will be at least one mapping per dimm in the interleave set. For
a BLK-region there is only "mapping0" listing the starting DPA of the
BLK-region and the available DPA capacity of that space (matches "size"
above).
The max number of mappings per "region" is hard coded per the
constraints of sysfs attribute groups. That said the number of mappings
per region should never exceed the maximum number of possible dimms in
the system. If the current number turns out to not be enough then the
"mappings" attribute clarifies how many there are supposed to be. "32
should be enough for anybody...".
Cc: Neil Brown <neilb@suse.de>
Cc: <linux-acpi@vger.kernel.org>
Cc: Greg KH <gregkh@linuxfoundation.org>
Cc: Robert Moore <robert.moore@intel.com>
Cc: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Acked-by: Christoph Hellwig <hch@lst.de>
Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Tested-by: Toshi Kani <toshi.kani@hp.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
2015-06-10 08:13:14 +08:00
|
|
|
static struct nd_region *nd_region_create(struct nvdimm_bus *nvdimm_bus,
|
2019-11-13 09:00:24 +08:00
|
|
|
struct nd_region_desc *ndr_desc,
|
|
|
|
const struct device_type *dev_type, const char *caller)
|
libnvdimm, nfit: regions (block-data-window, persistent memory, volatile memory)
A "region" device represents the maximum capacity of a BLK range (mmio
block-data-window(s)), or a PMEM range (DAX-capable persistent memory or
volatile memory), without regard for aliasing. Aliasing, in the
dimm-local address space (DPA), is resolved by metadata on a dimm to
designate which exclusive interface will access the aliased DPA ranges.
Support for the per-dimm metadata/label arrvies is in a subsequent
patch.
The name format of "region" devices is "regionN" where, like dimms, N is
a global ida index assigned at discovery time. This id is not reliable
across reboots nor in the presence of hotplug. Look to attributes of
the region or static id-data of the sub-namespace to generate a
persistent name. However, if the platform configuration does not change
it is reasonable to expect the same region id to be assigned at the next
boot.
"region"s have 2 generic attributes "size", and "mapping"s where:
- size: the BLK accessible capacity or the span of the
system physical address range in the case of PMEM.
- mappingN: a tuple describing a dimm's contribution to the region's
capacity in the format (<nmemX>,<dpa>,<size>). For a PMEM-region
there will be at least one mapping per dimm in the interleave set. For
a BLK-region there is only "mapping0" listing the starting DPA of the
BLK-region and the available DPA capacity of that space (matches "size"
above).
The max number of mappings per "region" is hard coded per the
constraints of sysfs attribute groups. That said the number of mappings
per region should never exceed the maximum number of possible dimms in
the system. If the current number turns out to not be enough then the
"mappings" attribute clarifies how many there are supposed to be. "32
should be enough for anybody...".
Cc: Neil Brown <neilb@suse.de>
Cc: <linux-acpi@vger.kernel.org>
Cc: Greg KH <gregkh@linuxfoundation.org>
Cc: Robert Moore <robert.moore@intel.com>
Cc: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Acked-by: Christoph Hellwig <hch@lst.de>
Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Tested-by: Toshi Kani <toshi.kani@hp.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
2015-06-10 08:13:14 +08:00
|
|
|
{
|
|
|
|
struct nd_region *nd_region;
|
|
|
|
struct device *dev;
|
nd_btt: atomic sector updates
BTT stands for Block Translation Table, and is a way to provide power
fail sector atomicity semantics for block devices that have the ability
to perform byte granularity IO. It relies on the capability of libnvdimm
namespace devices to do byte aligned IO.
The BTT works as a stacked blocked device, and reserves a chunk of space
from the backing device for its accounting metadata. It is a bio-based
driver because all IO is done synchronously, and there is no queuing or
asynchronous completions at either the device or the driver level.
The BTT uses 'lanes' to index into various 'on-disk' data structures,
and lanes also act as a synchronization mechanism in case there are more
CPUs than available lanes. We did a comparison between two lane lock
strategies - first where we kept an atomic counter around that tracked
which was the last lane that was used, and 'our' lane was determined by
atomically incrementing that. That way, for the nr_cpus > nr_lanes case,
theoretically, no CPU would be blocked waiting for a lane. The other
strategy was to use the cpu number we're scheduled on to and hash it to
a lane number. Theoretically, this could block an IO that could've
otherwise run using a different, free lane. But some fio workloads
showed that the direct cpu -> lane hash performed faster than tracking
'last lane' - my reasoning is the cache thrash caused by moving the
atomic variable made that approach slower than simply waiting out the
in-progress IO. This supports the conclusion that the driver can be a
very simple bio-based one that does synchronous IOs instead of queuing.
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Boaz Harrosh <boaz@plexistor.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Jens Axboe <axboe@fb.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Neil Brown <neilb@suse.de>
Cc: Jeff Moyer <jmoyer@redhat.com>
Cc: Dave Chinner <david@fromorbit.com>
Cc: Greg KH <gregkh@linuxfoundation.org>
[jmoyer: fix nmi watchdog timeout in btt_map_init]
[jmoyer: move btt initialization to module load path]
[jmoyer: fix memory leak in the btt initialization path]
[jmoyer: Don't overwrite corrupted arenas]
Signed-off-by: Vishal Verma <vishal.l.verma@linux.intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
2015-06-25 16:20:32 +08:00
|
|
|
unsigned int i;
|
2015-06-24 08:08:34 +08:00
|
|
|
int ro = 0;
|
libnvdimm, nfit: regions (block-data-window, persistent memory, volatile memory)
A "region" device represents the maximum capacity of a BLK range (mmio
block-data-window(s)), or a PMEM range (DAX-capable persistent memory or
volatile memory), without regard for aliasing. Aliasing, in the
dimm-local address space (DPA), is resolved by metadata on a dimm to
designate which exclusive interface will access the aliased DPA ranges.
Support for the per-dimm metadata/label arrvies is in a subsequent
patch.
The name format of "region" devices is "regionN" where, like dimms, N is
a global ida index assigned at discovery time. This id is not reliable
across reboots nor in the presence of hotplug. Look to attributes of
the region or static id-data of the sub-namespace to generate a
persistent name. However, if the platform configuration does not change
it is reasonable to expect the same region id to be assigned at the next
boot.
"region"s have 2 generic attributes "size", and "mapping"s where:
- size: the BLK accessible capacity or the span of the
system physical address range in the case of PMEM.
- mappingN: a tuple describing a dimm's contribution to the region's
capacity in the format (<nmemX>,<dpa>,<size>). For a PMEM-region
there will be at least one mapping per dimm in the interleave set. For
a BLK-region there is only "mapping0" listing the starting DPA of the
BLK-region and the available DPA capacity of that space (matches "size"
above).
The max number of mappings per "region" is hard coded per the
constraints of sysfs attribute groups. That said the number of mappings
per region should never exceed the maximum number of possible dimms in
the system. If the current number turns out to not be enough then the
"mappings" attribute clarifies how many there are supposed to be. "32
should be enough for anybody...".
Cc: Neil Brown <neilb@suse.de>
Cc: <linux-acpi@vger.kernel.org>
Cc: Greg KH <gregkh@linuxfoundation.org>
Cc: Robert Moore <robert.moore@intel.com>
Cc: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Acked-by: Christoph Hellwig <hch@lst.de>
Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Tested-by: Toshi Kani <toshi.kani@hp.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
2015-06-10 08:13:14 +08:00
|
|
|
|
|
|
|
for (i = 0; i < ndr_desc->num_mappings; i++) {
|
2016-09-20 07:38:50 +08:00
|
|
|
struct nd_mapping_desc *mapping = &ndr_desc->mapping[i];
|
|
|
|
struct nvdimm *nvdimm = mapping->nvdimm;
|
libnvdimm, nfit: regions (block-data-window, persistent memory, volatile memory)
A "region" device represents the maximum capacity of a BLK range (mmio
block-data-window(s)), or a PMEM range (DAX-capable persistent memory or
volatile memory), without regard for aliasing. Aliasing, in the
dimm-local address space (DPA), is resolved by metadata on a dimm to
designate which exclusive interface will access the aliased DPA ranges.
Support for the per-dimm metadata/label arrvies is in a subsequent
patch.
The name format of "region" devices is "regionN" where, like dimms, N is
a global ida index assigned at discovery time. This id is not reliable
across reboots nor in the presence of hotplug. Look to attributes of
the region or static id-data of the sub-namespace to generate a
persistent name. However, if the platform configuration does not change
it is reasonable to expect the same region id to be assigned at the next
boot.
"region"s have 2 generic attributes "size", and "mapping"s where:
- size: the BLK accessible capacity or the span of the
system physical address range in the case of PMEM.
- mappingN: a tuple describing a dimm's contribution to the region's
capacity in the format (<nmemX>,<dpa>,<size>). For a PMEM-region
there will be at least one mapping per dimm in the interleave set. For
a BLK-region there is only "mapping0" listing the starting DPA of the
BLK-region and the available DPA capacity of that space (matches "size"
above).
The max number of mappings per "region" is hard coded per the
constraints of sysfs attribute groups. That said the number of mappings
per region should never exceed the maximum number of possible dimms in
the system. If the current number turns out to not be enough then the
"mappings" attribute clarifies how many there are supposed to be. "32
should be enough for anybody...".
Cc: Neil Brown <neilb@suse.de>
Cc: <linux-acpi@vger.kernel.org>
Cc: Greg KH <gregkh@linuxfoundation.org>
Cc: Robert Moore <robert.moore@intel.com>
Cc: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Acked-by: Christoph Hellwig <hch@lst.de>
Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Tested-by: Toshi Kani <toshi.kani@hp.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
2015-06-10 08:13:14 +08:00
|
|
|
|
2019-09-05 23:46:02 +08:00
|
|
|
if ((mapping->start | mapping->size) % PAGE_SIZE) {
|
|
|
|
dev_err(&nvdimm_bus->dev,
|
|
|
|
"%s: %s mapping%d is not %ld aligned\n",
|
|
|
|
caller, dev_name(&nvdimm->dev), i, PAGE_SIZE);
|
libnvdimm, nfit: regions (block-data-window, persistent memory, volatile memory)
A "region" device represents the maximum capacity of a BLK range (mmio
block-data-window(s)), or a PMEM range (DAX-capable persistent memory or
volatile memory), without regard for aliasing. Aliasing, in the
dimm-local address space (DPA), is resolved by metadata on a dimm to
designate which exclusive interface will access the aliased DPA ranges.
Support for the per-dimm metadata/label arrvies is in a subsequent
patch.
The name format of "region" devices is "regionN" where, like dimms, N is
a global ida index assigned at discovery time. This id is not reliable
across reboots nor in the presence of hotplug. Look to attributes of
the region or static id-data of the sub-namespace to generate a
persistent name. However, if the platform configuration does not change
it is reasonable to expect the same region id to be assigned at the next
boot.
"region"s have 2 generic attributes "size", and "mapping"s where:
- size: the BLK accessible capacity or the span of the
system physical address range in the case of PMEM.
- mappingN: a tuple describing a dimm's contribution to the region's
capacity in the format (<nmemX>,<dpa>,<size>). For a PMEM-region
there will be at least one mapping per dimm in the interleave set. For
a BLK-region there is only "mapping0" listing the starting DPA of the
BLK-region and the available DPA capacity of that space (matches "size"
above).
The max number of mappings per "region" is hard coded per the
constraints of sysfs attribute groups. That said the number of mappings
per region should never exceed the maximum number of possible dimms in
the system. If the current number turns out to not be enough then the
"mappings" attribute clarifies how many there are supposed to be. "32
should be enough for anybody...".
Cc: Neil Brown <neilb@suse.de>
Cc: <linux-acpi@vger.kernel.org>
Cc: Greg KH <gregkh@linuxfoundation.org>
Cc: Robert Moore <robert.moore@intel.com>
Cc: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Acked-by: Christoph Hellwig <hch@lst.de>
Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Tested-by: Toshi Kani <toshi.kani@hp.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
2015-06-10 08:13:14 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
2015-06-24 08:08:34 +08:00
|
|
|
|
2017-05-05 05:01:24 +08:00
|
|
|
if (test_bit(NDD_UNARMED, &nvdimm->flags))
|
2015-06-24 08:08:34 +08:00
|
|
|
ro = 1;
|
2019-02-03 08:35:26 +08:00
|
|
|
|
libnvdimm, nfit: regions (block-data-window, persistent memory, volatile memory)
A "region" device represents the maximum capacity of a BLK range (mmio
block-data-window(s)), or a PMEM range (DAX-capable persistent memory or
volatile memory), without regard for aliasing. Aliasing, in the
dimm-local address space (DPA), is resolved by metadata on a dimm to
designate which exclusive interface will access the aliased DPA ranges.
Support for the per-dimm metadata/label arrvies is in a subsequent
patch.
The name format of "region" devices is "regionN" where, like dimms, N is
a global ida index assigned at discovery time. This id is not reliable
across reboots nor in the presence of hotplug. Look to attributes of
the region or static id-data of the sub-namespace to generate a
persistent name. However, if the platform configuration does not change
it is reasonable to expect the same region id to be assigned at the next
boot.
"region"s have 2 generic attributes "size", and "mapping"s where:
- size: the BLK accessible capacity or the span of the
system physical address range in the case of PMEM.
- mappingN: a tuple describing a dimm's contribution to the region's
capacity in the format (<nmemX>,<dpa>,<size>). For a PMEM-region
there will be at least one mapping per dimm in the interleave set. For
a BLK-region there is only "mapping0" listing the starting DPA of the
BLK-region and the available DPA capacity of that space (matches "size"
above).
The max number of mappings per "region" is hard coded per the
constraints of sysfs attribute groups. That said the number of mappings
per region should never exceed the maximum number of possible dimms in
the system. If the current number turns out to not be enough then the
"mappings" attribute clarifies how many there are supposed to be. "32
should be enough for anybody...".
Cc: Neil Brown <neilb@suse.de>
Cc: <linux-acpi@vger.kernel.org>
Cc: Greg KH <gregkh@linuxfoundation.org>
Cc: Robert Moore <robert.moore@intel.com>
Cc: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Acked-by: Christoph Hellwig <hch@lst.de>
Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Tested-by: Toshi Kani <toshi.kani@hp.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
2015-06-10 08:13:14 +08:00
|
|
|
}
|
|
|
|
|
2022-03-10 11:49:48 +08:00
|
|
|
nd_region =
|
|
|
|
kzalloc(struct_size(nd_region, mapping, ndr_desc->num_mappings),
|
|
|
|
GFP_KERNEL);
|
2015-06-25 16:21:02 +08:00
|
|
|
|
2022-03-10 11:49:48 +08:00
|
|
|
if (!nd_region)
|
libnvdimm, nfit: regions (block-data-window, persistent memory, volatile memory)
A "region" device represents the maximum capacity of a BLK range (mmio
block-data-window(s)), or a PMEM range (DAX-capable persistent memory or
volatile memory), without regard for aliasing. Aliasing, in the
dimm-local address space (DPA), is resolved by metadata on a dimm to
designate which exclusive interface will access the aliased DPA ranges.
Support for the per-dimm metadata/label arrvies is in a subsequent
patch.
The name format of "region" devices is "regionN" where, like dimms, N is
a global ida index assigned at discovery time. This id is not reliable
across reboots nor in the presence of hotplug. Look to attributes of
the region or static id-data of the sub-namespace to generate a
persistent name. However, if the platform configuration does not change
it is reasonable to expect the same region id to be assigned at the next
boot.
"region"s have 2 generic attributes "size", and "mapping"s where:
- size: the BLK accessible capacity or the span of the
system physical address range in the case of PMEM.
- mappingN: a tuple describing a dimm's contribution to the region's
capacity in the format (<nmemX>,<dpa>,<size>). For a PMEM-region
there will be at least one mapping per dimm in the interleave set. For
a BLK-region there is only "mapping0" listing the starting DPA of the
BLK-region and the available DPA capacity of that space (matches "size"
above).
The max number of mappings per "region" is hard coded per the
constraints of sysfs attribute groups. That said the number of mappings
per region should never exceed the maximum number of possible dimms in
the system. If the current number turns out to not be enough then the
"mappings" attribute clarifies how many there are supposed to be. "32
should be enough for anybody...".
Cc: Neil Brown <neilb@suse.de>
Cc: <linux-acpi@vger.kernel.org>
Cc: Greg KH <gregkh@linuxfoundation.org>
Cc: Robert Moore <robert.moore@intel.com>
Cc: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Acked-by: Christoph Hellwig <hch@lst.de>
Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Tested-by: Toshi Kani <toshi.kani@hp.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
2015-06-10 08:13:14 +08:00
|
|
|
return NULL;
|
2019-11-07 09:43:31 +08:00
|
|
|
nd_region->id = memregion_alloc(GFP_KERNEL);
|
nd_btt: atomic sector updates
BTT stands for Block Translation Table, and is a way to provide power
fail sector atomicity semantics for block devices that have the ability
to perform byte granularity IO. It relies on the capability of libnvdimm
namespace devices to do byte aligned IO.
The BTT works as a stacked blocked device, and reserves a chunk of space
from the backing device for its accounting metadata. It is a bio-based
driver because all IO is done synchronously, and there is no queuing or
asynchronous completions at either the device or the driver level.
The BTT uses 'lanes' to index into various 'on-disk' data structures,
and lanes also act as a synchronization mechanism in case there are more
CPUs than available lanes. We did a comparison between two lane lock
strategies - first where we kept an atomic counter around that tracked
which was the last lane that was used, and 'our' lane was determined by
atomically incrementing that. That way, for the nr_cpus > nr_lanes case,
theoretically, no CPU would be blocked waiting for a lane. The other
strategy was to use the cpu number we're scheduled on to and hash it to
a lane number. Theoretically, this could block an IO that could've
otherwise run using a different, free lane. But some fio workloads
showed that the direct cpu -> lane hash performed faster than tracking
'last lane' - my reasoning is the cache thrash caused by moving the
atomic variable made that approach slower than simply waiting out the
in-progress IO. This supports the conclusion that the driver can be a
very simple bio-based one that does synchronous IOs instead of queuing.
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Boaz Harrosh <boaz@plexistor.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Jens Axboe <axboe@fb.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Neil Brown <neilb@suse.de>
Cc: Jeff Moyer <jmoyer@redhat.com>
Cc: Dave Chinner <david@fromorbit.com>
Cc: Greg KH <gregkh@linuxfoundation.org>
[jmoyer: fix nmi watchdog timeout in btt_map_init]
[jmoyer: move btt initialization to module load path]
[jmoyer: fix memory leak in the btt initialization path]
[jmoyer: Don't overwrite corrupted arenas]
Signed-off-by: Vishal Verma <vishal.l.verma@linux.intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
2015-06-25 16:20:32 +08:00
|
|
|
if (nd_region->id < 0)
|
|
|
|
goto err_id;
|
|
|
|
|
|
|
|
nd_region->lane = alloc_percpu(struct nd_percpu_lane);
|
|
|
|
if (!nd_region->lane)
|
|
|
|
goto err_percpu;
|
|
|
|
|
|
|
|
for (i = 0; i < nr_cpu_ids; i++) {
|
|
|
|
struct nd_percpu_lane *ndl;
|
|
|
|
|
|
|
|
ndl = per_cpu_ptr(nd_region->lane, i);
|
|
|
|
spin_lock_init(&ndl->lock);
|
|
|
|
ndl->count = 0;
|
libnvdimm, nfit: regions (block-data-window, persistent memory, volatile memory)
A "region" device represents the maximum capacity of a BLK range (mmio
block-data-window(s)), or a PMEM range (DAX-capable persistent memory or
volatile memory), without regard for aliasing. Aliasing, in the
dimm-local address space (DPA), is resolved by metadata on a dimm to
designate which exclusive interface will access the aliased DPA ranges.
Support for the per-dimm metadata/label arrvies is in a subsequent
patch.
The name format of "region" devices is "regionN" where, like dimms, N is
a global ida index assigned at discovery time. This id is not reliable
across reboots nor in the presence of hotplug. Look to attributes of
the region or static id-data of the sub-namespace to generate a
persistent name. However, if the platform configuration does not change
it is reasonable to expect the same region id to be assigned at the next
boot.
"region"s have 2 generic attributes "size", and "mapping"s where:
- size: the BLK accessible capacity or the span of the
system physical address range in the case of PMEM.
- mappingN: a tuple describing a dimm's contribution to the region's
capacity in the format (<nmemX>,<dpa>,<size>). For a PMEM-region
there will be at least one mapping per dimm in the interleave set. For
a BLK-region there is only "mapping0" listing the starting DPA of the
BLK-region and the available DPA capacity of that space (matches "size"
above).
The max number of mappings per "region" is hard coded per the
constraints of sysfs attribute groups. That said the number of mappings
per region should never exceed the maximum number of possible dimms in
the system. If the current number turns out to not be enough then the
"mappings" attribute clarifies how many there are supposed to be. "32
should be enough for anybody...".
Cc: Neil Brown <neilb@suse.de>
Cc: <linux-acpi@vger.kernel.org>
Cc: Greg KH <gregkh@linuxfoundation.org>
Cc: Robert Moore <robert.moore@intel.com>
Cc: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Acked-by: Christoph Hellwig <hch@lst.de>
Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Tested-by: Toshi Kani <toshi.kani@hp.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
2015-06-10 08:13:14 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < ndr_desc->num_mappings; i++) {
|
2016-09-20 07:38:50 +08:00
|
|
|
struct nd_mapping_desc *mapping = &ndr_desc->mapping[i];
|
|
|
|
struct nvdimm *nvdimm = mapping->nvdimm;
|
|
|
|
|
|
|
|
nd_region->mapping[i].nvdimm = nvdimm;
|
|
|
|
nd_region->mapping[i].start = mapping->start;
|
|
|
|
nd_region->mapping[i].size = mapping->size;
|
2017-08-05 08:20:16 +08:00
|
|
|
nd_region->mapping[i].position = mapping->position;
|
2016-09-20 07:04:21 +08:00
|
|
|
INIT_LIST_HEAD(&nd_region->mapping[i].labels);
|
|
|
|
mutex_init(&nd_region->mapping[i].lock);
|
libnvdimm, nfit: regions (block-data-window, persistent memory, volatile memory)
A "region" device represents the maximum capacity of a BLK range (mmio
block-data-window(s)), or a PMEM range (DAX-capable persistent memory or
volatile memory), without regard for aliasing. Aliasing, in the
dimm-local address space (DPA), is resolved by metadata on a dimm to
designate which exclusive interface will access the aliased DPA ranges.
Support for the per-dimm metadata/label arrvies is in a subsequent
patch.
The name format of "region" devices is "regionN" where, like dimms, N is
a global ida index assigned at discovery time. This id is not reliable
across reboots nor in the presence of hotplug. Look to attributes of
the region or static id-data of the sub-namespace to generate a
persistent name. However, if the platform configuration does not change
it is reasonable to expect the same region id to be assigned at the next
boot.
"region"s have 2 generic attributes "size", and "mapping"s where:
- size: the BLK accessible capacity or the span of the
system physical address range in the case of PMEM.
- mappingN: a tuple describing a dimm's contribution to the region's
capacity in the format (<nmemX>,<dpa>,<size>). For a PMEM-region
there will be at least one mapping per dimm in the interleave set. For
a BLK-region there is only "mapping0" listing the starting DPA of the
BLK-region and the available DPA capacity of that space (matches "size"
above).
The max number of mappings per "region" is hard coded per the
constraints of sysfs attribute groups. That said the number of mappings
per region should never exceed the maximum number of possible dimms in
the system. If the current number turns out to not be enough then the
"mappings" attribute clarifies how many there are supposed to be. "32
should be enough for anybody...".
Cc: Neil Brown <neilb@suse.de>
Cc: <linux-acpi@vger.kernel.org>
Cc: Greg KH <gregkh@linuxfoundation.org>
Cc: Robert Moore <robert.moore@intel.com>
Cc: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Acked-by: Christoph Hellwig <hch@lst.de>
Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Tested-by: Toshi Kani <toshi.kani@hp.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
2015-06-10 08:13:14 +08:00
|
|
|
|
|
|
|
get_device(&nvdimm->dev);
|
|
|
|
}
|
|
|
|
nd_region->ndr_mappings = ndr_desc->num_mappings;
|
|
|
|
nd_region->provider_data = ndr_desc->provider_data;
|
2015-05-02 01:11:27 +08:00
|
|
|
nd_region->nd_set = ndr_desc->nd_set;
|
nd_btt: atomic sector updates
BTT stands for Block Translation Table, and is a way to provide power
fail sector atomicity semantics for block devices that have the ability
to perform byte granularity IO. It relies on the capability of libnvdimm
namespace devices to do byte aligned IO.
The BTT works as a stacked blocked device, and reserves a chunk of space
from the backing device for its accounting metadata. It is a bio-based
driver because all IO is done synchronously, and there is no queuing or
asynchronous completions at either the device or the driver level.
The BTT uses 'lanes' to index into various 'on-disk' data structures,
and lanes also act as a synchronization mechanism in case there are more
CPUs than available lanes. We did a comparison between two lane lock
strategies - first where we kept an atomic counter around that tracked
which was the last lane that was used, and 'our' lane was determined by
atomically incrementing that. That way, for the nr_cpus > nr_lanes case,
theoretically, no CPU would be blocked waiting for a lane. The other
strategy was to use the cpu number we're scheduled on to and hash it to
a lane number. Theoretically, this could block an IO that could've
otherwise run using a different, free lane. But some fio workloads
showed that the direct cpu -> lane hash performed faster than tracking
'last lane' - my reasoning is the cache thrash caused by moving the
atomic variable made that approach slower than simply waiting out the
in-progress IO. This supports the conclusion that the driver can be a
very simple bio-based one that does synchronous IOs instead of queuing.
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Boaz Harrosh <boaz@plexistor.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Jens Axboe <axboe@fb.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Neil Brown <neilb@suse.de>
Cc: Jeff Moyer <jmoyer@redhat.com>
Cc: Dave Chinner <david@fromorbit.com>
Cc: Greg KH <gregkh@linuxfoundation.org>
[jmoyer: fix nmi watchdog timeout in btt_map_init]
[jmoyer: move btt initialization to module load path]
[jmoyer: fix memory leak in the btt initialization path]
[jmoyer: Don't overwrite corrupted arenas]
Signed-off-by: Vishal Verma <vishal.l.verma@linux.intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
2015-06-25 16:20:32 +08:00
|
|
|
nd_region->num_lanes = ndr_desc->num_lanes;
|
2015-08-25 07:20:23 +08:00
|
|
|
nd_region->flags = ndr_desc->flags;
|
2015-06-24 08:08:34 +08:00
|
|
|
nd_region->ro = ro;
|
2015-06-20 02:18:33 +08:00
|
|
|
nd_region->numa_node = ndr_desc->numa_node;
|
2018-11-10 04:43:07 +08:00
|
|
|
nd_region->target_node = ndr_desc->target_node;
|
2015-05-02 01:34:01 +08:00
|
|
|
ida_init(&nd_region->ns_ida);
|
2015-06-25 16:20:04 +08:00
|
|
|
ida_init(&nd_region->btt_ida);
|
2015-07-31 05:57:47 +08:00
|
|
|
ida_init(&nd_region->pfn_ida);
|
2016-03-12 02:15:36 +08:00
|
|
|
ida_init(&nd_region->dax_ida);
|
libnvdimm, nfit: regions (block-data-window, persistent memory, volatile memory)
A "region" device represents the maximum capacity of a BLK range (mmio
block-data-window(s)), or a PMEM range (DAX-capable persistent memory or
volatile memory), without regard for aliasing. Aliasing, in the
dimm-local address space (DPA), is resolved by metadata on a dimm to
designate which exclusive interface will access the aliased DPA ranges.
Support for the per-dimm metadata/label arrvies is in a subsequent
patch.
The name format of "region" devices is "regionN" where, like dimms, N is
a global ida index assigned at discovery time. This id is not reliable
across reboots nor in the presence of hotplug. Look to attributes of
the region or static id-data of the sub-namespace to generate a
persistent name. However, if the platform configuration does not change
it is reasonable to expect the same region id to be assigned at the next
boot.
"region"s have 2 generic attributes "size", and "mapping"s where:
- size: the BLK accessible capacity or the span of the
system physical address range in the case of PMEM.
- mappingN: a tuple describing a dimm's contribution to the region's
capacity in the format (<nmemX>,<dpa>,<size>). For a PMEM-region
there will be at least one mapping per dimm in the interleave set. For
a BLK-region there is only "mapping0" listing the starting DPA of the
BLK-region and the available DPA capacity of that space (matches "size"
above).
The max number of mappings per "region" is hard coded per the
constraints of sysfs attribute groups. That said the number of mappings
per region should never exceed the maximum number of possible dimms in
the system. If the current number turns out to not be enough then the
"mappings" attribute clarifies how many there are supposed to be. "32
should be enough for anybody...".
Cc: Neil Brown <neilb@suse.de>
Cc: <linux-acpi@vger.kernel.org>
Cc: Greg KH <gregkh@linuxfoundation.org>
Cc: Robert Moore <robert.moore@intel.com>
Cc: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Acked-by: Christoph Hellwig <hch@lst.de>
Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Tested-by: Toshi Kani <toshi.kani@hp.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
2015-06-10 08:13:14 +08:00
|
|
|
dev = &nd_region->dev;
|
|
|
|
dev_set_name(dev, "region%d", nd_region->id);
|
|
|
|
dev->parent = &nvdimm_bus->dev;
|
|
|
|
dev->type = dev_type;
|
|
|
|
dev->groups = ndr_desc->attr_groups;
|
2018-04-06 13:21:13 +08:00
|
|
|
dev->of_node = ndr_desc->of_node;
|
libnvdimm, nfit: regions (block-data-window, persistent memory, volatile memory)
A "region" device represents the maximum capacity of a BLK range (mmio
block-data-window(s)), or a PMEM range (DAX-capable persistent memory or
volatile memory), without regard for aliasing. Aliasing, in the
dimm-local address space (DPA), is resolved by metadata on a dimm to
designate which exclusive interface will access the aliased DPA ranges.
Support for the per-dimm metadata/label arrvies is in a subsequent
patch.
The name format of "region" devices is "regionN" where, like dimms, N is
a global ida index assigned at discovery time. This id is not reliable
across reboots nor in the presence of hotplug. Look to attributes of
the region or static id-data of the sub-namespace to generate a
persistent name. However, if the platform configuration does not change
it is reasonable to expect the same region id to be assigned at the next
boot.
"region"s have 2 generic attributes "size", and "mapping"s where:
- size: the BLK accessible capacity or the span of the
system physical address range in the case of PMEM.
- mappingN: a tuple describing a dimm's contribution to the region's
capacity in the format (<nmemX>,<dpa>,<size>). For a PMEM-region
there will be at least one mapping per dimm in the interleave set. For
a BLK-region there is only "mapping0" listing the starting DPA of the
BLK-region and the available DPA capacity of that space (matches "size"
above).
The max number of mappings per "region" is hard coded per the
constraints of sysfs attribute groups. That said the number of mappings
per region should never exceed the maximum number of possible dimms in
the system. If the current number turns out to not be enough then the
"mappings" attribute clarifies how many there are supposed to be. "32
should be enough for anybody...".
Cc: Neil Brown <neilb@suse.de>
Cc: <linux-acpi@vger.kernel.org>
Cc: Greg KH <gregkh@linuxfoundation.org>
Cc: Robert Moore <robert.moore@intel.com>
Cc: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Acked-by: Christoph Hellwig <hch@lst.de>
Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Tested-by: Toshi Kani <toshi.kani@hp.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
2015-06-10 08:13:14 +08:00
|
|
|
nd_region->ndr_size = resource_size(ndr_desc->res);
|
|
|
|
nd_region->ndr_start = ndr_desc->res->start;
|
2020-01-31 04:06:23 +08:00
|
|
|
nd_region->align = default_align(nd_region);
|
2019-07-05 22:03:22 +08:00
|
|
|
if (ndr_desc->flush)
|
|
|
|
nd_region->flush = ndr_desc->flush;
|
|
|
|
else
|
|
|
|
nd_region->flush = NULL;
|
|
|
|
|
2022-04-21 23:33:29 +08:00
|
|
|
device_initialize(dev);
|
|
|
|
lockdep_set_class(&dev->mutex, &nvdimm_region_key);
|
libnvdimm, nfit: regions (block-data-window, persistent memory, volatile memory)
A "region" device represents the maximum capacity of a BLK range (mmio
block-data-window(s)), or a PMEM range (DAX-capable persistent memory or
volatile memory), without regard for aliasing. Aliasing, in the
dimm-local address space (DPA), is resolved by metadata on a dimm to
designate which exclusive interface will access the aliased DPA ranges.
Support for the per-dimm metadata/label arrvies is in a subsequent
patch.
The name format of "region" devices is "regionN" where, like dimms, N is
a global ida index assigned at discovery time. This id is not reliable
across reboots nor in the presence of hotplug. Look to attributes of
the region or static id-data of the sub-namespace to generate a
persistent name. However, if the platform configuration does not change
it is reasonable to expect the same region id to be assigned at the next
boot.
"region"s have 2 generic attributes "size", and "mapping"s where:
- size: the BLK accessible capacity or the span of the
system physical address range in the case of PMEM.
- mappingN: a tuple describing a dimm's contribution to the region's
capacity in the format (<nmemX>,<dpa>,<size>). For a PMEM-region
there will be at least one mapping per dimm in the interleave set. For
a BLK-region there is only "mapping0" listing the starting DPA of the
BLK-region and the available DPA capacity of that space (matches "size"
above).
The max number of mappings per "region" is hard coded per the
constraints of sysfs attribute groups. That said the number of mappings
per region should never exceed the maximum number of possible dimms in
the system. If the current number turns out to not be enough then the
"mappings" attribute clarifies how many there are supposed to be. "32
should be enough for anybody...".
Cc: Neil Brown <neilb@suse.de>
Cc: <linux-acpi@vger.kernel.org>
Cc: Greg KH <gregkh@linuxfoundation.org>
Cc: Robert Moore <robert.moore@intel.com>
Cc: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Acked-by: Christoph Hellwig <hch@lst.de>
Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Tested-by: Toshi Kani <toshi.kani@hp.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
2015-06-10 08:13:14 +08:00
|
|
|
nd_device_register(dev);
|
|
|
|
|
|
|
|
return nd_region;
|
nd_btt: atomic sector updates
BTT stands for Block Translation Table, and is a way to provide power
fail sector atomicity semantics for block devices that have the ability
to perform byte granularity IO. It relies on the capability of libnvdimm
namespace devices to do byte aligned IO.
The BTT works as a stacked blocked device, and reserves a chunk of space
from the backing device for its accounting metadata. It is a bio-based
driver because all IO is done synchronously, and there is no queuing or
asynchronous completions at either the device or the driver level.
The BTT uses 'lanes' to index into various 'on-disk' data structures,
and lanes also act as a synchronization mechanism in case there are more
CPUs than available lanes. We did a comparison between two lane lock
strategies - first where we kept an atomic counter around that tracked
which was the last lane that was used, and 'our' lane was determined by
atomically incrementing that. That way, for the nr_cpus > nr_lanes case,
theoretically, no CPU would be blocked waiting for a lane. The other
strategy was to use the cpu number we're scheduled on to and hash it to
a lane number. Theoretically, this could block an IO that could've
otherwise run using a different, free lane. But some fio workloads
showed that the direct cpu -> lane hash performed faster than tracking
'last lane' - my reasoning is the cache thrash caused by moving the
atomic variable made that approach slower than simply waiting out the
in-progress IO. This supports the conclusion that the driver can be a
very simple bio-based one that does synchronous IOs instead of queuing.
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Boaz Harrosh <boaz@plexistor.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Jens Axboe <axboe@fb.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Neil Brown <neilb@suse.de>
Cc: Jeff Moyer <jmoyer@redhat.com>
Cc: Dave Chinner <david@fromorbit.com>
Cc: Greg KH <gregkh@linuxfoundation.org>
[jmoyer: fix nmi watchdog timeout in btt_map_init]
[jmoyer: move btt initialization to module load path]
[jmoyer: fix memory leak in the btt initialization path]
[jmoyer: Don't overwrite corrupted arenas]
Signed-off-by: Vishal Verma <vishal.l.verma@linux.intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
2015-06-25 16:20:32 +08:00
|
|
|
|
|
|
|
err_percpu:
|
2019-11-07 09:43:31 +08:00
|
|
|
memregion_free(nd_region->id);
|
nd_btt: atomic sector updates
BTT stands for Block Translation Table, and is a way to provide power
fail sector atomicity semantics for block devices that have the ability
to perform byte granularity IO. It relies on the capability of libnvdimm
namespace devices to do byte aligned IO.
The BTT works as a stacked blocked device, and reserves a chunk of space
from the backing device for its accounting metadata. It is a bio-based
driver because all IO is done synchronously, and there is no queuing or
asynchronous completions at either the device or the driver level.
The BTT uses 'lanes' to index into various 'on-disk' data structures,
and lanes also act as a synchronization mechanism in case there are more
CPUs than available lanes. We did a comparison between two lane lock
strategies - first where we kept an atomic counter around that tracked
which was the last lane that was used, and 'our' lane was determined by
atomically incrementing that. That way, for the nr_cpus > nr_lanes case,
theoretically, no CPU would be blocked waiting for a lane. The other
strategy was to use the cpu number we're scheduled on to and hash it to
a lane number. Theoretically, this could block an IO that could've
otherwise run using a different, free lane. But some fio workloads
showed that the direct cpu -> lane hash performed faster than tracking
'last lane' - my reasoning is the cache thrash caused by moving the
atomic variable made that approach slower than simply waiting out the
in-progress IO. This supports the conclusion that the driver can be a
very simple bio-based one that does synchronous IOs instead of queuing.
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Boaz Harrosh <boaz@plexistor.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Jens Axboe <axboe@fb.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Neil Brown <neilb@suse.de>
Cc: Jeff Moyer <jmoyer@redhat.com>
Cc: Dave Chinner <david@fromorbit.com>
Cc: Greg KH <gregkh@linuxfoundation.org>
[jmoyer: fix nmi watchdog timeout in btt_map_init]
[jmoyer: move btt initialization to module load path]
[jmoyer: fix memory leak in the btt initialization path]
[jmoyer: Don't overwrite corrupted arenas]
Signed-off-by: Vishal Verma <vishal.l.verma@linux.intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
2015-06-25 16:20:32 +08:00
|
|
|
err_id:
|
2022-03-10 11:49:48 +08:00
|
|
|
kfree(nd_region);
|
nd_btt: atomic sector updates
BTT stands for Block Translation Table, and is a way to provide power
fail sector atomicity semantics for block devices that have the ability
to perform byte granularity IO. It relies on the capability of libnvdimm
namespace devices to do byte aligned IO.
The BTT works as a stacked blocked device, and reserves a chunk of space
from the backing device for its accounting metadata. It is a bio-based
driver because all IO is done synchronously, and there is no queuing or
asynchronous completions at either the device or the driver level.
The BTT uses 'lanes' to index into various 'on-disk' data structures,
and lanes also act as a synchronization mechanism in case there are more
CPUs than available lanes. We did a comparison between two lane lock
strategies - first where we kept an atomic counter around that tracked
which was the last lane that was used, and 'our' lane was determined by
atomically incrementing that. That way, for the nr_cpus > nr_lanes case,
theoretically, no CPU would be blocked waiting for a lane. The other
strategy was to use the cpu number we're scheduled on to and hash it to
a lane number. Theoretically, this could block an IO that could've
otherwise run using a different, free lane. But some fio workloads
showed that the direct cpu -> lane hash performed faster than tracking
'last lane' - my reasoning is the cache thrash caused by moving the
atomic variable made that approach slower than simply waiting out the
in-progress IO. This supports the conclusion that the driver can be a
very simple bio-based one that does synchronous IOs instead of queuing.
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Boaz Harrosh <boaz@plexistor.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Jens Axboe <axboe@fb.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Neil Brown <neilb@suse.de>
Cc: Jeff Moyer <jmoyer@redhat.com>
Cc: Dave Chinner <david@fromorbit.com>
Cc: Greg KH <gregkh@linuxfoundation.org>
[jmoyer: fix nmi watchdog timeout in btt_map_init]
[jmoyer: move btt initialization to module load path]
[jmoyer: fix memory leak in the btt initialization path]
[jmoyer: Don't overwrite corrupted arenas]
Signed-off-by: Vishal Verma <vishal.l.verma@linux.intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
2015-06-25 16:20:32 +08:00
|
|
|
return NULL;
|
libnvdimm, nfit: regions (block-data-window, persistent memory, volatile memory)
A "region" device represents the maximum capacity of a BLK range (mmio
block-data-window(s)), or a PMEM range (DAX-capable persistent memory or
volatile memory), without regard for aliasing. Aliasing, in the
dimm-local address space (DPA), is resolved by metadata on a dimm to
designate which exclusive interface will access the aliased DPA ranges.
Support for the per-dimm metadata/label arrvies is in a subsequent
patch.
The name format of "region" devices is "regionN" where, like dimms, N is
a global ida index assigned at discovery time. This id is not reliable
across reboots nor in the presence of hotplug. Look to attributes of
the region or static id-data of the sub-namespace to generate a
persistent name. However, if the platform configuration does not change
it is reasonable to expect the same region id to be assigned at the next
boot.
"region"s have 2 generic attributes "size", and "mapping"s where:
- size: the BLK accessible capacity or the span of the
system physical address range in the case of PMEM.
- mappingN: a tuple describing a dimm's contribution to the region's
capacity in the format (<nmemX>,<dpa>,<size>). For a PMEM-region
there will be at least one mapping per dimm in the interleave set. For
a BLK-region there is only "mapping0" listing the starting DPA of the
BLK-region and the available DPA capacity of that space (matches "size"
above).
The max number of mappings per "region" is hard coded per the
constraints of sysfs attribute groups. That said the number of mappings
per region should never exceed the maximum number of possible dimms in
the system. If the current number turns out to not be enough then the
"mappings" attribute clarifies how many there are supposed to be. "32
should be enough for anybody...".
Cc: Neil Brown <neilb@suse.de>
Cc: <linux-acpi@vger.kernel.org>
Cc: Greg KH <gregkh@linuxfoundation.org>
Cc: Robert Moore <robert.moore@intel.com>
Cc: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Acked-by: Christoph Hellwig <hch@lst.de>
Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Tested-by: Toshi Kani <toshi.kani@hp.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
2015-06-10 08:13:14 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
struct nd_region *nvdimm_pmem_region_create(struct nvdimm_bus *nvdimm_bus,
|
|
|
|
struct nd_region_desc *ndr_desc)
|
|
|
|
{
|
nd_btt: atomic sector updates
BTT stands for Block Translation Table, and is a way to provide power
fail sector atomicity semantics for block devices that have the ability
to perform byte granularity IO. It relies on the capability of libnvdimm
namespace devices to do byte aligned IO.
The BTT works as a stacked blocked device, and reserves a chunk of space
from the backing device for its accounting metadata. It is a bio-based
driver because all IO is done synchronously, and there is no queuing or
asynchronous completions at either the device or the driver level.
The BTT uses 'lanes' to index into various 'on-disk' data structures,
and lanes also act as a synchronization mechanism in case there are more
CPUs than available lanes. We did a comparison between two lane lock
strategies - first where we kept an atomic counter around that tracked
which was the last lane that was used, and 'our' lane was determined by
atomically incrementing that. That way, for the nr_cpus > nr_lanes case,
theoretically, no CPU would be blocked waiting for a lane. The other
strategy was to use the cpu number we're scheduled on to and hash it to
a lane number. Theoretically, this could block an IO that could've
otherwise run using a different, free lane. But some fio workloads
showed that the direct cpu -> lane hash performed faster than tracking
'last lane' - my reasoning is the cache thrash caused by moving the
atomic variable made that approach slower than simply waiting out the
in-progress IO. This supports the conclusion that the driver can be a
very simple bio-based one that does synchronous IOs instead of queuing.
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Boaz Harrosh <boaz@plexistor.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Jens Axboe <axboe@fb.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Neil Brown <neilb@suse.de>
Cc: Jeff Moyer <jmoyer@redhat.com>
Cc: Dave Chinner <david@fromorbit.com>
Cc: Greg KH <gregkh@linuxfoundation.org>
[jmoyer: fix nmi watchdog timeout in btt_map_init]
[jmoyer: move btt initialization to module load path]
[jmoyer: fix memory leak in the btt initialization path]
[jmoyer: Don't overwrite corrupted arenas]
Signed-off-by: Vishal Verma <vishal.l.verma@linux.intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
2015-06-25 16:20:32 +08:00
|
|
|
ndr_desc->num_lanes = ND_MAX_LANES;
|
libnvdimm, nfit: regions (block-data-window, persistent memory, volatile memory)
A "region" device represents the maximum capacity of a BLK range (mmio
block-data-window(s)), or a PMEM range (DAX-capable persistent memory or
volatile memory), without regard for aliasing. Aliasing, in the
dimm-local address space (DPA), is resolved by metadata on a dimm to
designate which exclusive interface will access the aliased DPA ranges.
Support for the per-dimm metadata/label arrvies is in a subsequent
patch.
The name format of "region" devices is "regionN" where, like dimms, N is
a global ida index assigned at discovery time. This id is not reliable
across reboots nor in the presence of hotplug. Look to attributes of
the region or static id-data of the sub-namespace to generate a
persistent name. However, if the platform configuration does not change
it is reasonable to expect the same region id to be assigned at the next
boot.
"region"s have 2 generic attributes "size", and "mapping"s where:
- size: the BLK accessible capacity or the span of the
system physical address range in the case of PMEM.
- mappingN: a tuple describing a dimm's contribution to the region's
capacity in the format (<nmemX>,<dpa>,<size>). For a PMEM-region
there will be at least one mapping per dimm in the interleave set. For
a BLK-region there is only "mapping0" listing the starting DPA of the
BLK-region and the available DPA capacity of that space (matches "size"
above).
The max number of mappings per "region" is hard coded per the
constraints of sysfs attribute groups. That said the number of mappings
per region should never exceed the maximum number of possible dimms in
the system. If the current number turns out to not be enough then the
"mappings" attribute clarifies how many there are supposed to be. "32
should be enough for anybody...".
Cc: Neil Brown <neilb@suse.de>
Cc: <linux-acpi@vger.kernel.org>
Cc: Greg KH <gregkh@linuxfoundation.org>
Cc: Robert Moore <robert.moore@intel.com>
Cc: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Acked-by: Christoph Hellwig <hch@lst.de>
Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Tested-by: Toshi Kani <toshi.kani@hp.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
2015-06-10 08:13:14 +08:00
|
|
|
return nd_region_create(nvdimm_bus, ndr_desc, &nd_pmem_device_type,
|
|
|
|
__func__);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(nvdimm_pmem_region_create);
|
|
|
|
|
|
|
|
struct nd_region *nvdimm_volatile_region_create(struct nvdimm_bus *nvdimm_bus,
|
|
|
|
struct nd_region_desc *ndr_desc)
|
|
|
|
{
|
nd_btt: atomic sector updates
BTT stands for Block Translation Table, and is a way to provide power
fail sector atomicity semantics for block devices that have the ability
to perform byte granularity IO. It relies on the capability of libnvdimm
namespace devices to do byte aligned IO.
The BTT works as a stacked blocked device, and reserves a chunk of space
from the backing device for its accounting metadata. It is a bio-based
driver because all IO is done synchronously, and there is no queuing or
asynchronous completions at either the device or the driver level.
The BTT uses 'lanes' to index into various 'on-disk' data structures,
and lanes also act as a synchronization mechanism in case there are more
CPUs than available lanes. We did a comparison between two lane lock
strategies - first where we kept an atomic counter around that tracked
which was the last lane that was used, and 'our' lane was determined by
atomically incrementing that. That way, for the nr_cpus > nr_lanes case,
theoretically, no CPU would be blocked waiting for a lane. The other
strategy was to use the cpu number we're scheduled on to and hash it to
a lane number. Theoretically, this could block an IO that could've
otherwise run using a different, free lane. But some fio workloads
showed that the direct cpu -> lane hash performed faster than tracking
'last lane' - my reasoning is the cache thrash caused by moving the
atomic variable made that approach slower than simply waiting out the
in-progress IO. This supports the conclusion that the driver can be a
very simple bio-based one that does synchronous IOs instead of queuing.
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Boaz Harrosh <boaz@plexistor.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Jens Axboe <axboe@fb.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Neil Brown <neilb@suse.de>
Cc: Jeff Moyer <jmoyer@redhat.com>
Cc: Dave Chinner <david@fromorbit.com>
Cc: Greg KH <gregkh@linuxfoundation.org>
[jmoyer: fix nmi watchdog timeout in btt_map_init]
[jmoyer: move btt initialization to module load path]
[jmoyer: fix memory leak in the btt initialization path]
[jmoyer: Don't overwrite corrupted arenas]
Signed-off-by: Vishal Verma <vishal.l.verma@linux.intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
2015-06-25 16:20:32 +08:00
|
|
|
ndr_desc->num_lanes = ND_MAX_LANES;
|
libnvdimm, nfit: regions (block-data-window, persistent memory, volatile memory)
A "region" device represents the maximum capacity of a BLK range (mmio
block-data-window(s)), or a PMEM range (DAX-capable persistent memory or
volatile memory), without regard for aliasing. Aliasing, in the
dimm-local address space (DPA), is resolved by metadata on a dimm to
designate which exclusive interface will access the aliased DPA ranges.
Support for the per-dimm metadata/label arrvies is in a subsequent
patch.
The name format of "region" devices is "regionN" where, like dimms, N is
a global ida index assigned at discovery time. This id is not reliable
across reboots nor in the presence of hotplug. Look to attributes of
the region or static id-data of the sub-namespace to generate a
persistent name. However, if the platform configuration does not change
it is reasonable to expect the same region id to be assigned at the next
boot.
"region"s have 2 generic attributes "size", and "mapping"s where:
- size: the BLK accessible capacity or the span of the
system physical address range in the case of PMEM.
- mappingN: a tuple describing a dimm's contribution to the region's
capacity in the format (<nmemX>,<dpa>,<size>). For a PMEM-region
there will be at least one mapping per dimm in the interleave set. For
a BLK-region there is only "mapping0" listing the starting DPA of the
BLK-region and the available DPA capacity of that space (matches "size"
above).
The max number of mappings per "region" is hard coded per the
constraints of sysfs attribute groups. That said the number of mappings
per region should never exceed the maximum number of possible dimms in
the system. If the current number turns out to not be enough then the
"mappings" attribute clarifies how many there are supposed to be. "32
should be enough for anybody...".
Cc: Neil Brown <neilb@suse.de>
Cc: <linux-acpi@vger.kernel.org>
Cc: Greg KH <gregkh@linuxfoundation.org>
Cc: Robert Moore <robert.moore@intel.com>
Cc: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Acked-by: Christoph Hellwig <hch@lst.de>
Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Tested-by: Toshi Kani <toshi.kani@hp.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
2015-06-10 08:13:14 +08:00
|
|
|
return nd_region_create(nvdimm_bus, ndr_desc, &nd_volatile_device_type,
|
|
|
|
__func__);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(nvdimm_volatile_region_create);
|
2016-05-18 11:24:16 +08:00
|
|
|
|
2019-07-05 22:03:22 +08:00
|
|
|
int nvdimm_flush(struct nd_region *nd_region, struct bio *bio)
|
|
|
|
{
|
|
|
|
int rc = 0;
|
|
|
|
|
|
|
|
if (!nd_region->flush)
|
|
|
|
rc = generic_nvdimm_flush(nd_region);
|
|
|
|
else {
|
|
|
|
if (nd_region->flush(nd_region, bio))
|
|
|
|
rc = -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
2016-07-08 10:44:50 +08:00
|
|
|
/**
|
|
|
|
* nvdimm_flush - flush any posted write queues between the cpu and pmem media
|
2022-03-10 11:49:48 +08:00
|
|
|
* @nd_region: interleaved pmem region
|
2016-07-08 10:44:50 +08:00
|
|
|
*/
|
2019-07-05 22:03:22 +08:00
|
|
|
int generic_nvdimm_flush(struct nd_region *nd_region)
|
2016-07-08 10:44:50 +08:00
|
|
|
{
|
|
|
|
struct nd_region_data *ndrd = dev_get_drvdata(&nd_region->dev);
|
2016-05-28 00:23:01 +08:00
|
|
|
int i, idx;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Try to encourage some diversity in flush hint addresses
|
|
|
|
* across cpus assuming a limited number of flush hints.
|
|
|
|
*/
|
|
|
|
idx = this_cpu_read(flush_idx);
|
|
|
|
idx = this_cpu_add_return(flush_idx, hash_32(current->pid + idx, 8));
|
2016-07-08 10:44:50 +08:00
|
|
|
|
|
|
|
/*
|
2020-07-01 15:22:32 +08:00
|
|
|
* The pmem_wmb() is needed to 'sfence' all
|
|
|
|
* previous writes such that they are architecturally visible for
|
|
|
|
* the platform buffer flush. Note that we've already arranged for pmem
|
2017-05-30 03:22:50 +08:00
|
|
|
* writes to avoid the cache via memcpy_flushcache(). The final
|
|
|
|
* wmb() ensures ordering for the NVDIMM flush write.
|
2016-07-08 10:44:50 +08:00
|
|
|
*/
|
2020-07-01 15:22:32 +08:00
|
|
|
pmem_wmb();
|
2016-07-08 10:44:50 +08:00
|
|
|
for (i = 0; i < nd_region->ndr_mappings; i++)
|
2016-09-24 08:53:52 +08:00
|
|
|
if (ndrd_get_flush_wpq(ndrd, i, 0))
|
|
|
|
writeq(1, ndrd_get_flush_wpq(ndrd, i, idx));
|
2016-07-08 10:44:50 +08:00
|
|
|
wmb();
|
2019-07-05 22:03:22 +08:00
|
|
|
|
|
|
|
return 0;
|
2016-07-08 10:44:50 +08:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(nvdimm_flush);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* nvdimm_has_flush - determine write flushing requirements
|
2022-03-10 11:49:48 +08:00
|
|
|
* @nd_region: interleaved pmem region
|
2016-07-08 10:44:50 +08:00
|
|
|
*
|
|
|
|
* Returns 1 if writes require flushing
|
|
|
|
* Returns 0 if writes do not require flushing
|
|
|
|
* Returns -ENXIO if flushing capability can not be determined
|
|
|
|
*/
|
|
|
|
int nvdimm_has_flush(struct nd_region *nd_region)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
2017-05-30 14:11:57 +08:00
|
|
|
/* no nvdimm or pmem api == flushing capability unknown */
|
|
|
|
if (nd_region->ndr_mappings == 0
|
|
|
|
|| !IS_ENABLED(CONFIG_ARCH_HAS_PMEM_API))
|
2016-07-08 10:44:50 +08:00
|
|
|
return -ENXIO;
|
|
|
|
|
2021-04-02 17:25:55 +08:00
|
|
|
/* Test if an explicit flush function is defined */
|
|
|
|
if (test_bit(ND_REGION_ASYNC, &nd_region->flags) && nd_region->flush)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
/* Test if any flush hints for the region are available */
|
2017-04-25 06:43:05 +08:00
|
|
|
for (i = 0; i < nd_region->ndr_mappings; i++) {
|
|
|
|
struct nd_mapping *nd_mapping = &nd_region->mapping[i];
|
|
|
|
struct nvdimm *nvdimm = nd_mapping->nvdimm;
|
|
|
|
|
|
|
|
/* flush hints present / available */
|
|
|
|
if (nvdimm->num_flush)
|
2016-07-08 10:44:50 +08:00
|
|
|
return 1;
|
2017-04-25 06:43:05 +08:00
|
|
|
}
|
2016-07-08 10:44:50 +08:00
|
|
|
|
|
|
|
/*
|
2021-04-02 17:25:55 +08:00
|
|
|
* The platform defines dimm devices without hints nor explicit flush,
|
|
|
|
* assume platform persistence mechanism like ADR
|
2016-07-08 10:44:50 +08:00
|
|
|
*/
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(nvdimm_has_flush);
|
|
|
|
|
2017-06-10 00:46:50 +08:00
|
|
|
int nvdimm_has_cache(struct nd_region *nd_region)
|
|
|
|
{
|
2018-06-07 00:45:15 +08:00
|
|
|
return is_nd_pmem(&nd_region->dev) &&
|
|
|
|
!test_bit(ND_REGION_PERSIST_CACHE, &nd_region->flags);
|
2017-06-10 00:46:50 +08:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(nvdimm_has_cache);
|
|
|
|
|
2019-07-05 22:03:24 +08:00
|
|
|
bool is_nvdimm_sync(struct nd_region *nd_region)
|
|
|
|
{
|
2019-09-24 19:43:27 +08:00
|
|
|
if (is_nd_volatile(&nd_region->dev))
|
|
|
|
return true;
|
|
|
|
|
2019-07-05 22:03:24 +08:00
|
|
|
return is_nd_pmem(&nd_region->dev) &&
|
|
|
|
!test_bit(ND_REGION_ASYNC, &nd_region->flags);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(is_nvdimm_sync);
|
|
|
|
|
2018-11-25 02:47:04 +08:00
|
|
|
struct conflict_context {
|
|
|
|
struct nd_region *nd_region;
|
|
|
|
resource_size_t start, size;
|
|
|
|
};
|
|
|
|
|
|
|
|
static int region_conflict(struct device *dev, void *data)
|
|
|
|
{
|
|
|
|
struct nd_region *nd_region;
|
|
|
|
struct conflict_context *ctx = data;
|
|
|
|
resource_size_t res_end, region_end, region_start;
|
|
|
|
|
|
|
|
if (!is_memory(dev))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
nd_region = to_nd_region(dev);
|
|
|
|
if (nd_region == ctx->nd_region)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
res_end = ctx->start + ctx->size;
|
|
|
|
region_start = nd_region->ndr_start;
|
|
|
|
region_end = region_start + nd_region->ndr_size;
|
|
|
|
if (ctx->start >= region_start && ctx->start < region_end)
|
|
|
|
return -EBUSY;
|
|
|
|
if (res_end > region_start && res_end <= region_end)
|
|
|
|
return -EBUSY;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int nd_region_conflict(struct nd_region *nd_region, resource_size_t start,
|
|
|
|
resource_size_t size)
|
|
|
|
{
|
|
|
|
struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(&nd_region->dev);
|
|
|
|
struct conflict_context ctx = {
|
|
|
|
.nd_region = nd_region,
|
|
|
|
.start = start,
|
|
|
|
.size = size,
|
|
|
|
};
|
|
|
|
|
|
|
|
return device_for_each_child(&nvdimm_bus->dev, &ctx, region_conflict);
|
|
|
|
}
|