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