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