aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc
diff options
context:
space:
mode:
authorRashmica Gupta <rashmica.g@gmail.com>2018-08-03 02:06:00 -0400
committerMichael Ellerman <mpe@ellerman.id.au>2018-08-10 08:12:31 -0400
commitd3da701d3308ce1fa457f32c6c9e2102aedea030 (patch)
tree6475bec1418566c5edc0d1d9ff12448bee69ec9a /arch/powerpc
parent7c27a26e1ed5a7dd709aa19685d2c98f64e1cf0c (diff)
powerpc/powernv: Allow memory that has been hot-removed to be hot-added
This patch allows the memory removed by memtrace to be readded to the kernel. So now you don't have to reboot your system to add the memory back to the kernel or to have a different amount of memory removed. Signed-off-by: Rashmica Gupta <rashmica.g@gmail.com> Tested-by: Michael Neuling <mikey@neuling.org> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Diffstat (limited to 'arch/powerpc')
-rw-r--r--arch/powerpc/platforms/powernv/memtrace.c92
1 files changed, 85 insertions, 7 deletions
diff --git a/arch/powerpc/platforms/powernv/memtrace.c b/arch/powerpc/platforms/powernv/memtrace.c
index f73101119eba..51dc398ae3f7 100644
--- a/arch/powerpc/platforms/powernv/memtrace.c
+++ b/arch/powerpc/platforms/powernv/memtrace.c
@@ -177,8 +177,11 @@ static int memtrace_init_debugfs(void)
177 177
178 snprintf(ent->name, 16, "%08x", ent->nid); 178 snprintf(ent->name, 16, "%08x", ent->nid);
179 dir = debugfs_create_dir(ent->name, memtrace_debugfs_dir); 179 dir = debugfs_create_dir(ent->name, memtrace_debugfs_dir);
180 if (!dir) 180 if (!dir) {
181 pr_err("Failed to create debugfs directory for node %d\n",
182 ent->nid);
181 return -1; 183 return -1;
184 }
182 185
183 ent->dir = dir; 186 ent->dir = dir;
184 debugfs_create_file("trace", 0400, dir, ent, &memtrace_fops); 187 debugfs_create_file("trace", 0400, dir, ent, &memtrace_fops);
@@ -189,18 +192,93 @@ static int memtrace_init_debugfs(void)
189 return ret; 192 return ret;
190} 193}
191 194
195static int online_mem_block(struct memory_block *mem, void *arg)
196{
197 return device_online(&mem->dev);
198}
199
200/*
201 * Iterate through the chunks of memory we have removed from the kernel
202 * and attempt to add them back to the kernel.
203 */
204static int memtrace_online(void)
205{
206 int i, ret = 0;
207 struct memtrace_entry *ent;
208
209 for (i = memtrace_array_nr - 1; i >= 0; i--) {
210 ent = &memtrace_array[i];
211
212 /* We have onlined this chunk previously */
213 if (ent->nid == -1)
214 continue;
215
216 /* Remove from io mappings */
217 if (ent->mem) {
218 iounmap(ent->mem);
219 ent->mem = 0;
220 }
221
222 if (add_memory(ent->nid, ent->start, ent->size)) {
223 pr_err("Failed to add trace memory to node %d\n",
224 ent->nid);
225 ret += 1;
226 continue;
227 }
228
229 /*
230 * If kernel isn't compiled with the auto online option
231 * we need to online the memory ourselves.
232 */
233 if (!memhp_auto_online) {
234 walk_memory_range(PFN_DOWN(ent->start),
235 PFN_UP(ent->start + ent->size - 1),
236 NULL, online_mem_block);
237 }
238
239 /*
240 * Memory was added successfully so clean up references to it
241 * so on reentry we can tell that this chunk was added.
242 */
243 debugfs_remove_recursive(ent->dir);
244 pr_info("Added trace memory back to node %d\n", ent->nid);
245 ent->size = ent->start = ent->nid = -1;
246 }
247 if (ret)
248 return ret;
249
250 /* If all chunks of memory were added successfully, reset globals */
251 kfree(memtrace_array);
252 memtrace_array = NULL;
253 memtrace_size = 0;
254 memtrace_array_nr = 0;
255 return 0;
256}
257
192static int memtrace_enable_set(void *data, u64 val) 258static int memtrace_enable_set(void *data, u64 val)
193{ 259{
194 if (memtrace_size) 260 u64 bytes;
261
262 /*
263 * Don't attempt to do anything if size isn't aligned to a memory
264 * block or equal to zero.
265 */
266 bytes = memory_block_size_bytes();
267 if (val & (bytes - 1)) {
268 pr_err("Value must be aligned with 0x%llx\n", bytes);
195 return -EINVAL; 269 return -EINVAL;
270 }
196 271
197 if (!val) 272 /* Re-add/online previously removed/offlined memory */
198 return -EINVAL; 273 if (memtrace_size) {
274 if (memtrace_online())
275 return -EAGAIN;
276 }
199 277
200 /* Make sure size is aligned to a memory block */ 278 if (!val)
201 if (val & (memory_block_size_bytes() - 1)) 279 return 0;
202 return -EINVAL;
203 280
281 /* Offline and remove memory */
204 if (memtrace_init_regions_runtime(val)) 282 if (memtrace_init_regions_runtime(val))
205 return -EINVAL; 283 return -EINVAL;
206 284