blob: 086997212dbbac5fe259fb6274f94329a1d3d9f8 [file] [log] [blame]
Greg Kroah-Hartmanb2441312017-11-01 15:07:57 +01001// SPDX-License-Identifier: GPL-2.0
Dave Hansen3947be12005-10-29 18:16:54 -07002/*
Kay Sievers10fbcf42011-12-21 14:48:43 -08003 * Memory subsystem support
Dave Hansen3947be12005-10-29 18:16:54 -07004 *
5 * Written by Matt Tolentino <matthew.e.tolentino@intel.com>
6 * Dave Hansen <haveblue@us.ibm.com>
7 *
8 * This file provides the necessary infrastructure to represent
9 * a SPARSEMEM-memory-model system's physical memory in /sysfs.
10 * All arch-independent code that assumes MEMORY_HOTPLUG requires
11 * SPARSEMEM should be contained here, or in mm/memory_hotplug.c.
12 */
13
Dave Hansen3947be12005-10-29 18:16:54 -070014#include <linux/module.h>
15#include <linux/init.h>
Dave Hansen3947be12005-10-29 18:16:54 -070016#include <linux/topology.h>
Randy.Dunlapc59ede72006-01-11 12:17:46 -080017#include <linux/capability.h>
Dave Hansen3947be12005-10-29 18:16:54 -070018#include <linux/device.h>
19#include <linux/memory.h>
Dave Hansen3947be12005-10-29 18:16:54 -070020#include <linux/memory_hotplug.h>
21#include <linux/mm.h>
Shaohua Li9f1b16a2008-10-18 20:27:12 -070022#include <linux/stat.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090023#include <linux/slab.h>
Shaohua Li9f1b16a2008-10-18 20:27:12 -070024
Arun Sharma600634972011-07-26 16:09:06 -070025#include <linux/atomic.h>
Linus Torvalds7c0f6ba2016-12-24 11:46:01 -080026#include <linux/uaccess.h>
Dave Hansen3947be12005-10-29 18:16:54 -070027
28#define MEMORY_CLASS_NAME "memory"
Nathan Fontenot0c2c99b2011-01-20 10:43:34 -060029
Gu Zheng7315f0c2013-08-28 14:38:27 +080030#define to_memory_block(dev) container_of(dev, struct memory_block, dev)
31
Nathan Fontenot0c2c99b2011-01-20 10:43:34 -060032static int sections_per_block;
33
David Hildenbrand90ec010f2019-07-18 15:57:40 -070034static inline unsigned long base_memory_block_id(unsigned long section_nr)
Nathan Fontenot0c2c99b2011-01-20 10:43:34 -060035{
36 return section_nr / sections_per_block;
37}
Dave Hansen3947be12005-10-29 18:16:54 -070038
David Hildenbrand90ec010f2019-07-18 15:57:40 -070039static inline unsigned long pfn_to_block_id(unsigned long pfn)
David Hildenbranddb051a02019-07-18 15:56:56 -070040{
41 return base_memory_block_id(pfn_to_section_nr(pfn));
42}
43
David Hildenbrandea884642019-07-18 15:57:50 -070044static inline unsigned long phys_to_block_id(unsigned long phys)
45{
46 return pfn_to_block_id(PFN_DOWN(phys));
47}
48
Rafael J. Wysocki4960e052013-05-08 14:18:37 +020049static int memory_subsys_online(struct device *dev);
50static int memory_subsys_offline(struct device *dev);
51
Kay Sievers10fbcf42011-12-21 14:48:43 -080052static struct bus_type memory_subsys = {
Kay Sieversaf5ca3f42007-12-20 02:09:39 +010053 .name = MEMORY_CLASS_NAME,
Kay Sievers10fbcf42011-12-21 14:48:43 -080054 .dev_name = MEMORY_CLASS_NAME,
Rafael J. Wysocki4960e052013-05-08 14:18:37 +020055 .online = memory_subsys_online,
56 .offline = memory_subsys_offline,
Dave Hansen3947be12005-10-29 18:16:54 -070057};
58
Alan Sterne041c682006-03-27 01:16:30 -080059static BLOCKING_NOTIFIER_HEAD(memory_chain);
Dave Hansen3947be12005-10-29 18:16:54 -070060
Andy Whitcroft98a38eb2006-01-06 00:10:35 -080061int register_memory_notifier(struct notifier_block *nb)
Dave Hansen3947be12005-10-29 18:16:54 -070062{
Ioana Ciornei2aeebca2015-03-08 12:48:35 +020063 return blocking_notifier_chain_register(&memory_chain, nb);
Dave Hansen3947be12005-10-29 18:16:54 -070064}
Hannes Hering3c82c302008-05-07 14:43:01 +020065EXPORT_SYMBOL(register_memory_notifier);
Dave Hansen3947be12005-10-29 18:16:54 -070066
Andy Whitcroft98a38eb2006-01-06 00:10:35 -080067void unregister_memory_notifier(struct notifier_block *nb)
Dave Hansen3947be12005-10-29 18:16:54 -070068{
Ioana Ciornei2aeebca2015-03-08 12:48:35 +020069 blocking_notifier_chain_unregister(&memory_chain, nb);
Dave Hansen3947be12005-10-29 18:16:54 -070070}
Hannes Hering3c82c302008-05-07 14:43:01 +020071EXPORT_SYMBOL(unregister_memory_notifier);
Dave Hansen3947be12005-10-29 18:16:54 -070072
Yasuaki Ishimatsufa7194e2012-12-11 16:00:44 -080073static void memory_block_release(struct device *dev)
74{
Gu Zheng7315f0c2013-08-28 14:38:27 +080075 struct memory_block *mem = to_memory_block(dev);
Yasuaki Ishimatsufa7194e2012-12-11 16:00:44 -080076
77 kfree(mem);
78}
79
Nathan Fontenot0c2c99b2011-01-20 10:43:34 -060080unsigned long __weak memory_block_size_bytes(void)
81{
82 return MIN_MEMORY_BLOCK_SIZE;
83}
Dave Hansenc221c0b2019-02-25 10:57:40 -080084EXPORT_SYMBOL_GPL(memory_block_size_bytes);
Nathan Fontenot0c2c99b2011-01-20 10:43:34 -060085
Dave Hansen3947be12005-10-29 18:16:54 -070086/*
David Hildenbrandf915fb72019-09-23 15:35:43 -070087 * Show the first physical section index (number) of this memory block.
Dave Hansen3947be12005-10-29 18:16:54 -070088 */
David Hildenbrand3f8e9172018-12-03 12:16:11 +010089static ssize_t phys_index_show(struct device *dev,
90 struct device_attribute *attr, char *buf)
Dave Hansen3947be12005-10-29 18:16:54 -070091{
Gu Zheng7315f0c2013-08-28 14:38:27 +080092 struct memory_block *mem = to_memory_block(dev);
Nathan Fontenotd3360162011-01-20 10:44:29 -060093 unsigned long phys_index;
94
95 phys_index = mem->start_section_nr / sections_per_block;
96 return sprintf(buf, "%08lx\n", phys_index);
97}
98
Dave Hansen3947be12005-10-29 18:16:54 -070099/*
David Hildenbrand53cdc1c2020-03-28 19:17:19 -0700100 * Legacy interface that we cannot remove. Always indicate "removable"
101 * with CONFIG_MEMORY_HOTREMOVE - bad heuristic.
Badari Pulavarty5c755e92008-07-23 21:28:19 -0700102 */
David Hildenbrand3f8e9172018-12-03 12:16:11 +0100103static ssize_t removable_show(struct device *dev, struct device_attribute *attr,
104 char *buf)
Badari Pulavarty5c755e92008-07-23 21:28:19 -0700105{
David Hildenbrand53cdc1c2020-03-28 19:17:19 -0700106 return sprintf(buf, "%d\n", (int)IS_ENABLED(CONFIG_MEMORY_HOTREMOVE));
Badari Pulavarty5c755e92008-07-23 21:28:19 -0700107}
108
109/*
Dave Hansen3947be12005-10-29 18:16:54 -0700110 * online, offline, going offline, etc.
111 */
David Hildenbrand3f8e9172018-12-03 12:16:11 +0100112static ssize_t state_show(struct device *dev, struct device_attribute *attr,
113 char *buf)
Dave Hansen3947be12005-10-29 18:16:54 -0700114{
Gu Zheng7315f0c2013-08-28 14:38:27 +0800115 struct memory_block *mem = to_memory_block(dev);
Dave Hansen3947be12005-10-29 18:16:54 -0700116 ssize_t len = 0;
117
118 /*
119 * We can probably put these states in a nice little array
120 * so that they're not open-coded
121 */
122 switch (mem->state) {
Ioana Ciornei3d3af6a2015-03-08 12:29:04 +0200123 case MEM_ONLINE:
124 len = sprintf(buf, "online\n");
125 break;
126 case MEM_OFFLINE:
127 len = sprintf(buf, "offline\n");
128 break;
129 case MEM_GOING_OFFLINE:
130 len = sprintf(buf, "going-offline\n");
131 break;
132 default:
133 len = sprintf(buf, "ERROR-UNKNOWN-%ld\n",
134 mem->state);
135 WARN_ON(1);
136 break;
Dave Hansen3947be12005-10-29 18:16:54 -0700137 }
138
139 return len;
140}
141
Yasunori Goto7b78d332007-10-21 16:41:36 -0700142int memory_notify(unsigned long val, void *v)
Dave Hansen3947be12005-10-29 18:16:54 -0700143{
Alan Sterne041c682006-03-27 01:16:30 -0800144 return blocking_notifier_call_chain(&memory_chain, val, v);
Dave Hansen3947be12005-10-29 18:16:54 -0700145}
146
147/*
Pavel Tatashinb77eab72018-04-05 16:22:52 -0700148 * The probe routines leave the pages uninitialized, just as the bootmem code
149 * does. Make sure we do not access them, but instead use only information from
150 * within sections.
Mel Gorman2bbcb8782011-10-17 16:38:20 +0200151 */
Pavel Tatashinb77eab72018-04-05 16:22:52 -0700152static bool pages_correctly_probed(unsigned long start_pfn)
Mel Gorman2bbcb8782011-10-17 16:38:20 +0200153{
Pavel Tatashinb77eab72018-04-05 16:22:52 -0700154 unsigned long section_nr = pfn_to_section_nr(start_pfn);
155 unsigned long section_nr_end = section_nr + sections_per_block;
Mel Gorman2bbcb8782011-10-17 16:38:20 +0200156 unsigned long pfn = start_pfn;
157
158 /*
159 * memmap between sections is not contiguous except with
160 * SPARSEMEM_VMEMMAP. We lookup the page once per section
161 * and assume memmap is contiguous within each section
162 */
Pavel Tatashinb77eab72018-04-05 16:22:52 -0700163 for (; section_nr < section_nr_end; section_nr++) {
Mel Gorman2bbcb8782011-10-17 16:38:20 +0200164 if (WARN_ON_ONCE(!pfn_valid(pfn)))
165 return false;
Mel Gorman2bbcb8782011-10-17 16:38:20 +0200166
Pavel Tatashinb77eab72018-04-05 16:22:52 -0700167 if (!present_section_nr(section_nr)) {
Michal Hocko1ecc07f2018-12-28 00:39:34 -0800168 pr_warn("section %ld pfn[%lx, %lx) not present\n",
Pavel Tatashinb77eab72018-04-05 16:22:52 -0700169 section_nr, pfn, pfn + PAGES_PER_SECTION);
170 return false;
171 } else if (!valid_section_nr(section_nr)) {
Michal Hocko1ecc07f2018-12-28 00:39:34 -0800172 pr_warn("section %ld pfn[%lx, %lx) no valid memmap\n",
Pavel Tatashinb77eab72018-04-05 16:22:52 -0700173 section_nr, pfn, pfn + PAGES_PER_SECTION);
174 return false;
175 } else if (online_section_nr(section_nr)) {
Michal Hocko1ecc07f2018-12-28 00:39:34 -0800176 pr_warn("section %ld pfn[%lx, %lx) is already online\n",
Pavel Tatashinb77eab72018-04-05 16:22:52 -0700177 section_nr, pfn, pfn + PAGES_PER_SECTION);
Mel Gorman2bbcb8782011-10-17 16:38:20 +0200178 return false;
179 }
Pavel Tatashinb77eab72018-04-05 16:22:52 -0700180 pfn += PAGES_PER_SECTION;
Mel Gorman2bbcb8782011-10-17 16:38:20 +0200181 }
182
183 return true;
184}
185
186/*
Dave Hansen3947be12005-10-29 18:16:54 -0700187 * MEMORY_HOTPLUG depends on SPARSEMEM in mm/Kconfig, so it is
188 * OK to have direct references to sparsemem variables in here.
189 */
190static int
Baoquan He063b8a42019-05-13 17:19:35 -0700191memory_block_action(unsigned long start_section_nr, unsigned long action,
David Hildenbrandbd5c2342020-01-30 22:14:54 -0800192 int online_type, int nid)
Dave Hansen3947be12005-10-29 18:16:54 -0700193{
Wen Congyanga16cee12012-10-08 16:33:58 -0700194 unsigned long start_pfn;
Anton Blanchard5409d2c2011-05-11 17:25:14 +1000195 unsigned long nr_pages = PAGES_PER_SECTION * sections_per_block;
Dave Hansen3947be12005-10-29 18:16:54 -0700196 int ret;
Dave Hansen3947be12005-10-29 18:16:54 -0700197
Baoquan He063b8a42019-05-13 17:19:35 -0700198 start_pfn = section_nr_to_pfn(start_section_nr);
Greg Kroah-Hartmande0ed362011-10-18 14:00:57 -0700199
Dave Hansen3947be12005-10-29 18:16:54 -0700200 switch (action) {
Ioana Ciornei3d3af6a2015-03-08 12:29:04 +0200201 case MEM_ONLINE:
Pavel Tatashinb77eab72018-04-05 16:22:52 -0700202 if (!pages_correctly_probed(start_pfn))
Ioana Ciornei3d3af6a2015-03-08 12:29:04 +0200203 return -EBUSY;
Mel Gorman2bbcb8782011-10-17 16:38:20 +0200204
David Hildenbrandbd5c2342020-01-30 22:14:54 -0800205 ret = online_pages(start_pfn, nr_pages, online_type, nid);
Ioana Ciornei3d3af6a2015-03-08 12:29:04 +0200206 break;
207 case MEM_OFFLINE:
208 ret = offline_pages(start_pfn, nr_pages);
209 break;
210 default:
211 WARN(1, KERN_WARNING "%s(%ld, %ld) unknown action: "
Baoquan He063b8a42019-05-13 17:19:35 -0700212 "%ld\n", __func__, start_section_nr, action, action);
Ioana Ciornei3d3af6a2015-03-08 12:29:04 +0200213 ret = -EINVAL;
Dave Hansen3947be12005-10-29 18:16:54 -0700214 }
Dave Hansen3947be12005-10-29 18:16:54 -0700215
216 return ret;
217}
218
Nathan Fontenotdc18d702017-02-24 15:00:02 -0800219static int memory_block_change_state(struct memory_block *mem,
Seth Jenningsfa2be402013-08-20 16:05:05 -0500220 unsigned long to_state, unsigned long from_state_req)
Dave Hansen3947be12005-10-29 18:16:54 -0700221{
Greg Kroah-Hartmande0ed362011-10-18 14:00:57 -0700222 int ret = 0;
Nathan Fontenot0c2c99b2011-01-20 10:43:34 -0600223
Rafael J. Wysocki4960e052013-05-08 14:18:37 +0200224 if (mem->state != from_state_req)
225 return -EINVAL;
Dave Hansen3947be12005-10-29 18:16:54 -0700226
Nathan Fontenot0c2c99b2011-01-20 10:43:34 -0600227 if (to_state == MEM_OFFLINE)
228 mem->state = MEM_GOING_OFFLINE;
229
Seth Jenningsfa2be402013-08-20 16:05:05 -0500230 ret = memory_block_action(mem->start_section_nr, to_state,
David Hildenbrandbd5c2342020-01-30 22:14:54 -0800231 mem->online_type, mem->nid);
Seth Jenningsfa2be402013-08-20 16:05:05 -0500232
Rafael J. Wysockib2c064b2013-05-23 10:38:55 +0200233 mem->state = ret ? from_state_req : to_state;
Seth Jenningsfa2be402013-08-20 16:05:05 -0500234
Rafael J. Wysocki4960e052013-05-08 14:18:37 +0200235 return ret;
236}
Nathan Fontenot0c2c99b2011-01-20 10:43:34 -0600237
Seth Jenningsfa2be402013-08-20 16:05:05 -0500238/* The device lock serializes operations on memory_subsys_[online|offline] */
Rafael J. Wysocki4960e052013-05-08 14:18:37 +0200239static int memory_subsys_online(struct device *dev)
240{
Gu Zheng7315f0c2013-08-28 14:38:27 +0800241 struct memory_block *mem = to_memory_block(dev);
Rafael J. Wysocki4960e052013-05-08 14:18:37 +0200242 int ret;
Dave Hansen3947be12005-10-29 18:16:54 -0700243
Seth Jenningsfa2be402013-08-20 16:05:05 -0500244 if (mem->state == MEM_ONLINE)
245 return 0;
Rafael J. Wysocki4960e052013-05-08 14:18:37 +0200246
Seth Jenningsfa2be402013-08-20 16:05:05 -0500247 /*
David Hildenbrand3f8e9172018-12-03 12:16:11 +0100248 * If we are called from state_store(), online_type will be
Seth Jenningsfa2be402013-08-20 16:05:05 -0500249 * set >= 0 Otherwise we were called from the device online
250 * attribute and need to set the online_type.
251 */
252 if (mem->online_type < 0)
Tang Chen4f7c6b42014-08-06 16:05:13 -0700253 mem->online_type = MMOP_ONLINE_KEEP;
Rafael J. Wysocki4960e052013-05-08 14:18:37 +0200254
Seth Jenningsfa2be402013-08-20 16:05:05 -0500255 ret = memory_block_change_state(mem, MEM_ONLINE, MEM_OFFLINE);
256
257 /* clear online_type */
258 mem->online_type = -1;
259
Rafael J. Wysocki4960e052013-05-08 14:18:37 +0200260 return ret;
261}
262
263static int memory_subsys_offline(struct device *dev)
264{
Gu Zheng7315f0c2013-08-28 14:38:27 +0800265 struct memory_block *mem = to_memory_block(dev);
Rafael J. Wysocki4960e052013-05-08 14:18:37 +0200266
Seth Jenningsfa2be402013-08-20 16:05:05 -0500267 if (mem->state == MEM_OFFLINE)
268 return 0;
Rafael J. Wysocki4960e052013-05-08 14:18:37 +0200269
Seth Jenningsfa2be402013-08-20 16:05:05 -0500270 return memory_block_change_state(mem, MEM_OFFLINE, MEM_ONLINE);
Rafael J. Wysocki4960e052013-05-08 14:18:37 +0200271}
272
David Hildenbrand3f8e9172018-12-03 12:16:11 +0100273static ssize_t state_store(struct device *dev, struct device_attribute *attr,
274 const char *buf, size_t count)
Dave Hansen3947be12005-10-29 18:16:54 -0700275{
Gu Zheng7315f0c2013-08-28 14:38:27 +0800276 struct memory_block *mem = to_memory_block(dev);
Seth Jenningsfa2be402013-08-20 16:05:05 -0500277 int ret, online_type;
Dave Hansen3947be12005-10-29 18:16:54 -0700278
Rafael J. Wysocki5e33bc42013-08-28 21:41:01 +0200279 ret = lock_device_hotplug_sysfs();
280 if (ret)
281 return ret;
Rafael J. Wysocki4960e052013-05-08 14:18:37 +0200282
Tang Chen1f6a6cc2014-08-06 16:05:11 -0700283 if (sysfs_streq(buf, "online_kernel"))
Tang Chen4f7c6b42014-08-06 16:05:13 -0700284 online_type = MMOP_ONLINE_KERNEL;
Tang Chen1f6a6cc2014-08-06 16:05:11 -0700285 else if (sysfs_streq(buf, "online_movable"))
Tang Chen4f7c6b42014-08-06 16:05:13 -0700286 online_type = MMOP_ONLINE_MOVABLE;
Tang Chen1f6a6cc2014-08-06 16:05:11 -0700287 else if (sysfs_streq(buf, "online"))
Tang Chen4f7c6b42014-08-06 16:05:13 -0700288 online_type = MMOP_ONLINE_KEEP;
Tang Chen1f6a6cc2014-08-06 16:05:11 -0700289 else if (sysfs_streq(buf, "offline"))
Tang Chen4f7c6b42014-08-06 16:05:13 -0700290 online_type = MMOP_OFFLINE;
Yasuaki Ishimatsua37f8632013-10-11 15:36:25 +0900291 else {
292 ret = -EINVAL;
293 goto err;
294 }
Seth Jenningsfa2be402013-08-20 16:05:05 -0500295
296 switch (online_type) {
Tang Chen4f7c6b42014-08-06 16:05:13 -0700297 case MMOP_ONLINE_KERNEL:
298 case MMOP_ONLINE_MOVABLE:
299 case MMOP_ONLINE_KEEP:
David Hildenbrand381eab42018-10-30 15:10:29 -0700300 /* mem->online_type is protected by device_hotplug_lock */
Seth Jenningsfa2be402013-08-20 16:05:05 -0500301 mem->online_type = online_type;
302 ret = device_online(&mem->dev);
303 break;
Tang Chen4f7c6b42014-08-06 16:05:13 -0700304 case MMOP_OFFLINE:
Seth Jenningsfa2be402013-08-20 16:05:05 -0500305 ret = device_offline(&mem->dev);
306 break;
307 default:
308 ret = -EINVAL; /* should never happen */
Rafael J. Wysocki4960e052013-05-08 14:18:37 +0200309 }
Rafael J. Wysocki4960e052013-05-08 14:18:37 +0200310
Yasuaki Ishimatsua37f8632013-10-11 15:36:25 +0900311err:
Rafael J. Wysocki4960e052013-05-08 14:18:37 +0200312 unlock_device_hotplug();
Nathan Fontenot0c2c99b2011-01-20 10:43:34 -0600313
Reza Arbabd66ba152016-10-07 17:00:15 -0700314 if (ret < 0)
Dave Hansen3947be12005-10-29 18:16:54 -0700315 return ret;
Reza Arbabd66ba152016-10-07 17:00:15 -0700316 if (ret)
317 return -EINVAL;
318
Dave Hansen3947be12005-10-29 18:16:54 -0700319 return count;
320}
321
322/*
323 * phys_device is a bad name for this. What I really want
324 * is a way to differentiate between memory ranges that
325 * are part of physical devices that constitute
326 * a complete removable unit or fru.
327 * i.e. do these ranges belong to the same physical device,
328 * s.t. if I offline all of these sections I can then
329 * remove the physical device?
330 */
David Hildenbrand3f8e9172018-12-03 12:16:11 +0100331static ssize_t phys_device_show(struct device *dev,
Kay Sievers10fbcf42011-12-21 14:48:43 -0800332 struct device_attribute *attr, char *buf)
Dave Hansen3947be12005-10-29 18:16:54 -0700333{
Gu Zheng7315f0c2013-08-28 14:38:27 +0800334 struct memory_block *mem = to_memory_block(dev);
Dave Hansen3947be12005-10-29 18:16:54 -0700335 return sprintf(buf, "%d\n", mem->phys_device);
336}
337
Zhang Zhened2f2402014-10-09 15:26:31 -0700338#ifdef CONFIG_MEMORY_HOTREMOVE
Michal Hockoe5e68932017-09-06 16:19:37 -0700339static void print_allowed_zone(char *buf, int nid, unsigned long start_pfn,
340 unsigned long nr_pages, int online_type,
341 struct zone *default_zone)
342{
343 struct zone *zone;
344
Michal Hockoe5e68932017-09-06 16:19:37 -0700345 zone = zone_for_pfn_range(online_type, nid, start_pfn, nr_pages);
346 if (zone != default_zone) {
347 strcat(buf, " ");
348 strcat(buf, zone->name);
349 }
350}
351
David Hildenbrand3f8e9172018-12-03 12:16:11 +0100352static ssize_t valid_zones_show(struct device *dev,
Zhang Zhened2f2402014-10-09 15:26:31 -0700353 struct device_attribute *attr, char *buf)
354{
355 struct memory_block *mem = to_memory_block(dev);
Michal Hockof1dd2cd2017-07-06 15:38:11 -0700356 unsigned long start_pfn = section_nr_to_pfn(mem->start_section_nr);
Zhang Zhened2f2402014-10-09 15:26:31 -0700357 unsigned long nr_pages = PAGES_PER_SECTION * sections_per_block;
Michal Hockoe5e68932017-09-06 16:19:37 -0700358 struct zone *default_zone;
Michal Hockof1dd2cd2017-07-06 15:38:11 -0700359 int nid;
Zhang Zhened2f2402014-10-09 15:26:31 -0700360
Michal Hockof1dd2cd2017-07-06 15:38:11 -0700361 /*
Michal Hockof1dd2cd2017-07-06 15:38:11 -0700362 * Check the existing zone. Make sure that we do that only on the
363 * online nodes otherwise the page_zone is not reliable
364 */
365 if (mem->state == MEM_ONLINE) {
Mikhail Zaslonko4e8346d2018-09-04 15:46:09 -0700366 /*
367 * The block contains more than one zone can not be offlined.
368 * This can happen e.g. for ZONE_DMA and ZONE_DMA32
369 */
David Hildenbrand92917992020-02-03 17:34:26 -0800370 default_zone = test_pages_in_a_zone(start_pfn,
371 start_pfn + nr_pages);
372 if (!default_zone)
Mikhail Zaslonko4e8346d2018-09-04 15:46:09 -0700373 return sprintf(buf, "none\n");
David Hildenbrand92917992020-02-03 17:34:26 -0800374 strcat(buf, default_zone->name);
Michal Hockof1dd2cd2017-07-06 15:38:11 -0700375 goto out;
Zhang Zhened2f2402014-10-09 15:26:31 -0700376 }
377
Mikhail Zaslonko4e8346d2018-09-04 15:46:09 -0700378 nid = mem->nid;
Michal Hockoe5e68932017-09-06 16:19:37 -0700379 default_zone = zone_for_pfn_range(MMOP_ONLINE_KEEP, nid, start_pfn, nr_pages);
380 strcat(buf, default_zone->name);
Zhang Zhened2f2402014-10-09 15:26:31 -0700381
Michal Hockoe5e68932017-09-06 16:19:37 -0700382 print_allowed_zone(buf, nid, start_pfn, nr_pages, MMOP_ONLINE_KERNEL,
383 default_zone);
384 print_allowed_zone(buf, nid, start_pfn, nr_pages, MMOP_ONLINE_MOVABLE,
385 default_zone);
Michal Hockof1dd2cd2017-07-06 15:38:11 -0700386out:
Reza Arbaba371d9f2016-07-26 15:22:27 -0700387 strcat(buf, "\n");
388
389 return strlen(buf);
Zhang Zhened2f2402014-10-09 15:26:31 -0700390}
David Hildenbrand3f8e9172018-12-03 12:16:11 +0100391static DEVICE_ATTR_RO(valid_zones);
Zhang Zhened2f2402014-10-09 15:26:31 -0700392#endif
393
David Hildenbrand3f8e9172018-12-03 12:16:11 +0100394static DEVICE_ATTR_RO(phys_index);
395static DEVICE_ATTR_RW(state);
396static DEVICE_ATTR_RO(phys_device);
397static DEVICE_ATTR_RO(removable);
Dave Hansen3947be12005-10-29 18:16:54 -0700398
Dave Hansen3947be12005-10-29 18:16:54 -0700399/*
David Hildenbrandf915fb72019-09-23 15:35:43 -0700400 * Show the memory block size (shared by all memory blocks).
Dave Hansen3947be12005-10-29 18:16:54 -0700401 */
David Hildenbrand3f8e9172018-12-03 12:16:11 +0100402static ssize_t block_size_bytes_show(struct device *dev,
403 struct device_attribute *attr, char *buf)
Dave Hansen3947be12005-10-29 18:16:54 -0700404{
David Hildenbrand902ce63b2019-09-23 15:35:46 -0700405 return sprintf(buf, "%lx\n", memory_block_size_bytes());
Dave Hansen3947be12005-10-29 18:16:54 -0700406}
407
David Hildenbrand3f8e9172018-12-03 12:16:11 +0100408static DEVICE_ATTR_RO(block_size_bytes);
Dave Hansen3947be12005-10-29 18:16:54 -0700409
Dave Hansen3947be12005-10-29 18:16:54 -0700410/*
Vitaly Kuznetsov31bc3852016-03-15 14:56:48 -0700411 * Memory auto online policy.
412 */
413
David Hildenbrand3f8e9172018-12-03 12:16:11 +0100414static ssize_t auto_online_blocks_show(struct device *dev,
415 struct device_attribute *attr, char *buf)
Vitaly Kuznetsov31bc3852016-03-15 14:56:48 -0700416{
417 if (memhp_auto_online)
418 return sprintf(buf, "online\n");
419 else
420 return sprintf(buf, "offline\n");
421}
422
David Hildenbrand3f8e9172018-12-03 12:16:11 +0100423static ssize_t auto_online_blocks_store(struct device *dev,
424 struct device_attribute *attr,
425 const char *buf, size_t count)
Vitaly Kuznetsov31bc3852016-03-15 14:56:48 -0700426{
427 if (sysfs_streq(buf, "online"))
428 memhp_auto_online = true;
429 else if (sysfs_streq(buf, "offline"))
430 memhp_auto_online = false;
431 else
432 return -EINVAL;
433
434 return count;
435}
436
David Hildenbrand3f8e9172018-12-03 12:16:11 +0100437static DEVICE_ATTR_RW(auto_online_blocks);
Vitaly Kuznetsov31bc3852016-03-15 14:56:48 -0700438
439/*
Dave Hansen3947be12005-10-29 18:16:54 -0700440 * Some architectures will have custom drivers to do this, and
441 * will not need to do it from userspace. The fake hot-add code
442 * as well as ppc64 will do all of their discovery in userspace
443 * and will require this interface.
444 */
445#ifdef CONFIG_ARCH_MEMORY_PROBE
David Hildenbrand3f8e9172018-12-03 12:16:11 +0100446static ssize_t probe_store(struct device *dev, struct device_attribute *attr,
447 const char *buf, size_t count)
Dave Hansen3947be12005-10-29 18:16:54 -0700448{
449 u64 phys_addr;
John Allencb5490a2016-01-14 15:22:16 -0800450 int nid, ret;
Anton Blanchard61b94fe2011-09-15 06:26:15 +1000451 unsigned long pages_per_block = PAGES_PER_SECTION * sections_per_block;
Dave Hansen3947be12005-10-29 18:16:54 -0700452
Zhang Zhenb69deb22014-08-06 16:06:06 -0700453 ret = kstrtoull(buf, 0, &phys_addr);
454 if (ret)
455 return ret;
Dave Hansen3947be12005-10-29 18:16:54 -0700456
Anton Blanchard61b94fe2011-09-15 06:26:15 +1000457 if (phys_addr & ((pages_per_block << PAGE_SHIFT) - 1))
458 return -EINVAL;
459
David Hildenbrand8df1d0e2018-10-30 15:10:24 -0700460 ret = lock_device_hotplug_sysfs();
461 if (ret)
zhong jiang37803842019-04-18 17:50:16 -0700462 return ret;
David Hildenbrand8df1d0e2018-10-30 15:10:24 -0700463
John Allencb5490a2016-01-14 15:22:16 -0800464 nid = memory_add_physaddr_to_nid(phys_addr);
David Hildenbrand8df1d0e2018-10-30 15:10:24 -0700465 ret = __add_memory(nid, phys_addr,
466 MIN_MEMORY_BLOCK_SIZE * sections_per_block);
Nathan Fontenot6add7cd2011-01-31 10:55:23 -0600467
John Allencb5490a2016-01-14 15:22:16 -0800468 if (ret)
469 goto out;
Dave Hansen3947be12005-10-29 18:16:54 -0700470
Nikanth Karthikesan9f0af692011-03-24 11:46:18 +0530471 ret = count;
472out:
David Hildenbrand8df1d0e2018-10-30 15:10:24 -0700473 unlock_device_hotplug();
Nikanth Karthikesan9f0af692011-03-24 11:46:18 +0530474 return ret;
Dave Hansen3947be12005-10-29 18:16:54 -0700475}
Dave Hansen3947be12005-10-29 18:16:54 -0700476
David Hildenbrand3f8e9172018-12-03 12:16:11 +0100477static DEVICE_ATTR_WO(probe);
Dave Hansen3947be12005-10-29 18:16:54 -0700478#endif
479
Andi Kleenfacb6012009-12-16 12:20:00 +0100480#ifdef CONFIG_MEMORY_FAILURE
481/*
482 * Support for offlining pages of memory
483 */
484
485/* Soft offline a page */
David Hildenbrand3f8e9172018-12-03 12:16:11 +0100486static ssize_t soft_offline_page_store(struct device *dev,
487 struct device_attribute *attr,
488 const char *buf, size_t count)
Andi Kleenfacb6012009-12-16 12:20:00 +0100489{
490 int ret;
491 u64 pfn;
492 if (!capable(CAP_SYS_ADMIN))
493 return -EPERM;
Jingoo Han34da5e62013-07-26 13:10:22 +0900494 if (kstrtoull(buf, 0, &pfn) < 0)
Andi Kleenfacb6012009-12-16 12:20:00 +0100495 return -EINVAL;
496 pfn >>= PAGE_SHIFT;
Naoya Horiguchifeec24a2019-11-30 17:53:38 -0800497 ret = soft_offline_page(pfn, 0);
Andi Kleenfacb6012009-12-16 12:20:00 +0100498 return ret == 0 ? count : ret;
499}
500
501/* Forcibly offline a page, including killing processes. */
David Hildenbrand3f8e9172018-12-03 12:16:11 +0100502static ssize_t hard_offline_page_store(struct device *dev,
503 struct device_attribute *attr,
504 const char *buf, size_t count)
Andi Kleenfacb6012009-12-16 12:20:00 +0100505{
506 int ret;
507 u64 pfn;
508 if (!capable(CAP_SYS_ADMIN))
509 return -EPERM;
Jingoo Han34da5e62013-07-26 13:10:22 +0900510 if (kstrtoull(buf, 0, &pfn) < 0)
Andi Kleenfacb6012009-12-16 12:20:00 +0100511 return -EINVAL;
512 pfn >>= PAGE_SHIFT;
Eric W. Biederman83b57532017-07-09 18:14:01 -0500513 ret = memory_failure(pfn, 0);
Andi Kleenfacb6012009-12-16 12:20:00 +0100514 return ret ? ret : count;
515}
516
David Hildenbrand3f8e9172018-12-03 12:16:11 +0100517static DEVICE_ATTR_WO(soft_offline_page);
518static DEVICE_ATTR_WO(hard_offline_page);
Andi Kleenfacb6012009-12-16 12:20:00 +0100519#endif
520
Dave Hansen3947be12005-10-29 18:16:54 -0700521/*
522 * Note that phys_device is optional. It is here to allow for
523 * differentiation between which *physical* devices each
524 * section belongs to...
525 */
Heiko Carstensbc32df02010-03-15 00:35:03 -0400526int __weak arch_get_memory_phys_device(unsigned long start_pfn)
527{
528 return 0;
529}
Dave Hansen3947be12005-10-29 18:16:54 -0700530
David Hildenbranddd625282019-07-18 15:57:53 -0700531/* A reference for the returned memory block device is acquired. */
532static struct memory_block *find_memory_block_by_id(unsigned long block_id)
Robin Holt98383032010-09-29 14:00:55 -0500533{
Kay Sievers10fbcf42011-12-21 14:48:43 -0800534 struct device *dev;
Robin Holt98383032010-09-29 14:00:55 -0500535
David Hildenbranddd625282019-07-18 15:57:53 -0700536 dev = subsys_find_device_by_id(&memory_subsys, block_id, NULL);
537 return dev ? to_memory_block(dev) : NULL;
David Hildenbranddb051a02019-07-18 15:56:56 -0700538}
539
Dave Hansen3947be12005-10-29 18:16:54 -0700540/*
541 * For now, we have a linear search to go find the appropriate
542 * memory_block corresponding to a particular phys_index. If
543 * this gets to be a real problem, we can always use a radix
544 * tree or something here.
545 *
Kay Sievers10fbcf42011-12-21 14:48:43 -0800546 * This could be made generic for all device subsystems.
Dave Hansen3947be12005-10-29 18:16:54 -0700547 */
Gary Hadec04fc582009-01-06 14:39:14 -0800548struct memory_block *find_memory_block(struct mem_section *section)
Dave Hansen3947be12005-10-29 18:16:54 -0700549{
David Hildenbranddd625282019-07-18 15:57:53 -0700550 unsigned long block_id = base_memory_block_id(__section_nr(section));
551
552 return find_memory_block_by_id(block_id);
Dave Hansen3947be12005-10-29 18:16:54 -0700553}
554
Nathan Fontenot96b2c0f2013-06-04 14:42:28 -0500555static struct attribute *memory_memblk_attrs[] = {
556 &dev_attr_phys_index.attr,
Nathan Fontenot96b2c0f2013-06-04 14:42:28 -0500557 &dev_attr_state.attr,
558 &dev_attr_phys_device.attr,
559 &dev_attr_removable.attr,
Zhang Zhened2f2402014-10-09 15:26:31 -0700560#ifdef CONFIG_MEMORY_HOTREMOVE
561 &dev_attr_valid_zones.attr,
562#endif
Nathan Fontenot96b2c0f2013-06-04 14:42:28 -0500563 NULL
564};
565
566static struct attribute_group memory_memblk_attr_group = {
567 .attrs = memory_memblk_attrs,
568};
569
570static const struct attribute_group *memory_memblk_attr_groups[] = {
571 &memory_memblk_attr_group,
572 NULL,
573};
574
575/*
576 * register_memory - Setup a sysfs device for a memory block
577 */
578static
579int register_memory(struct memory_block *memory)
580{
Arvind Yadav085aa2d2018-04-26 21:12:09 +0530581 int ret;
582
Nathan Fontenot96b2c0f2013-06-04 14:42:28 -0500583 memory->dev.bus = &memory_subsys;
584 memory->dev.id = memory->start_section_nr / sections_per_block;
585 memory->dev.release = memory_block_release;
586 memory->dev.groups = memory_memblk_attr_groups;
Linus Torvaldsf991fae2013-07-03 14:35:40 -0700587 memory->dev.offline = memory->state == MEM_OFFLINE;
Nathan Fontenot96b2c0f2013-06-04 14:42:28 -0500588
Arvind Yadav085aa2d2018-04-26 21:12:09 +0530589 ret = device_register(&memory->dev);
590 if (ret)
591 put_device(&memory->dev);
592
593 return ret;
Nathan Fontenot96b2c0f2013-06-04 14:42:28 -0500594}
595
David Hildenbrand90ec010f2019-07-18 15:57:40 -0700596static int init_memory_block(struct memory_block **memory,
597 unsigned long block_id, unsigned long state)
Nathan Fontenote4619c82010-10-19 12:44:20 -0500598{
Nathan Fontenot0c2c99b2011-01-20 10:43:34 -0600599 struct memory_block *mem;
Nathan Fontenote4619c82010-10-19 12:44:20 -0500600 unsigned long start_pfn;
601 int ret = 0;
602
David Hildenbranddd625282019-07-18 15:57:53 -0700603 mem = find_memory_block_by_id(block_id);
David Hildenbranddb051a02019-07-18 15:56:56 -0700604 if (mem) {
605 put_device(&mem->dev);
606 return -EEXIST;
607 }
Nathan Fontenot0c2c99b2011-01-20 10:43:34 -0600608 mem = kzalloc(sizeof(*mem), GFP_KERNEL);
Nathan Fontenote4619c82010-10-19 12:44:20 -0500609 if (!mem)
610 return -ENOMEM;
611
David Hildenbrand18115822019-07-18 15:56:46 -0700612 mem->start_section_nr = block_id * sections_per_block;
Nathan Fontenote4619c82010-10-19 12:44:20 -0500613 mem->state = state;
Nathan Fontenotd3360162011-01-20 10:44:29 -0600614 start_pfn = section_nr_to_pfn(mem->start_section_nr);
Nathan Fontenote4619c82010-10-19 12:44:20 -0500615 mem->phys_device = arch_get_memory_phys_device(start_pfn);
David Hildenbrandd84f2f52019-09-23 15:35:40 -0700616 mem->nid = NUMA_NO_NODE;
Nathan Fontenote4619c82010-10-19 12:44:20 -0500617
Nathan Fontenot0c2c99b2011-01-20 10:43:34 -0600618 ret = register_memory(mem);
Nathan Fontenot0c2c99b2011-01-20 10:43:34 -0600619
620 *memory = mem;
621 return ret;
622}
623
David Hildenbrand2491f0a2019-07-18 15:57:37 -0700624static int add_memory_block(unsigned long base_section_nr)
Nathan Fontenot0c2c99b2011-01-20 10:43:34 -0600625{
David Hildenbrand68c3a6a2020-04-06 20:06:40 -0700626 int section_count = 0;
Seth Jenningscb5e39b2013-08-20 12:13:03 -0500627 struct memory_block *mem;
David Hildenbrand2491f0a2019-07-18 15:57:37 -0700628 unsigned long nr;
Nathan Fontenot0c2c99b2011-01-20 10:43:34 -0600629
David Hildenbrand2491f0a2019-07-18 15:57:37 -0700630 for (nr = base_section_nr; nr < base_section_nr + sections_per_block;
631 nr++)
632 if (present_section_nr(nr))
David Hildenbrand18115822019-07-18 15:56:46 -0700633 section_count++;
Nathan Fontenot0c2c99b2011-01-20 10:43:34 -0600634
Seth Jenningscb5e39b2013-08-20 12:13:03 -0500635 if (section_count == 0)
636 return 0;
David Hildenbrand68c3a6a2020-04-06 20:06:40 -0700637 return init_memory_block(&mem, base_memory_block_id(base_section_nr),
638 MEM_ONLINE);
Nathan Fontenote4619c82010-10-19 12:44:20 -0500639}
640
David Hildenbranddb051a02019-07-18 15:56:56 -0700641static void unregister_memory(struct memory_block *memory)
David Rientjes4edd7ce2013-04-29 15:08:22 -0700642{
David Hildenbranddb051a02019-07-18 15:56:56 -0700643 if (WARN_ON_ONCE(memory->dev.bus != &memory_subsys))
644 return;
David Rientjes4edd7ce2013-04-29 15:08:22 -0700645
David Hildenbrandcb7b3a32019-05-13 17:21:37 -0700646 /* drop the ref. we got via find_memory_block() */
Seth Jenningsdf2b7172013-08-20 12:12:59 -0500647 put_device(&memory->dev);
David Rientjes4edd7ce2013-04-29 15:08:22 -0700648 device_unregister(&memory->dev);
649}
650
David Hildenbranddb051a02019-07-18 15:56:56 -0700651/*
652 * Create memory block devices for the given memory area. Start and size
653 * have to be aligned to memory block granularity. Memory block devices
654 * will be initialized as offline.
David Hildenbrand848e19a2019-11-30 17:54:14 -0800655 *
656 * Called under device_hotplug_lock.
David Hildenbranddb051a02019-07-18 15:56:56 -0700657 */
658int create_memory_block_devices(unsigned long start, unsigned long size)
659{
David Hildenbrand90ec010f2019-07-18 15:57:40 -0700660 const unsigned long start_block_id = pfn_to_block_id(PFN_DOWN(start));
661 unsigned long end_block_id = pfn_to_block_id(PFN_DOWN(start + size));
David Hildenbranddb051a02019-07-18 15:56:56 -0700662 struct memory_block *mem;
663 unsigned long block_id;
664 int ret = 0;
665
666 if (WARN_ON_ONCE(!IS_ALIGNED(start, memory_block_size_bytes()) ||
667 !IS_ALIGNED(size, memory_block_size_bytes())))
668 return -EINVAL;
669
David Hildenbranddb051a02019-07-18 15:56:56 -0700670 for (block_id = start_block_id; block_id != end_block_id; block_id++) {
671 ret = init_memory_block(&mem, block_id, MEM_OFFLINE);
672 if (ret)
673 break;
David Hildenbranddb051a02019-07-18 15:56:56 -0700674 }
675 if (ret) {
676 end_block_id = block_id;
677 for (block_id = start_block_id; block_id != end_block_id;
678 block_id++) {
David Hildenbranddd625282019-07-18 15:57:53 -0700679 mem = find_memory_block_by_id(block_id);
David Hildenbrand848e19a2019-11-30 17:54:14 -0800680 if (WARN_ON_ONCE(!mem))
681 continue;
David Hildenbranddb051a02019-07-18 15:56:56 -0700682 unregister_memory(mem);
683 }
684 }
David Hildenbranddb051a02019-07-18 15:56:56 -0700685 return ret;
686}
687
David Hildenbrand4c4b7f92019-07-18 15:57:06 -0700688/*
689 * Remove memory block devices for the given memory area. Start and size
690 * have to be aligned to memory block granularity. Memory block devices
691 * have to be offline.
David Hildenbrand848e19a2019-11-30 17:54:14 -0800692 *
693 * Called under device_hotplug_lock.
David Hildenbrand4c4b7f92019-07-18 15:57:06 -0700694 */
695void remove_memory_block_devices(unsigned long start, unsigned long size)
Dave Hansen3947be12005-10-29 18:16:54 -0700696{
David Hildenbrand90ec010f2019-07-18 15:57:40 -0700697 const unsigned long start_block_id = pfn_to_block_id(PFN_DOWN(start));
698 const unsigned long end_block_id = pfn_to_block_id(PFN_DOWN(start + size));
Dave Hansen3947be12005-10-29 18:16:54 -0700699 struct memory_block *mem;
David Hildenbrand90ec010f2019-07-18 15:57:40 -0700700 unsigned long block_id;
Dave Hansen3947be12005-10-29 18:16:54 -0700701
David Hildenbrand4c4b7f92019-07-18 15:57:06 -0700702 if (WARN_ON_ONCE(!IS_ALIGNED(start, memory_block_size_bytes()) ||
703 !IS_ALIGNED(size, memory_block_size_bytes())))
David Hildenbrandcb7b3a32019-05-13 17:21:37 -0700704 return;
705
David Hildenbrand4c4b7f92019-07-18 15:57:06 -0700706 for (block_id = start_block_id; block_id != end_block_id; block_id++) {
David Hildenbranddd625282019-07-18 15:57:53 -0700707 mem = find_memory_block_by_id(block_id);
David Hildenbrand4c4b7f92019-07-18 15:57:06 -0700708 if (WARN_ON_ONCE(!mem))
709 continue;
David Hildenbrand4c4b7f92019-07-18 15:57:06 -0700710 unregister_memory_block_under_nodes(mem);
Nathan Fontenot0c2c99b2011-01-20 10:43:34 -0600711 unregister_memory(mem);
David Hildenbrand4c4b7f92019-07-18 15:57:06 -0700712 }
Dave Hansen3947be12005-10-29 18:16:54 -0700713}
714
Yasuaki Ishimatsu6677e3e2013-02-22 16:32:52 -0800715/* return true if the memory block is offlined, otherwise, return false */
716bool is_memblock_offlined(struct memory_block *mem)
717{
718 return mem->state == MEM_OFFLINE;
719}
720
Nathan Fontenot96b2c0f2013-06-04 14:42:28 -0500721static struct attribute *memory_root_attrs[] = {
722#ifdef CONFIG_ARCH_MEMORY_PROBE
723 &dev_attr_probe.attr,
724#endif
725
726#ifdef CONFIG_MEMORY_FAILURE
727 &dev_attr_soft_offline_page.attr,
728 &dev_attr_hard_offline_page.attr,
729#endif
730
731 &dev_attr_block_size_bytes.attr,
Vitaly Kuznetsov31bc3852016-03-15 14:56:48 -0700732 &dev_attr_auto_online_blocks.attr,
Nathan Fontenot96b2c0f2013-06-04 14:42:28 -0500733 NULL
734};
735
736static struct attribute_group memory_root_attr_group = {
737 .attrs = memory_root_attrs,
738};
739
740static const struct attribute_group *memory_root_attr_groups[] = {
741 &memory_root_attr_group,
742 NULL,
743};
744
Wen Congyange90bdb72012-10-08 16:34:01 -0700745/*
David Hildenbrand848e19a2019-11-30 17:54:14 -0800746 * Initialize the sysfs support for memory devices. At the time this function
747 * is called, we cannot have concurrent creation/deletion of memory block
748 * devices, the device_hotplug_lock is not needed.
Dave Hansen3947be12005-10-29 18:16:54 -0700749 */
David Hildenbrand902ce63b2019-09-23 15:35:46 -0700750void __init memory_dev_init(void)
Dave Hansen3947be12005-10-29 18:16:54 -0700751{
Dave Hansen3947be12005-10-29 18:16:54 -0700752 int ret;
David Hildenbrand2491f0a2019-07-18 15:57:37 -0700753 unsigned long block_sz, nr;
Dave Hansen3947be12005-10-29 18:16:54 -0700754
David Hildenbrand902ce63b2019-09-23 15:35:46 -0700755 /* Validate the configured memory block size */
756 block_sz = memory_block_size_bytes();
757 if (!is_power_of_2(block_sz) || block_sz < MIN_MEMORY_BLOCK_SIZE)
758 panic("Memory block size not suitable: 0x%lx\n", block_sz);
759 sections_per_block = block_sz / MIN_MEMORY_BLOCK_SIZE;
760
Nathan Fontenot96b2c0f2013-06-04 14:42:28 -0500761 ret = subsys_system_register(&memory_subsys, memory_root_attr_groups);
Andrew Morton28ec24e2006-12-06 20:37:29 -0800762 if (ret)
David Hildenbrand848e19a2019-11-30 17:54:14 -0800763 panic("%s() failed to register subsystem: %d\n", __func__, ret);
Dave Hansen3947be12005-10-29 18:16:54 -0700764
765 /*
766 * Create entries for memory sections that were found
767 * during boot and have been initialized
768 */
David Hildenbrand2491f0a2019-07-18 15:57:37 -0700769 for (nr = 0; nr <= __highest_present_section_nr;
770 nr += sections_per_block) {
David Hildenbrand848e19a2019-11-30 17:54:14 -0800771 ret = add_memory_block(nr);
772 if (ret)
773 panic("%s() failed to add memory block: %d\n", __func__,
774 ret);
Dave Hansen3947be12005-10-29 18:16:54 -0700775 }
Dave Hansen3947be12005-10-29 18:16:54 -0700776}
David Hildenbrandea884642019-07-18 15:57:50 -0700777
778/**
779 * walk_memory_blocks - walk through all present memory blocks overlapped
780 * by the range [start, start + size)
781 *
782 * @start: start address of the memory range
783 * @size: size of the memory range
784 * @arg: argument passed to func
785 * @func: callback for each memory section walked
786 *
787 * This function walks through all present memory blocks overlapped by the
788 * range [start, start + size), calling func on each memory block.
789 *
790 * In case func() returns an error, walking is aborted and the error is
791 * returned.
792 */
793int walk_memory_blocks(unsigned long start, unsigned long size,
794 void *arg, walk_memory_blocks_func_t func)
795{
796 const unsigned long start_block_id = phys_to_block_id(start);
797 const unsigned long end_block_id = phys_to_block_id(start + size - 1);
798 struct memory_block *mem;
799 unsigned long block_id;
800 int ret = 0;
801
David Hildenbranddd625282019-07-18 15:57:53 -0700802 if (!size)
803 return 0;
804
David Hildenbrandea884642019-07-18 15:57:50 -0700805 for (block_id = start_block_id; block_id <= end_block_id; block_id++) {
David Hildenbranddd625282019-07-18 15:57:53 -0700806 mem = find_memory_block_by_id(block_id);
David Hildenbrandea884642019-07-18 15:57:50 -0700807 if (!mem)
808 continue;
809
810 ret = func(mem, arg);
811 put_device(&mem->dev);
812 if (ret)
813 break;
814 }
815 return ret;
816}
David Hildenbrand2c91f8f2019-11-15 17:34:57 -0800817
818struct for_each_memory_block_cb_data {
819 walk_memory_blocks_func_t func;
820 void *arg;
821};
822
823static int for_each_memory_block_cb(struct device *dev, void *data)
824{
825 struct memory_block *mem = to_memory_block(dev);
826 struct for_each_memory_block_cb_data *cb_data = data;
827
828 return cb_data->func(mem, cb_data->arg);
829}
830
831/**
832 * for_each_memory_block - walk through all present memory blocks
833 *
834 * @arg: argument passed to func
835 * @func: callback for each memory block walked
836 *
837 * This function walks through all present memory blocks, calling func on
838 * each memory block.
839 *
840 * In case func() returns an error, walking is aborted and the error is
841 * returned.
842 */
843int for_each_memory_block(void *arg, walk_memory_blocks_func_t func)
844{
845 struct for_each_memory_block_cb_data cb_data = {
846 .func = func,
847 .arg = arg,
848 };
849
850 return bus_for_each_dev(&memory_subsys, NULL, &cb_data,
851 for_each_memory_block_cb);
852}