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:
Linus Torvalds
2015-09-08 14:35:59 -07:00
92 changed files with 2142 additions and 745 deletions

View File

@@ -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/

View File

@@ -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)
{

View File

@@ -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;