Merge tag 'libnvdimm-for-4.3' of git://git.kernel.org/pub/scm/linux/kernel/git/nvdimm/nvdimm
Pull libnvdimm updates from Dan Williams: "This update has successfully completed a 0day-kbuild run and has appeared in a linux-next release. The changes outside of the typical drivers/nvdimm/ and drivers/acpi/nfit.[ch] paths are related to the removal of IORESOURCE_CACHEABLE, the introduction of memremap(), and the introduction of ZONE_DEVICE + devm_memremap_pages(). Summary: - Introduce ZONE_DEVICE and devm_memremap_pages() as a generic mechanism for adding device-driver-discovered memory regions to the kernel's direct map. This facility is used by the pmem driver to enable pfn_to_page() operations on the page frames returned by DAX ('direct_access' in 'struct block_device_operations'). For now, the 'memmap' allocation for these "device" pages comes from "System RAM". Support for allocating the memmap from device memory will arrive in a later kernel. - Introduce memremap() to replace usages of ioremap_cache() and ioremap_wt(). memremap() drops the __iomem annotation for these mappings to memory that do not have i/o side effects. The replacement of ioremap_cache() with memremap() is limited to the pmem driver to ease merging the api change in v4.3. Completion of the conversion is targeted for v4.4. - Similar to the usage of memcpy_to_pmem() + wmb_pmem() in the pmem driver, update the VFS DAX implementation and PMEM api to provide persistence guarantees for kernel operations on a DAX mapping. - Convert the ACPI NFIT 'BLK' driver to map the block apertures as cacheable to improve performance. - Miscellaneous updates and fixes to libnvdimm including support for issuing "address range scrub" commands, clarifying the optimal 'sector size' of pmem devices, a clarification of the usage of the ACPI '_STA' (status) property for DIMM devices, and other minor fixes" * tag 'libnvdimm-for-4.3' of git://git.kernel.org/pub/scm/linux/kernel/git/nvdimm/nvdimm: (34 commits) libnvdimm, pmem: direct map legacy pmem by default libnvdimm, pmem: 'struct page' for pmem libnvdimm, pfn: 'struct page' provider infrastructure x86, pmem: clarify that ARCH_HAS_PMEM_API implies PMEM mapped WB add devm_memremap_pages mm: ZONE_DEVICE for "device memory" mm: move __phys_to_pfn and __pfn_to_phys to asm/generic/memory_model.h dax: drop size parameter to ->direct_access() nd_blk: change aperture mapping from WC to WB nvdimm: change to use generic kvfree() pmem, dax: have direct_access use __pmem annotation dax: update I/O path to do proper PMEM flushing pmem: add copy_from_iter_pmem() and clear_pmem() pmem, x86: clean up conditional pmem includes pmem: remove layer when calling arch_has_wmb_pmem() pmem, x86: move x86 PMEM API to new pmem.h header libnvdimm, e820: make CONFIG_X86_PMEM_LEGACY a tristate option pmem: switch to devm_ allocations devres: add devm_memremap libnvdimm, btt: write and validate parent_uuid ...
This commit is contained in:
@@ -1,9 +1,12 @@
|
||||
ldflags-y += --wrap=ioremap_wt
|
||||
ldflags-y += --wrap=ioremap_wc
|
||||
ldflags-y += --wrap=memremap
|
||||
ldflags-y += --wrap=devm_ioremap_nocache
|
||||
ldflags-y += --wrap=ioremap_cache
|
||||
ldflags-y += --wrap=devm_memremap
|
||||
ldflags-y += --wrap=devm_memunmap
|
||||
ldflags-y += --wrap=ioremap_nocache
|
||||
ldflags-y += --wrap=iounmap
|
||||
ldflags-y += --wrap=memunmap
|
||||
ldflags-y += --wrap=__devm_request_region
|
||||
ldflags-y += --wrap=__request_region
|
||||
ldflags-y += --wrap=__release_region
|
||||
|
||||
@@ -15,6 +18,7 @@ obj-$(CONFIG_LIBNVDIMM) += libnvdimm.o
|
||||
obj-$(CONFIG_BLK_DEV_PMEM) += nd_pmem.o
|
||||
obj-$(CONFIG_ND_BTT) += nd_btt.o
|
||||
obj-$(CONFIG_ND_BLK) += nd_blk.o
|
||||
obj-$(CONFIG_X86_PMEM_LEGACY) += nd_e820.o
|
||||
obj-$(CONFIG_ACPI_NFIT) += nfit.o
|
||||
|
||||
nfit-y := $(ACPI_SRC)/nfit.o
|
||||
@@ -29,6 +33,9 @@ nd_btt-y += config_check.o
|
||||
nd_blk-y := $(NVDIMM_SRC)/blk.o
|
||||
nd_blk-y += config_check.o
|
||||
|
||||
nd_e820-y := $(NVDIMM_SRC)/e820.o
|
||||
nd_e820-y += config_check.o
|
||||
|
||||
libnvdimm-y := $(NVDIMM_SRC)/core.o
|
||||
libnvdimm-y += $(NVDIMM_SRC)/bus.o
|
||||
libnvdimm-y += $(NVDIMM_SRC)/dimm_devs.o
|
||||
@@ -37,7 +44,9 @@ libnvdimm-y += $(NVDIMM_SRC)/region_devs.o
|
||||
libnvdimm-y += $(NVDIMM_SRC)/region.o
|
||||
libnvdimm-y += $(NVDIMM_SRC)/namespace_devs.o
|
||||
libnvdimm-y += $(NVDIMM_SRC)/label.o
|
||||
libnvdimm-$(CONFIG_ND_CLAIM) += $(NVDIMM_SRC)/claim.o
|
||||
libnvdimm-$(CONFIG_BTT) += $(NVDIMM_SRC)/btt_devs.o
|
||||
libnvdimm-$(CONFIG_NVDIMM_PFN) += $(NVDIMM_SRC)/pfn_devs.o
|
||||
libnvdimm-y += config_check.o
|
||||
|
||||
obj-m += test/
|
||||
|
@@ -80,11 +80,46 @@ void __iomem *__wrap_devm_ioremap_nocache(struct device *dev,
|
||||
}
|
||||
EXPORT_SYMBOL(__wrap_devm_ioremap_nocache);
|
||||
|
||||
void __iomem *__wrap_ioremap_cache(resource_size_t offset, unsigned long size)
|
||||
void *__wrap_devm_memremap(struct device *dev, resource_size_t offset,
|
||||
size_t size, unsigned long flags)
|
||||
{
|
||||
return __nfit_test_ioremap(offset, size, ioremap_cache);
|
||||
struct nfit_test_resource *nfit_res;
|
||||
|
||||
rcu_read_lock();
|
||||
nfit_res = get_nfit_res(offset);
|
||||
rcu_read_unlock();
|
||||
if (nfit_res)
|
||||
return nfit_res->buf + offset - nfit_res->res->start;
|
||||
return devm_memremap(dev, offset, size, flags);
|
||||
}
|
||||
EXPORT_SYMBOL(__wrap_ioremap_cache);
|
||||
EXPORT_SYMBOL(__wrap_devm_memremap);
|
||||
|
||||
void *__wrap_memremap(resource_size_t offset, size_t size,
|
||||
unsigned long flags)
|
||||
{
|
||||
struct nfit_test_resource *nfit_res;
|
||||
|
||||
rcu_read_lock();
|
||||
nfit_res = get_nfit_res(offset);
|
||||
rcu_read_unlock();
|
||||
if (nfit_res)
|
||||
return nfit_res->buf + offset - nfit_res->res->start;
|
||||
return memremap(offset, size, flags);
|
||||
}
|
||||
EXPORT_SYMBOL(__wrap_memremap);
|
||||
|
||||
void __wrap_devm_memunmap(struct device *dev, void *addr)
|
||||
{
|
||||
struct nfit_test_resource *nfit_res;
|
||||
|
||||
rcu_read_lock();
|
||||
nfit_res = get_nfit_res((unsigned long) addr);
|
||||
rcu_read_unlock();
|
||||
if (nfit_res)
|
||||
return;
|
||||
return devm_memunmap(dev, addr);
|
||||
}
|
||||
EXPORT_SYMBOL(__wrap_devm_memunmap);
|
||||
|
||||
void __iomem *__wrap_ioremap_nocache(resource_size_t offset, unsigned long size)
|
||||
{
|
||||
@@ -92,12 +127,6 @@ void __iomem *__wrap_ioremap_nocache(resource_size_t offset, unsigned long size)
|
||||
}
|
||||
EXPORT_SYMBOL(__wrap_ioremap_nocache);
|
||||
|
||||
void __iomem *__wrap_ioremap_wt(resource_size_t offset, unsigned long size)
|
||||
{
|
||||
return __nfit_test_ioremap(offset, size, ioremap_wt);
|
||||
}
|
||||
EXPORT_SYMBOL(__wrap_ioremap_wt);
|
||||
|
||||
void __iomem *__wrap_ioremap_wc(resource_size_t offset, unsigned long size)
|
||||
{
|
||||
return __nfit_test_ioremap(offset, size, ioremap_wc);
|
||||
@@ -117,9 +146,22 @@ void __wrap_iounmap(volatile void __iomem *addr)
|
||||
}
|
||||
EXPORT_SYMBOL(__wrap_iounmap);
|
||||
|
||||
struct resource *__wrap___request_region(struct resource *parent,
|
||||
resource_size_t start, resource_size_t n, const char *name,
|
||||
int flags)
|
||||
void __wrap_memunmap(void *addr)
|
||||
{
|
||||
struct nfit_test_resource *nfit_res;
|
||||
|
||||
rcu_read_lock();
|
||||
nfit_res = get_nfit_res((unsigned long) addr);
|
||||
rcu_read_unlock();
|
||||
if (nfit_res)
|
||||
return;
|
||||
return memunmap(addr);
|
||||
}
|
||||
EXPORT_SYMBOL(__wrap_memunmap);
|
||||
|
||||
static struct resource *nfit_test_request_region(struct device *dev,
|
||||
struct resource *parent, resource_size_t start,
|
||||
resource_size_t n, const char *name, int flags)
|
||||
{
|
||||
struct nfit_test_resource *nfit_res;
|
||||
|
||||
@@ -147,10 +189,29 @@ struct resource *__wrap___request_region(struct resource *parent,
|
||||
return res;
|
||||
}
|
||||
}
|
||||
if (dev)
|
||||
return __devm_request_region(dev, parent, start, n, name);
|
||||
return __request_region(parent, start, n, name, flags);
|
||||
}
|
||||
|
||||
struct resource *__wrap___request_region(struct resource *parent,
|
||||
resource_size_t start, resource_size_t n, const char *name,
|
||||
int flags)
|
||||
{
|
||||
return nfit_test_request_region(NULL, parent, start, n, name, flags);
|
||||
}
|
||||
EXPORT_SYMBOL(__wrap___request_region);
|
||||
|
||||
struct resource *__wrap___devm_request_region(struct device *dev,
|
||||
struct resource *parent, resource_size_t start,
|
||||
resource_size_t n, const char *name)
|
||||
{
|
||||
if (!dev)
|
||||
return NULL;
|
||||
return nfit_test_request_region(dev, parent, start, n, name, 0);
|
||||
}
|
||||
EXPORT_SYMBOL(__wrap___devm_request_region);
|
||||
|
||||
void __wrap___release_region(struct resource *parent, resource_size_t start,
|
||||
resource_size_t n)
|
||||
{
|
||||
|
@@ -147,75 +147,153 @@ static struct nfit_test *to_nfit_test(struct device *dev)
|
||||
return container_of(pdev, struct nfit_test, pdev);
|
||||
}
|
||||
|
||||
static int nfit_test_cmd_get_config_size(struct nd_cmd_get_config_size *nd_cmd,
|
||||
unsigned int buf_len)
|
||||
{
|
||||
if (buf_len < sizeof(*nd_cmd))
|
||||
return -EINVAL;
|
||||
|
||||
nd_cmd->status = 0;
|
||||
nd_cmd->config_size = LABEL_SIZE;
|
||||
nd_cmd->max_xfer = SZ_4K;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nfit_test_cmd_get_config_data(struct nd_cmd_get_config_data_hdr
|
||||
*nd_cmd, unsigned int buf_len, void *label)
|
||||
{
|
||||
unsigned int len, offset = nd_cmd->in_offset;
|
||||
int rc;
|
||||
|
||||
if (buf_len < sizeof(*nd_cmd))
|
||||
return -EINVAL;
|
||||
if (offset >= LABEL_SIZE)
|
||||
return -EINVAL;
|
||||
if (nd_cmd->in_length + sizeof(*nd_cmd) > buf_len)
|
||||
return -EINVAL;
|
||||
|
||||
nd_cmd->status = 0;
|
||||
len = min(nd_cmd->in_length, LABEL_SIZE - offset);
|
||||
memcpy(nd_cmd->out_buf, label + offset, len);
|
||||
rc = buf_len - sizeof(*nd_cmd) - len;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int nfit_test_cmd_set_config_data(struct nd_cmd_set_config_hdr *nd_cmd,
|
||||
unsigned int buf_len, void *label)
|
||||
{
|
||||
unsigned int len, offset = nd_cmd->in_offset;
|
||||
u32 *status;
|
||||
int rc;
|
||||
|
||||
if (buf_len < sizeof(*nd_cmd))
|
||||
return -EINVAL;
|
||||
if (offset >= LABEL_SIZE)
|
||||
return -EINVAL;
|
||||
if (nd_cmd->in_length + sizeof(*nd_cmd) + 4 > buf_len)
|
||||
return -EINVAL;
|
||||
|
||||
status = (void *)nd_cmd + nd_cmd->in_length + sizeof(*nd_cmd);
|
||||
*status = 0;
|
||||
len = min(nd_cmd->in_length, LABEL_SIZE - offset);
|
||||
memcpy(label + offset, nd_cmd->in_buf, len);
|
||||
rc = buf_len - sizeof(*nd_cmd) - (len + 4);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int nfit_test_cmd_ars_cap(struct nd_cmd_ars_cap *nd_cmd,
|
||||
unsigned int buf_len)
|
||||
{
|
||||
if (buf_len < sizeof(*nd_cmd))
|
||||
return -EINVAL;
|
||||
|
||||
nd_cmd->max_ars_out = 256;
|
||||
nd_cmd->status = (ND_ARS_PERSISTENT | ND_ARS_VOLATILE) << 16;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nfit_test_cmd_ars_start(struct nd_cmd_ars_start *nd_cmd,
|
||||
unsigned int buf_len)
|
||||
{
|
||||
if (buf_len < sizeof(*nd_cmd))
|
||||
return -EINVAL;
|
||||
|
||||
nd_cmd->status = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nfit_test_cmd_ars_status(struct nd_cmd_ars_status *nd_cmd,
|
||||
unsigned int buf_len)
|
||||
{
|
||||
if (buf_len < sizeof(*nd_cmd))
|
||||
return -EINVAL;
|
||||
|
||||
nd_cmd->out_length = 256;
|
||||
nd_cmd->num_records = 0;
|
||||
nd_cmd->status = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nfit_test_ctl(struct nvdimm_bus_descriptor *nd_desc,
|
||||
struct nvdimm *nvdimm, unsigned int cmd, void *buf,
|
||||
unsigned int buf_len)
|
||||
{
|
||||
struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc);
|
||||
struct nfit_test *t = container_of(acpi_desc, typeof(*t), acpi_desc);
|
||||
struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
|
||||
int i, rc;
|
||||
int i, rc = 0;
|
||||
|
||||
if (!nfit_mem || !test_bit(cmd, &nfit_mem->dsm_mask))
|
||||
return -ENOTTY;
|
||||
if (nvdimm) {
|
||||
struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
|
||||
|
||||
/* lookup label space for the given dimm */
|
||||
for (i = 0; i < ARRAY_SIZE(handle); i++)
|
||||
if (__to_nfit_memdev(nfit_mem)->device_handle == handle[i])
|
||||
if (!nfit_mem || !test_bit(cmd, &nfit_mem->dsm_mask))
|
||||
return -ENOTTY;
|
||||
|
||||
/* lookup label space for the given dimm */
|
||||
for (i = 0; i < ARRAY_SIZE(handle); i++)
|
||||
if (__to_nfit_memdev(nfit_mem)->device_handle ==
|
||||
handle[i])
|
||||
break;
|
||||
if (i >= ARRAY_SIZE(handle))
|
||||
return -ENXIO;
|
||||
|
||||
switch (cmd) {
|
||||
case ND_CMD_GET_CONFIG_SIZE:
|
||||
rc = nfit_test_cmd_get_config_size(buf, buf_len);
|
||||
break;
|
||||
if (i >= ARRAY_SIZE(handle))
|
||||
return -ENXIO;
|
||||
case ND_CMD_GET_CONFIG_DATA:
|
||||
rc = nfit_test_cmd_get_config_data(buf, buf_len,
|
||||
t->label[i]);
|
||||
break;
|
||||
case ND_CMD_SET_CONFIG_DATA:
|
||||
rc = nfit_test_cmd_set_config_data(buf, buf_len,
|
||||
t->label[i]);
|
||||
break;
|
||||
default:
|
||||
return -ENOTTY;
|
||||
}
|
||||
} else {
|
||||
if (!nd_desc || !test_bit(cmd, &nd_desc->dsm_mask))
|
||||
return -ENOTTY;
|
||||
|
||||
switch (cmd) {
|
||||
case ND_CMD_GET_CONFIG_SIZE: {
|
||||
struct nd_cmd_get_config_size *nd_cmd = buf;
|
||||
|
||||
if (buf_len < sizeof(*nd_cmd))
|
||||
return -EINVAL;
|
||||
nd_cmd->status = 0;
|
||||
nd_cmd->config_size = LABEL_SIZE;
|
||||
nd_cmd->max_xfer = SZ_4K;
|
||||
rc = 0;
|
||||
break;
|
||||
}
|
||||
case ND_CMD_GET_CONFIG_DATA: {
|
||||
struct nd_cmd_get_config_data_hdr *nd_cmd = buf;
|
||||
unsigned int len, offset = nd_cmd->in_offset;
|
||||
|
||||
if (buf_len < sizeof(*nd_cmd))
|
||||
return -EINVAL;
|
||||
if (offset >= LABEL_SIZE)
|
||||
return -EINVAL;
|
||||
if (nd_cmd->in_length + sizeof(*nd_cmd) > buf_len)
|
||||
return -EINVAL;
|
||||
|
||||
nd_cmd->status = 0;
|
||||
len = min(nd_cmd->in_length, LABEL_SIZE - offset);
|
||||
memcpy(nd_cmd->out_buf, t->label[i] + offset, len);
|
||||
rc = buf_len - sizeof(*nd_cmd) - len;
|
||||
break;
|
||||
}
|
||||
case ND_CMD_SET_CONFIG_DATA: {
|
||||
struct nd_cmd_set_config_hdr *nd_cmd = buf;
|
||||
unsigned int len, offset = nd_cmd->in_offset;
|
||||
u32 *status;
|
||||
|
||||
if (buf_len < sizeof(*nd_cmd))
|
||||
return -EINVAL;
|
||||
if (offset >= LABEL_SIZE)
|
||||
return -EINVAL;
|
||||
if (nd_cmd->in_length + sizeof(*nd_cmd) + 4 > buf_len)
|
||||
return -EINVAL;
|
||||
|
||||
status = buf + nd_cmd->in_length + sizeof(*nd_cmd);
|
||||
*status = 0;
|
||||
len = min(nd_cmd->in_length, LABEL_SIZE - offset);
|
||||
memcpy(t->label[i] + offset, nd_cmd->in_buf, len);
|
||||
rc = buf_len - sizeof(*nd_cmd) - (len + 4);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return -ENOTTY;
|
||||
switch (cmd) {
|
||||
case ND_CMD_ARS_CAP:
|
||||
rc = nfit_test_cmd_ars_cap(buf, buf_len);
|
||||
break;
|
||||
case ND_CMD_ARS_START:
|
||||
rc = nfit_test_cmd_ars_start(buf, buf_len);
|
||||
break;
|
||||
case ND_CMD_ARS_STATUS:
|
||||
rc = nfit_test_cmd_ars_status(buf, buf_len);
|
||||
break;
|
||||
default:
|
||||
return -ENOTTY;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
@@ -876,6 +954,9 @@ static void nfit_test0_setup(struct nfit_test *t)
|
||||
set_bit(ND_CMD_GET_CONFIG_SIZE, &acpi_desc->dimm_dsm_force_en);
|
||||
set_bit(ND_CMD_GET_CONFIG_DATA, &acpi_desc->dimm_dsm_force_en);
|
||||
set_bit(ND_CMD_SET_CONFIG_DATA, &acpi_desc->dimm_dsm_force_en);
|
||||
set_bit(ND_CMD_ARS_CAP, &acpi_desc->bus_dsm_force_en);
|
||||
set_bit(ND_CMD_ARS_START, &acpi_desc->bus_dsm_force_en);
|
||||
set_bit(ND_CMD_ARS_STATUS, &acpi_desc->bus_dsm_force_en);
|
||||
nd_desc = &acpi_desc->nd_desc;
|
||||
nd_desc->ndctl = nfit_test_ctl;
|
||||
}
|
||||
@@ -948,9 +1029,13 @@ static int nfit_test_blk_do_io(struct nd_blk_region *ndbr, resource_size_t dpa,
|
||||
|
||||
lane = nd_region_acquire_lane(nd_region);
|
||||
if (rw)
|
||||
memcpy(mmio->base + dpa, iobuf, len);
|
||||
else
|
||||
memcpy(iobuf, mmio->base + dpa, len);
|
||||
memcpy(mmio->addr.base + dpa, iobuf, len);
|
||||
else {
|
||||
memcpy(iobuf, mmio->addr.base + dpa, len);
|
||||
|
||||
/* give us some some coverage of the mmio_flush_range() API */
|
||||
mmio_flush_range(mmio->addr.base + dpa, len);
|
||||
}
|
||||
nd_region_release_lane(nd_region, lane);
|
||||
|
||||
return 0;
|
||||
|
Reference in New Issue
Block a user