1 // SPDX-License-Identifier: GPL-2.0 2 #include <linux/platform_device.h> 3 #include <linux/memregion.h> 4 #include <linux/module.h> 5 #include <linux/dax.h> 6 #include <linux/mm.h> 7 8 static bool nohmem; 9 module_param_named(disable, nohmem, bool, 0444); 10 11 bool dax_hmem_initial_probe; 12 EXPORT_SYMBOL_FOR_MODULES(dax_hmem_initial_probe, "dax_hmem"); 13 14 static bool platform_initialized; 15 static DEFINE_MUTEX(hmem_resource_lock); 16 static struct resource hmem_active = { 17 .name = "HMEM devices", 18 .start = 0, 19 .end = -1, 20 .flags = IORESOURCE_MEM, 21 }; 22 23 int walk_hmem_resources(struct device *host, walk_hmem_fn fn) 24 { 25 struct resource *res; 26 int rc = 0; 27 28 mutex_lock(&hmem_resource_lock); 29 for (res = hmem_active.child; res; res = res->sibling) { 30 rc = fn(host, (int) res->desc, res); 31 if (rc) 32 break; 33 } 34 mutex_unlock(&hmem_resource_lock); 35 return rc; 36 } 37 EXPORT_SYMBOL_GPL(walk_hmem_resources); 38 39 static void __hmem_register_resource(int target_nid, struct resource *res) 40 { 41 struct platform_device *pdev; 42 struct resource *new; 43 int rc; 44 45 new = __request_region(&hmem_active, res->start, resource_size(res), "", 46 0); 47 if (!new) { 48 pr_debug("hmem range %pr already active\n", res); 49 return; 50 } 51 52 new->desc = target_nid; 53 54 if (platform_initialized) 55 return; 56 57 pdev = platform_device_alloc("hmem_platform", 0); 58 if (!pdev) { 59 pr_err_once("failed to register device-dax hmem_platform device\n"); 60 return; 61 } 62 63 rc = platform_device_add(pdev); 64 if (rc) 65 platform_device_put(pdev); 66 else 67 platform_initialized = true; 68 } 69 70 void hmem_register_resource(int target_nid, struct resource *res) 71 { 72 if (nohmem) 73 return; 74 75 mutex_lock(&hmem_resource_lock); 76 __hmem_register_resource(target_nid, res); 77 mutex_unlock(&hmem_resource_lock); 78 } 79 80 static __init int hmem_register_one(struct resource *res, void *data) 81 { 82 hmem_register_resource(phys_to_target_node(res->start), res); 83 84 return 0; 85 } 86 87 static __init int hmem_init(void) 88 { 89 walk_soft_reserve_res(0, -1, NULL, hmem_register_one); 90 return 0; 91 } 92 93 /* 94 * As this is a fallback for address ranges unclaimed by the ACPI HMAT 95 * parsing it must be at an initcall level greater than hmat_init(). 96 */ 97 device_initcall(hmem_init); 98