blob: 6fe2cb1c5f7c18d82af65aea4ad5fac24d59a25d [file] [log] [blame]
Dave Hansenc221c0b2019-02-25 10:57:40 -08001// SPDX-License-Identifier: GPL-2.0
2/* Copyright(c) 2016-2019 Intel Corporation. All rights reserved. */
3#include <linux/memremap.h>
4#include <linux/pagemap.h>
5#include <linux/memory.h>
6#include <linux/module.h>
7#include <linux/device.h>
8#include <linux/pfn_t.h>
9#include <linux/slab.h>
10#include <linux/dax.h>
11#include <linux/fs.h>
12#include <linux/mm.h>
13#include <linux/mman.h>
14#include "dax-private.h"
15#include "bus.h"
16
David Hildenbrand8a725e42020-06-04 16:48:48 -070017/* Memory resource name used for add_memory_driver_managed(). */
18static const char *kmem_name;
19/* Set if any memory will remain added when the driver will be unloaded. */
20static bool any_hotremove_failed;
21
Dan Williams59bc8d12020-10-13 16:49:48 -070022static struct range dax_kmem_range(struct dev_dax *dev_dax)
23{
24 struct range range;
25
26 /* memory-block align the hotplug range */
27 range.start = ALIGN(dev_dax->range.start, memory_block_size_bytes());
28 range.end = ALIGN_DOWN(dev_dax->range.end + 1, memory_block_size_bytes()) - 1;
29 return range;
30}
31
Dave Hansenc221c0b2019-02-25 10:57:40 -080032int dev_dax_kmem_probe(struct device *dev)
33{
34 struct dev_dax *dev_dax = to_dev_dax(dev);
Dan Williams59bc8d12020-10-13 16:49:48 -070035 struct range range = dax_kmem_range(dev_dax);
Dave Hansenc221c0b2019-02-25 10:57:40 -080036 struct resource *new_res;
Dan Williams7e6b4312020-10-13 16:49:53 -070037 char *res_name;
Dave Hansenc221c0b2019-02-25 10:57:40 -080038 int numa_node;
39 int rc;
40
41 /*
42 * Ensure good NUMA information for the persistent memory.
43 * Without this check, there is a risk that slow memory
44 * could be mixed in a node with faster memory, causing
45 * unavoidable performance issues.
46 */
47 numa_node = dev_dax->target_node;
48 if (numa_node < 0) {
Dan Williamsf5516ec2020-10-13 16:49:43 -070049 dev_warn(dev, "rejecting DAX region with invalid node: %d\n",
50 numa_node);
Dave Hansenc221c0b2019-02-25 10:57:40 -080051 return -EINVAL;
52 }
53
Dan Williams7e6b4312020-10-13 16:49:53 -070054 res_name = kstrdup(dev_name(dev), GFP_KERNEL);
55 if (!res_name)
David Hildenbrand60858c02020-05-22 22:22:42 -070056 return -ENOMEM;
57
58 /* Region is permanently reserved if hotremove fails. */
Dan Williams7e6b4312020-10-13 16:49:53 -070059 new_res = request_mem_region(range.start, range_len(&range), res_name);
Dave Hansenc221c0b2019-02-25 10:57:40 -080060 if (!new_res) {
Dan Williams59bc8d12020-10-13 16:49:48 -070061 dev_warn(dev, "could not reserve region [%#llx-%#llx]\n", range.start, range.end);
Dan Williams7e6b4312020-10-13 16:49:53 -070062 kfree(res_name);
Dave Hansenc221c0b2019-02-25 10:57:40 -080063 return -EBUSY;
64 }
65
66 /*
67 * Set flags appropriate for System RAM. Leave ..._BUSY clear
68 * so that add_memory() can add a child resource. Do not
69 * inherit flags from the parent since it may set new flags
70 * unknown to us that will break add_memory() below.
71 */
72 new_res->flags = IORESOURCE_SYSTEM_RAM;
Dave Hansenc221c0b2019-02-25 10:57:40 -080073
David Hildenbrand8a725e42020-06-04 16:48:48 -070074 /*
75 * Ensure that future kexec'd kernels will not treat this as RAM
76 * automatically.
77 */
78 rc = add_memory_driver_managed(numa_node, new_res->start,
79 resource_size(new_res), kmem_name);
Pavel Tatashin31e4ca92019-07-16 16:30:27 -070080 if (rc) {
81 release_resource(new_res);
82 kfree(new_res);
Dan Williams7e6b4312020-10-13 16:49:53 -070083 kfree(res_name);
Dave Hansenc221c0b2019-02-25 10:57:40 -080084 return rc;
Pavel Tatashin31e4ca92019-07-16 16:30:27 -070085 }
Dan Williams7e6b4312020-10-13 16:49:53 -070086
87 dev_set_drvdata(dev, res_name);
Pavel Tatashin9f960da2019-07-16 16:30:35 -070088 dev_dax->dax_kmem_res = new_res;
Dave Hansenc221c0b2019-02-25 10:57:40 -080089
90 return 0;
91}
92
Pavel Tatashin9f960da2019-07-16 16:30:35 -070093#ifdef CONFIG_MEMORY_HOTREMOVE
94static int dev_dax_kmem_remove(struct device *dev)
95{
96 struct dev_dax *dev_dax = to_dev_dax(dev);
Dan Williams59bc8d12020-10-13 16:49:48 -070097 struct range range = dax_kmem_range(dev_dax);
Pavel Tatashin9f960da2019-07-16 16:30:35 -070098 struct resource *res = dev_dax->dax_kmem_res;
Dan Williams7e6b4312020-10-13 16:49:53 -070099 const char *res_name = dev_get_drvdata(dev);
Pavel Tatashin9f960da2019-07-16 16:30:35 -0700100 int rc;
101
102 /*
103 * We have one shot for removing memory, if some memory blocks were not
104 * offline prior to calling this function remove_memory() will fail, and
105 * there is no way to hotremove this memory until reboot because device
106 * unbind will succeed even if we return failure.
107 */
Dan Williams59bc8d12020-10-13 16:49:48 -0700108 rc = remove_memory(dev_dax->target_node, range.start, range_len(&range));
Pavel Tatashin9f960da2019-07-16 16:30:35 -0700109 if (rc) {
David Hildenbrand8a725e42020-06-04 16:48:48 -0700110 any_hotremove_failed = true;
Dan Williams59bc8d12020-10-13 16:49:48 -0700111 dev_err(dev, "%#llx-%#llx cannot be hotremoved until the next reboot\n",
112 range.start, range.end);
Pavel Tatashin9f960da2019-07-16 16:30:35 -0700113 return rc;
114 }
115
116 /* Release and free dax resources */
117 release_resource(res);
118 kfree(res);
David Hildenbrand60858c02020-05-22 22:22:42 -0700119 kfree(res_name);
Pavel Tatashin9f960da2019-07-16 16:30:35 -0700120 dev_dax->dax_kmem_res = NULL;
121
122 return 0;
123}
124#else
Dave Hansenc221c0b2019-02-25 10:57:40 -0800125static int dev_dax_kmem_remove(struct device *dev)
126{
127 /*
Pavel Tatashin9f960da2019-07-16 16:30:35 -0700128 * Without hotremove purposely leak the request_mem_region() for the
129 * device-dax range and return '0' to ->remove() attempts. The removal
130 * of the device from the driver always succeeds, but the region is
131 * permanently pinned as reserved by the unreleased
Dave Hansenc221c0b2019-02-25 10:57:40 -0800132 * request_mem_region().
133 */
David Hildenbrand8a725e42020-06-04 16:48:48 -0700134 any_hotremove_failed = true;
Dave Hansenc221c0b2019-02-25 10:57:40 -0800135 return 0;
136}
Pavel Tatashin9f960da2019-07-16 16:30:35 -0700137#endif /* CONFIG_MEMORY_HOTREMOVE */
Dave Hansenc221c0b2019-02-25 10:57:40 -0800138
139static struct dax_device_driver device_dax_kmem_driver = {
140 .drv = {
141 .probe = dev_dax_kmem_probe,
142 .remove = dev_dax_kmem_remove,
143 },
144};
145
146static int __init dax_kmem_init(void)
147{
David Hildenbrand8a725e42020-06-04 16:48:48 -0700148 int rc;
149
150 /* Resource name is permanently allocated if any hotremove fails. */
151 kmem_name = kstrdup_const("System RAM (kmem)", GFP_KERNEL);
152 if (!kmem_name)
153 return -ENOMEM;
154
155 rc = dax_driver_register(&device_dax_kmem_driver);
156 if (rc)
157 kfree_const(kmem_name);
158 return rc;
Dave Hansenc221c0b2019-02-25 10:57:40 -0800159}
160
161static void __exit dax_kmem_exit(void)
162{
163 dax_driver_unregister(&device_dax_kmem_driver);
David Hildenbrand8a725e42020-06-04 16:48:48 -0700164 if (!any_hotremove_failed)
165 kfree_const(kmem_name);
Dave Hansenc221c0b2019-02-25 10:57:40 -0800166}
167
168MODULE_AUTHOR("Intel Corporation");
169MODULE_LICENSE("GPL v2");
170module_init(dax_kmem_init);
171module_exit(dax_kmem_exit);
172MODULE_ALIAS_DAX_DEVICE(0);