Source
1
+
// SPDX-License-Identifier: GPL-2.0
2
+
/* Copyright(c) 2016-2019 Intel Corporation. All rights reserved. */
3
+
4
+
5
+
6
+
7
+
8
+
9
+
10
+
11
+
12
+
13
+
14
+
15
+
16
+
17
+
int dev_dax_kmem_probe(struct device *dev)
18
+
{
19
+
struct dev_dax *dev_dax = to_dev_dax(dev);
20
+
struct resource *res = &dev_dax->region->res;
21
+
resource_size_t kmem_start;
22
+
resource_size_t kmem_size;
23
+
resource_size_t kmem_end;
24
+
struct resource *new_res;
25
+
int numa_node;
26
+
int rc;
27
+
28
+
/*
29
+
* Ensure good NUMA information for the persistent memory.
30
+
* Without this check, there is a risk that slow memory
31
+
* could be mixed in a node with faster memory, causing
32
+
* unavoidable performance issues.
33
+
*/
34
+
numa_node = dev_dax->target_node;
35
+
if (numa_node < 0) {
36
+
dev_warn(dev, "rejecting DAX region %pR with invalid node: %d\n",
37
+
res, numa_node);
38
+
return -EINVAL;
39
+
}
40
+
41
+
/* Hotplug starting at the beginning of the next block: */
42
+
kmem_start = ALIGN(res->start, memory_block_size_bytes());
43
+
44
+
kmem_size = resource_size(res);
45
+
/* Adjust the size down to compensate for moving up kmem_start: */
46
+
kmem_size -= kmem_start - res->start;
47
+
/* Align the size down to cover only complete blocks: */
48
+
kmem_size &= ~(memory_block_size_bytes() - 1);
49
+
kmem_end = kmem_start + kmem_size;
50
+
51
+
/* Region is permanently reserved. Hot-remove not yet implemented. */
52
+
new_res = request_mem_region(kmem_start, kmem_size, dev_name(dev));
53
+
if (!new_res) {
54
+
dev_warn(dev, "could not reserve region [%pa-%pa]\n",
55
+
&kmem_start, &kmem_end);
56
+
return -EBUSY;
57
+
}
58
+
59
+
/*
60
+
* Set flags appropriate for System RAM. Leave ..._BUSY clear
61
+
* so that add_memory() can add a child resource. Do not
62
+
* inherit flags from the parent since it may set new flags
63
+
* unknown to us that will break add_memory() below.
64
+
*/
65
+
new_res->flags = IORESOURCE_SYSTEM_RAM;
66
+
new_res->name = dev_name(dev);
67
+
68
+
rc = add_memory(numa_node, new_res->start, resource_size(new_res));
69
+
if (rc)
70
+
return rc;
71
+
72
+
return 0;
73
+
}
74
+
75
+
static int dev_dax_kmem_remove(struct device *dev)
76
+
{
77
+
/*
78
+
* Purposely leak the request_mem_region() for the device-dax
79
+
* range and return '0' to ->remove() attempts. The removal of
80
+
* the device from the driver always succeeds, but the region
81
+
* is permanently pinned as reserved by the unreleased
82
+
* request_mem_region().
83
+
*/
84
+
return 0;
85
+
}
86
+
87
+
static struct dax_device_driver device_dax_kmem_driver = {
88
+
.drv = {
89
+
.probe = dev_dax_kmem_probe,
90
+
.remove = dev_dax_kmem_remove,
91
+
},
92
+
};
93
+
94
+
static int __init dax_kmem_init(void)
95
+
{
96
+
return dax_driver_register(&device_dax_kmem_driver);
97
+
}
98
+
99
+
static void __exit dax_kmem_exit(void)
100
+
{
101
+
dax_driver_unregister(&device_dax_kmem_driver);
102
+
}
103
+
104
+
MODULE_AUTHOR("Intel Corporation");
105
+
MODULE_LICENSE("GPL v2");
106
+
module_init(dax_kmem_init);
107
+
module_exit(dax_kmem_exit);
108
+
MODULE_ALIAS_DAX_DEVICE(0);