libnvdimm, pmem: allow nfit_test to override pmem_direct_access()
Currently phys_to_pfn_t() is an exported symbol to allow nfit_test to override it and indicate that nfit_test-pmem is not device-mapped. Now, we want to enable nfit_test to operate without DMA_CMA and the pmem it provides will no longer be physically contiguous, i.e. won't be capable of supporting direct_access requests larger than a page. Make pmem_direct_access() a weak symbol so that it can be replaced by the tools/testing/nvdimm/ version, and move phys_to_pfn_t() to a static inline now that it no longer needs to be overridden. Acked-by: Johannes Thumshirn <jthumshirn@suse.de> Signed-off-by: Dan Williams <dan.j.williams@intel.com>
This commit is contained in:
		
							parent
							
								
									e02fb7264d
								
							
						
					
					
						commit
						f295e53b60
					
				| @ -29,23 +29,10 @@ | ||||
| #include <linux/slab.h> | ||||
| #include <linux/pmem.h> | ||||
| #include <linux/nd.h> | ||||
| #include "pmem.h" | ||||
| #include "pfn.h" | ||||
| #include "nd.h" | ||||
| 
 | ||||
| struct pmem_device { | ||||
| 	/* One contiguous memory region per device */ | ||||
| 	phys_addr_t		phys_addr; | ||||
| 	/* when non-zero this device is hosting a 'pfn' instance */ | ||||
| 	phys_addr_t		data_offset; | ||||
| 	u64			pfn_flags; | ||||
| 	void __pmem		*virt_addr; | ||||
| 	/* immutable base size of the namespace */ | ||||
| 	size_t			size; | ||||
| 	/* trim size when namespace capacity has been section aligned */ | ||||
| 	u32			pfn_pad; | ||||
| 	struct badblocks	bb; | ||||
| }; | ||||
| 
 | ||||
| static void pmem_clear_poison(struct pmem_device *pmem, phys_addr_t offset, | ||||
| 		unsigned int len) | ||||
| { | ||||
| @ -163,7 +150,8 @@ static int pmem_rw_page(struct block_device *bdev, sector_t sector, | ||||
| 	return rc; | ||||
| } | ||||
| 
 | ||||
| static long pmem_direct_access(struct block_device *bdev, sector_t sector, | ||||
| /* see "strong" declaration in tools/testing/nvdimm/pmem-dax.c */ | ||||
| __weak long pmem_direct_access(struct block_device *bdev, sector_t sector, | ||||
| 		      void __pmem **kaddr, pfn_t *pfn, long size) | ||||
| { | ||||
| 	struct pmem_device *pmem = bdev->bd_queue->queuedata; | ||||
|  | ||||
							
								
								
									
										24
									
								
								drivers/nvdimm/pmem.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								drivers/nvdimm/pmem.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,24 @@ | ||||
| #ifndef __NVDIMM_PMEM_H__ | ||||
| #define __NVDIMM_PMEM_H__ | ||||
| #include <linux/badblocks.h> | ||||
| #include <linux/types.h> | ||||
| #include <linux/pfn_t.h> | ||||
| #include <linux/fs.h> | ||||
| 
 | ||||
| long pmem_direct_access(struct block_device *bdev, sector_t sector, | ||||
| 		      void __pmem **kaddr, pfn_t *pfn, long size); | ||||
| /* this definition is in it's own header for tools/testing/nvdimm to consume */ | ||||
| struct pmem_device { | ||||
| 	/* One contiguous memory region per device */ | ||||
| 	phys_addr_t		phys_addr; | ||||
| 	/* when non-zero this device is hosting a 'pfn' instance */ | ||||
| 	phys_addr_t		data_offset; | ||||
| 	u64			pfn_flags; | ||||
| 	void __pmem		*virt_addr; | ||||
| 	/* immutable base size of the namespace */ | ||||
| 	size_t			size; | ||||
| 	/* trim size when namespace capacity has been section aligned */ | ||||
| 	u32			pfn_pad; | ||||
| 	struct badblocks	bb; | ||||
| }; | ||||
| #endif /* __NVDIMM_PMEM_H__ */ | ||||
| @ -28,7 +28,10 @@ static inline pfn_t pfn_to_pfn_t(unsigned long pfn) | ||||
| 	return __pfn_to_pfn_t(pfn, 0); | ||||
| } | ||||
| 
 | ||||
| extern pfn_t phys_to_pfn_t(phys_addr_t addr, u64 flags); | ||||
| static inline pfn_t phys_to_pfn_t(phys_addr_t addr, u64 flags) | ||||
| { | ||||
| 	return __pfn_to_pfn_t(addr >> PAGE_SHIFT, flags); | ||||
| } | ||||
| 
 | ||||
| static inline bool pfn_t_has_page(pfn_t pfn) | ||||
| { | ||||
|  | ||||
| @ -169,12 +169,6 @@ void devm_memunmap(struct device *dev, void *addr) | ||||
| } | ||||
| EXPORT_SYMBOL(devm_memunmap); | ||||
| 
 | ||||
| pfn_t phys_to_pfn_t(phys_addr_t addr, u64 flags) | ||||
| { | ||||
| 	return __pfn_to_pfn_t(addr >> PAGE_SHIFT, flags); | ||||
| } | ||||
| EXPORT_SYMBOL(phys_to_pfn_t); | ||||
| 
 | ||||
| #ifdef CONFIG_ZONE_DEVICE | ||||
| static DEFINE_MUTEX(pgmap_lock); | ||||
| static RADIX_TREE(pgmap_radix, GFP_KERNEL); | ||||
|  | ||||
| @ -11,12 +11,12 @@ ldflags-y += --wrap=__devm_release_region | ||||
| ldflags-y += --wrap=__request_region | ||||
| ldflags-y += --wrap=__release_region | ||||
| ldflags-y += --wrap=devm_memremap_pages | ||||
| ldflags-y += --wrap=phys_to_pfn_t | ||||
| 
 | ||||
| DRIVERS := ../../../drivers | ||||
| NVDIMM_SRC := $(DRIVERS)/nvdimm | ||||
| ACPI_SRC := $(DRIVERS)/acpi | ||||
| DAX_SRC := $(DRIVERS)/dax | ||||
| ccflags-y := -I$(src)/$(NVDIMM_SRC)/ | ||||
| 
 | ||||
| obj-$(CONFIG_LIBNVDIMM) += libnvdimm.o | ||||
| obj-$(CONFIG_BLK_DEV_PMEM) += nd_pmem.o | ||||
| @ -31,6 +31,7 @@ nfit-y := $(ACPI_SRC)/nfit.o | ||||
| nfit-y += config_check.o | ||||
| 
 | ||||
| nd_pmem-y := $(NVDIMM_SRC)/pmem.o | ||||
| nd_pmem-y += pmem-dax.o | ||||
| nd_pmem-y += config_check.o | ||||
| 
 | ||||
| nd_btt-y := $(NVDIMM_SRC)/btt.o | ||||
|  | ||||
							
								
								
									
										42
									
								
								tools/testing/nvdimm/pmem-dax.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								tools/testing/nvdimm/pmem-dax.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,42 @@ | ||||
| /*
 | ||||
|  * Copyright (c) 2014-2016, Intel Corporation. | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify it | ||||
|  * under the terms and conditions of the GNU General Public License, | ||||
|  * version 2, as published by the Free Software Foundation. | ||||
|  * | ||||
|  * This program is distributed in the hope it will be useful, but WITHOUT | ||||
|  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for | ||||
|  * more details. | ||||
|  */ | ||||
| #include "test/nfit_test.h" | ||||
| #include <linux/blkdev.h> | ||||
| #include <pmem.h> | ||||
| #include <nd.h> | ||||
| 
 | ||||
| long pmem_direct_access(struct block_device *bdev, sector_t sector, | ||||
| 		void __pmem **kaddr, pfn_t *pfn, long size) | ||||
| { | ||||
| 	struct pmem_device *pmem = bdev->bd_queue->queuedata; | ||||
| 	resource_size_t offset = sector * 512 + pmem->data_offset; | ||||
| 
 | ||||
| 	/* disable DAX for nfit_test pmem devices */ | ||||
| 	if (get_nfit_res(pmem->phys_addr + offset)) { | ||||
| 		dev_info_once(pmem->bb.dev, "dax is disabled for nfit_test\n"); | ||||
| 		return -EIO; | ||||
| 	} | ||||
| 
 | ||||
| 	if (unlikely(is_bad_pmem(&pmem->bb, sector, size))) | ||||
| 		return -EIO; | ||||
| 	*kaddr = pmem->virt_addr + offset; | ||||
| 	*pfn = phys_to_pfn_t(pmem->phys_addr + offset, pmem->pfn_flags); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * If badblocks are present, limit known good range to the | ||||
| 	 * requested range. | ||||
| 	 */ | ||||
| 	if (unlikely(pmem->bb.count)) | ||||
| 		return size; | ||||
| 	return pmem->size - pmem->pfn_pad - offset; | ||||
| } | ||||
| @ -52,7 +52,7 @@ static struct nfit_test_resource *__get_nfit_res(resource_size_t resource) | ||||
| 	return NULL; | ||||
| } | ||||
| 
 | ||||
| static struct nfit_test_resource *get_nfit_res(resource_size_t resource) | ||||
| struct nfit_test_resource *get_nfit_res(resource_size_t resource) | ||||
| { | ||||
| 	struct nfit_test_resource *res; | ||||
| 
 | ||||
| @ -62,6 +62,7 @@ static struct nfit_test_resource *get_nfit_res(resource_size_t resource) | ||||
| 
 | ||||
| 	return res; | ||||
| } | ||||
| EXPORT_SYMBOL(get_nfit_res); | ||||
| 
 | ||||
| void __iomem *__nfit_test_ioremap(resource_size_t offset, unsigned long size, | ||||
| 		void __iomem *(*fallback_fn)(resource_size_t, unsigned long)) | ||||
|  | ||||
| @ -12,6 +12,7 @@ | ||||
|  */ | ||||
| #ifndef __NFIT_TEST_H__ | ||||
| #define __NFIT_TEST_H__ | ||||
| #include <linux/list.h> | ||||
| 
 | ||||
| struct nfit_test_resource { | ||||
| 	struct list_head list; | ||||
| @ -26,4 +27,5 @@ void __iomem *__wrap_ioremap_nocache(resource_size_t offset, | ||||
| void __wrap_iounmap(volatile void __iomem *addr); | ||||
| void nfit_test_setup(nfit_test_lookup_fn lookup); | ||||
| void nfit_test_teardown(void); | ||||
| struct nfit_test_resource *get_nfit_res(resource_size_t resource); | ||||
| #endif | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user