mirror of
				https://github.com/torvalds/linux.git
				synced 2025-10-31 08:38:45 +02:00 
			
		
		
		
	dax/hmem: Move hmem device registration to dax_hmem.ko
In preparation for the CXL region driver to take over the responsibility of registering device-dax instances for CXL regions, move the registration of "hmem" devices to dax_hmem.ko. Previously the builtin component of this enabling (drivers/dax/hmem/device.o) would register platform devices for each address range and trigger the dax_hmem.ko module to load and attach device-dax instances to those devices. Now, the ranges are collected from the HMAT and EFI memory map walking, but the device creation is deferred. A new "hmem_platform" device is created which triggers dax_hmem.ko to load and register the platform devices. Tested-by: Fan Ni <fan.ni@samsung.com> Reviewed-by: Dave Jiang <dave.jiang@intel.com> Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com> Link: https://lore.kernel.org/r/167602002771.1924368.5653558226424530127.stgit@dwillia2-xfh.jf.intel.com Signed-off-by: Dan Williams <dan.j.williams@intel.com>
This commit is contained in:
		
							parent
							
								
									fe098574a9
								
							
						
					
					
						commit
						7dab174e2e
					
				
					 5 changed files with 157 additions and 54 deletions
				
			
		|  | @ -718,7 +718,7 @@ static void hmat_register_target_devices(struct memory_target *target) | |||
| 	for (res = target->memregions.child; res; res = res->sibling) { | ||||
| 		int target_nid = pxm_to_node(target->memory_pxm); | ||||
| 
 | ||||
| 		hmem_register_device(target_nid, res); | ||||
| 		hmem_register_resource(target_nid, res); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -46,7 +46,7 @@ config DEV_DAX_HMEM | |||
| 	  Say M if unsure. | ||||
| 
 | ||||
| config DEV_DAX_HMEM_DEVICES | ||||
| 	depends on DEV_DAX_HMEM && DAX=y | ||||
| 	depends on DEV_DAX_HMEM && DAX | ||||
| 	def_bool y | ||||
| 
 | ||||
| config DEV_DAX_KMEM | ||||
|  |  | |||
|  | @ -8,6 +8,8 @@ | |||
| static bool nohmem; | ||||
| module_param_named(disable, nohmem, bool, 0444); | ||||
| 
 | ||||
| static bool platform_initialized; | ||||
| static DEFINE_MUTEX(hmem_resource_lock); | ||||
| static struct resource hmem_active = { | ||||
| 	.name = "HMEM devices", | ||||
| 	.start = 0, | ||||
|  | @ -15,71 +17,66 @@ static struct resource hmem_active = { | |||
| 	.flags = IORESOURCE_MEM, | ||||
| }; | ||||
| 
 | ||||
| void hmem_register_device(int target_nid, struct resource *res) | ||||
| int walk_hmem_resources(struct device *host, walk_hmem_fn fn) | ||||
| { | ||||
| 	struct resource *res; | ||||
| 	int rc = 0; | ||||
| 
 | ||||
| 	mutex_lock(&hmem_resource_lock); | ||||
| 	for (res = hmem_active.child; res; res = res->sibling) { | ||||
| 		rc = fn(host, (int) res->desc, res); | ||||
| 		if (rc) | ||||
| 			break; | ||||
| 	} | ||||
| 	mutex_unlock(&hmem_resource_lock); | ||||
| 	return rc; | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(walk_hmem_resources); | ||||
| 
 | ||||
| static void __hmem_register_resource(int target_nid, struct resource *res) | ||||
| { | ||||
| 	struct platform_device *pdev; | ||||
| 	struct memregion_info info; | ||||
| 	int rc, id; | ||||
| 	struct resource *new; | ||||
| 	int rc; | ||||
| 
 | ||||
| 	if (nohmem) | ||||
| 		return; | ||||
| 
 | ||||
| 	rc = region_intersects(res->start, resource_size(res), IORESOURCE_MEM, | ||||
| 			       IORES_DESC_SOFT_RESERVED); | ||||
| 	if (rc != REGION_INTERSECTS) | ||||
| 		return; | ||||
| 
 | ||||
| 	id = memregion_alloc(GFP_KERNEL); | ||||
| 	if (id < 0) { | ||||
| 		pr_err("memregion allocation failure for %pr\n", res); | ||||
| 	new = __request_region(&hmem_active, res->start, resource_size(res), "", | ||||
| 			       0); | ||||
| 	if (!new) { | ||||
| 		pr_debug("hmem range %pr already active\n", res); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	pdev = platform_device_alloc("hmem", id); | ||||
| 	new->desc = target_nid; | ||||
| 
 | ||||
| 	if (platform_initialized) | ||||
| 		return; | ||||
| 
 | ||||
| 	pdev = platform_device_alloc("hmem_platform", 0); | ||||
| 	if (!pdev) { | ||||
| 		pr_err("hmem device allocation failure for %pr\n", res); | ||||
| 		goto out_pdev; | ||||
| 	} | ||||
| 
 | ||||
| 	if (!__request_region(&hmem_active, res->start, resource_size(res), | ||||
| 			      dev_name(&pdev->dev), 0)) { | ||||
| 		dev_dbg(&pdev->dev, "hmem range %pr already active\n", res); | ||||
| 		goto out_active; | ||||
| 	} | ||||
| 
 | ||||
| 	pdev->dev.numa_node = numa_map_to_online_node(target_nid); | ||||
| 	info = (struct memregion_info) { | ||||
| 		.target_node = target_nid, | ||||
| 		.range = { | ||||
| 			.start = res->start, | ||||
| 			.end = res->end, | ||||
| 		}, | ||||
| 	}; | ||||
| 	rc = platform_device_add_data(pdev, &info, sizeof(info)); | ||||
| 	if (rc < 0) { | ||||
| 		pr_err("hmem memregion_info allocation failure for %pr\n", res); | ||||
| 		goto out_resource; | ||||
| 		pr_err_once("failed to register device-dax hmem_platform device\n"); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	rc = platform_device_add(pdev); | ||||
| 	if (rc < 0) { | ||||
| 		dev_err(&pdev->dev, "device add failed for %pr\n", res); | ||||
| 		goto out_resource; | ||||
| 	} | ||||
| 	if (rc) | ||||
| 		platform_device_put(pdev); | ||||
| 	else | ||||
| 		platform_initialized = true; | ||||
| } | ||||
| 
 | ||||
| 	return; | ||||
| void hmem_register_resource(int target_nid, struct resource *res) | ||||
| { | ||||
| 	if (nohmem) | ||||
| 		return; | ||||
| 
 | ||||
| out_resource: | ||||
| 	__release_region(&hmem_active, res->start, resource_size(res)); | ||||
| out_active: | ||||
| 	platform_device_put(pdev); | ||||
| out_pdev: | ||||
| 	memregion_free(id); | ||||
| 	mutex_lock(&hmem_resource_lock); | ||||
| 	__hmem_register_resource(target_nid, res); | ||||
| 	mutex_unlock(&hmem_resource_lock); | ||||
| } | ||||
| 
 | ||||
| static __init int hmem_register_one(struct resource *res, void *data) | ||||
| { | ||||
| 	hmem_register_device(phys_to_target_node(res->start), res); | ||||
| 	hmem_register_resource(phys_to_target_node(res->start), res); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
|  |  | |||
|  | @ -3,6 +3,7 @@ | |||
| #include <linux/memregion.h> | ||||
| #include <linux/module.h> | ||||
| #include <linux/pfn_t.h> | ||||
| #include <linux/dax.h> | ||||
| #include "../bus.h" | ||||
| 
 | ||||
| static bool region_idle; | ||||
|  | @ -43,8 +44,110 @@ static struct platform_driver dax_hmem_driver = { | |||
| 	}, | ||||
| }; | ||||
| 
 | ||||
| module_platform_driver(dax_hmem_driver); | ||||
| static void release_memregion(void *data) | ||||
| { | ||||
| 	memregion_free((long) data); | ||||
| } | ||||
| 
 | ||||
| static void release_hmem(void *pdev) | ||||
| { | ||||
| 	platform_device_unregister(pdev); | ||||
| } | ||||
| 
 | ||||
| static int hmem_register_device(struct device *host, int target_nid, | ||||
| 				const struct resource *res) | ||||
| { | ||||
| 	struct platform_device *pdev; | ||||
| 	struct memregion_info info; | ||||
| 	long id; | ||||
| 	int rc; | ||||
| 
 | ||||
| 	rc = region_intersects(res->start, resource_size(res), IORESOURCE_MEM, | ||||
| 			       IORES_DESC_SOFT_RESERVED); | ||||
| 	if (rc != REGION_INTERSECTS) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	id = memregion_alloc(GFP_KERNEL); | ||||
| 	if (id < 0) { | ||||
| 		dev_err(host, "memregion allocation failure for %pr\n", res); | ||||
| 		return -ENOMEM; | ||||
| 	} | ||||
| 	rc = devm_add_action_or_reset(host, release_memregion, (void *) id); | ||||
| 	if (rc) | ||||
| 		return rc; | ||||
| 
 | ||||
| 	pdev = platform_device_alloc("hmem", id); | ||||
| 	if (!pdev) { | ||||
| 		dev_err(host, "device allocation failure for %pr\n", res); | ||||
| 		return -ENOMEM; | ||||
| 	} | ||||
| 
 | ||||
| 	pdev->dev.numa_node = numa_map_to_online_node(target_nid); | ||||
| 	info = (struct memregion_info) { | ||||
| 		.target_node = target_nid, | ||||
| 		.range = { | ||||
| 			.start = res->start, | ||||
| 			.end = res->end, | ||||
| 		}, | ||||
| 	}; | ||||
| 	rc = platform_device_add_data(pdev, &info, sizeof(info)); | ||||
| 	if (rc < 0) { | ||||
| 		dev_err(host, "memregion_info allocation failure for %pr\n", | ||||
| 		       res); | ||||
| 		goto out_put; | ||||
| 	} | ||||
| 
 | ||||
| 	rc = platform_device_add(pdev); | ||||
| 	if (rc < 0) { | ||||
| 		dev_err(host, "%s add failed for %pr\n", dev_name(&pdev->dev), | ||||
| 			res); | ||||
| 		goto out_put; | ||||
| 	} | ||||
| 
 | ||||
| 	return devm_add_action_or_reset(host, release_hmem, pdev); | ||||
| 
 | ||||
| out_put: | ||||
| 	platform_device_put(pdev); | ||||
| 	return rc; | ||||
| } | ||||
| 
 | ||||
| static int dax_hmem_platform_probe(struct platform_device *pdev) | ||||
| { | ||||
| 	return walk_hmem_resources(&pdev->dev, hmem_register_device); | ||||
| } | ||||
| 
 | ||||
| static struct platform_driver dax_hmem_platform_driver = { | ||||
| 	.probe = dax_hmem_platform_probe, | ||||
| 	.driver = { | ||||
| 		.name = "hmem_platform", | ||||
| 	}, | ||||
| }; | ||||
| 
 | ||||
| static __init int dax_hmem_init(void) | ||||
| { | ||||
| 	int rc; | ||||
| 
 | ||||
| 	rc = platform_driver_register(&dax_hmem_platform_driver); | ||||
| 	if (rc) | ||||
| 		return rc; | ||||
| 
 | ||||
| 	rc = platform_driver_register(&dax_hmem_driver); | ||||
| 	if (rc) | ||||
| 		platform_driver_unregister(&dax_hmem_platform_driver); | ||||
| 
 | ||||
| 	return rc; | ||||
| } | ||||
| 
 | ||||
| static __exit void dax_hmem_exit(void) | ||||
| { | ||||
| 	platform_driver_unregister(&dax_hmem_driver); | ||||
| 	platform_driver_unregister(&dax_hmem_platform_driver); | ||||
| } | ||||
| 
 | ||||
| module_init(dax_hmem_init); | ||||
| module_exit(dax_hmem_exit); | ||||
| 
 | ||||
| MODULE_ALIAS("platform:hmem*"); | ||||
| MODULE_ALIAS("platform:hmem_platform*"); | ||||
| MODULE_LICENSE("GPL v2"); | ||||
| MODULE_AUTHOR("Intel Corporation"); | ||||
|  |  | |||
|  | @ -262,11 +262,14 @@ static inline bool dax_mapping(struct address_space *mapping) | |||
| } | ||||
| 
 | ||||
| #ifdef CONFIG_DEV_DAX_HMEM_DEVICES | ||||
| void hmem_register_device(int target_nid, struct resource *r); | ||||
| void hmem_register_resource(int target_nid, struct resource *r); | ||||
| #else | ||||
| static inline void hmem_register_device(int target_nid, struct resource *r) | ||||
| static inline void hmem_register_resource(int target_nid, struct resource *r) | ||||
| { | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| typedef int (*walk_hmem_fn)(struct device *dev, int target_nid, | ||||
| 			    const struct resource *res); | ||||
| int walk_hmem_resources(struct device *dev, walk_hmem_fn fn); | ||||
| #endif | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Dan Williams
						Dan Williams