Blame view

drivers/base/memory.c 19.8 KB
3947be196   Dave Hansen   [PATCH] memory ho...
1
  /*
10fbcf4c6   Kay Sievers   convert 'memory' ...
2
   * Memory subsystem support
3947be196   Dave Hansen   [PATCH] memory ho...
3
4
5
6
7
8
9
10
11
   *
   * Written by Matt Tolentino <matthew.e.tolentino@intel.com>
   *            Dave Hansen <haveblue@us.ibm.com>
   *
   * This file provides the necessary infrastructure to represent
   * a SPARSEMEM-memory-model system's physical memory in /sysfs.
   * All arch-independent code that assumes MEMORY_HOTPLUG requires
   * SPARSEMEM should be contained here, or in mm/memory_hotplug.c.
   */
3947be196   Dave Hansen   [PATCH] memory ho...
12
13
  #include <linux/module.h>
  #include <linux/init.h>
3947be196   Dave Hansen   [PATCH] memory ho...
14
  #include <linux/topology.h>
c59ede7b7   Randy.Dunlap   [PATCH] move capa...
15
  #include <linux/capability.h>
3947be196   Dave Hansen   [PATCH] memory ho...
16
17
  #include <linux/device.h>
  #include <linux/memory.h>
3947be196   Dave Hansen   [PATCH] memory ho...
18
19
  #include <linux/memory_hotplug.h>
  #include <linux/mm.h>
da19cbcf7   Daniel Walker   driver core: memo...
20
  #include <linux/mutex.h>
9f1b16a51   Shaohua Li   memory_probe: fix...
21
  #include <linux/stat.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
22
  #include <linux/slab.h>
9f1b16a51   Shaohua Li   memory_probe: fix...
23

60063497a   Arun Sharma   atomic: use <linu...
24
  #include <linux/atomic.h>
3947be196   Dave Hansen   [PATCH] memory ho...
25
  #include <asm/uaccess.h>
2938ffbd4   Nathan Fontenot   Driver core: Add ...
26
  static DEFINE_MUTEX(mem_sysfs_mutex);
3947be196   Dave Hansen   [PATCH] memory ho...
27
  #define MEMORY_CLASS_NAME	"memory"
0c2c99b1b   Nathan Fontenot   memory hotplug: A...
28

7315f0ccf   Gu Zheng   drivers/base/memo...
29
  #define to_memory_block(dev) container_of(dev, struct memory_block, dev)
0c2c99b1b   Nathan Fontenot   memory hotplug: A...
30
31
32
33
34
35
  static int sections_per_block;
  
  static inline int base_memory_block_id(int section_nr)
  {
  	return section_nr / sections_per_block;
  }
3947be196   Dave Hansen   [PATCH] memory ho...
36

4960e05e2   Rafael J. Wysocki   Driver core: Intr...
37
38
  static int memory_subsys_online(struct device *dev);
  static int memory_subsys_offline(struct device *dev);
10fbcf4c6   Kay Sievers   convert 'memory' ...
39
  static struct bus_type memory_subsys = {
af5ca3f4e   Kay Sievers   Driver core: chan...
40
  	.name = MEMORY_CLASS_NAME,
10fbcf4c6   Kay Sievers   convert 'memory' ...
41
  	.dev_name = MEMORY_CLASS_NAME,
4960e05e2   Rafael J. Wysocki   Driver core: Intr...
42
43
  	.online = memory_subsys_online,
  	.offline = memory_subsys_offline,
3947be196   Dave Hansen   [PATCH] memory ho...
44
  };
e041c6834   Alan Stern   [PATCH] Notifier ...
45
  static BLOCKING_NOTIFIER_HEAD(memory_chain);
3947be196   Dave Hansen   [PATCH] memory ho...
46

98a38ebdd   Andy Whitcroft   [PATCH] memhotplu...
47
  int register_memory_notifier(struct notifier_block *nb)
3947be196   Dave Hansen   [PATCH] memory ho...
48
  {
2aeebca2f   Ioana Ciornei   drivers: base: me...
49
  	return blocking_notifier_chain_register(&memory_chain, nb);
3947be196   Dave Hansen   [PATCH] memory ho...
50
  }
3c82c30cd   Hannes Hering   memory: Introduce...
51
  EXPORT_SYMBOL(register_memory_notifier);
3947be196   Dave Hansen   [PATCH] memory ho...
52

98a38ebdd   Andy Whitcroft   [PATCH] memhotplu...
53
  void unregister_memory_notifier(struct notifier_block *nb)
3947be196   Dave Hansen   [PATCH] memory ho...
54
  {
2aeebca2f   Ioana Ciornei   drivers: base: me...
55
  	blocking_notifier_chain_unregister(&memory_chain, nb);
3947be196   Dave Hansen   [PATCH] memory ho...
56
  }
3c82c30cd   Hannes Hering   memory: Introduce...
57
  EXPORT_SYMBOL(unregister_memory_notifier);
3947be196   Dave Hansen   [PATCH] memory ho...
58

925cc71e5   Robert Jennings   mm: Add notifier ...
59
60
61
62
63
64
65
66
67
68
69
70
71
  static ATOMIC_NOTIFIER_HEAD(memory_isolate_chain);
  
  int register_memory_isolate_notifier(struct notifier_block *nb)
  {
  	return atomic_notifier_chain_register(&memory_isolate_chain, nb);
  }
  EXPORT_SYMBOL(register_memory_isolate_notifier);
  
  void unregister_memory_isolate_notifier(struct notifier_block *nb)
  {
  	atomic_notifier_chain_unregister(&memory_isolate_chain, nb);
  }
  EXPORT_SYMBOL(unregister_memory_isolate_notifier);
fa7194eb9   Yasuaki Ishimatsu   memory hotplug: s...
72
73
  static void memory_block_release(struct device *dev)
  {
7315f0ccf   Gu Zheng   drivers/base/memo...
74
  	struct memory_block *mem = to_memory_block(dev);
fa7194eb9   Yasuaki Ishimatsu   memory hotplug: s...
75
76
77
  
  	kfree(mem);
  }
0c2c99b1b   Nathan Fontenot   memory hotplug: A...
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
  unsigned long __weak memory_block_size_bytes(void)
  {
  	return MIN_MEMORY_BLOCK_SIZE;
  }
  
  static unsigned long get_memory_block_size(void)
  {
  	unsigned long block_sz;
  
  	block_sz = memory_block_size_bytes();
  
  	/* Validate blk_sz is a power of 2 and not less than section size */
  	if ((block_sz & (block_sz - 1)) || (block_sz < MIN_MEMORY_BLOCK_SIZE)) {
  		WARN_ON(1);
  		block_sz = MIN_MEMORY_BLOCK_SIZE;
  	}
  
  	return block_sz;
  }
3947be196   Dave Hansen   [PATCH] memory ho...
97
98
99
100
  /*
   * use this as the physical section index that this memsection
   * uses.
   */
10fbcf4c6   Kay Sievers   convert 'memory' ...
101
102
  static ssize_t show_mem_start_phys_index(struct device *dev,
  			struct device_attribute *attr, char *buf)
3947be196   Dave Hansen   [PATCH] memory ho...
103
  {
7315f0ccf   Gu Zheng   drivers/base/memo...
104
  	struct memory_block *mem = to_memory_block(dev);
d33601644   Nathan Fontenot   memory hotplug: U...
105
106
107
108
109
110
  	unsigned long phys_index;
  
  	phys_index = mem->start_section_nr / sections_per_block;
  	return sprintf(buf, "%08lx
  ", phys_index);
  }
3947be196   Dave Hansen   [PATCH] memory ho...
111
  /*
5c755e9fd   Badari Pulavarty   memory-hotplug: a...
112
113
   * Show whether the section of memory is likely to be hot-removable
   */
10fbcf4c6   Kay Sievers   convert 'memory' ...
114
115
  static ssize_t show_mem_removable(struct device *dev,
  			struct device_attribute *attr, char *buf)
5c755e9fd   Badari Pulavarty   memory-hotplug: a...
116
  {
0c2c99b1b   Nathan Fontenot   memory hotplug: A...
117
118
  	unsigned long i, pfn;
  	int ret = 1;
7315f0ccf   Gu Zheng   drivers/base/memo...
119
  	struct memory_block *mem = to_memory_block(dev);
5c755e9fd   Badari Pulavarty   memory-hotplug: a...
120

0c2c99b1b   Nathan Fontenot   memory hotplug: A...
121
  	for (i = 0; i < sections_per_block; i++) {
21ea9f5ac   Russ Anderson   drivers/base/memo...
122
123
  		if (!present_section_nr(mem->start_section_nr + i))
  			continue;
d33601644   Nathan Fontenot   memory hotplug: U...
124
  		pfn = section_nr_to_pfn(mem->start_section_nr + i);
0c2c99b1b   Nathan Fontenot   memory hotplug: A...
125
126
  		ret &= is_mem_section_removable(pfn, PAGES_PER_SECTION);
  	}
5c755e9fd   Badari Pulavarty   memory-hotplug: a...
127
128
129
130
131
  	return sprintf(buf, "%d
  ", ret);
  }
  
  /*
3947be196   Dave Hansen   [PATCH] memory ho...
132
133
   * online, offline, going offline, etc.
   */
10fbcf4c6   Kay Sievers   convert 'memory' ...
134
135
  static ssize_t show_mem_state(struct device *dev,
  			struct device_attribute *attr, char *buf)
3947be196   Dave Hansen   [PATCH] memory ho...
136
  {
7315f0ccf   Gu Zheng   drivers/base/memo...
137
  	struct memory_block *mem = to_memory_block(dev);
3947be196   Dave Hansen   [PATCH] memory ho...
138
139
140
141
142
143
144
  	ssize_t len = 0;
  
  	/*
  	 * We can probably put these states in a nice little array
  	 * so that they're not open-coded
  	 */
  	switch (mem->state) {
3d3af6afa   Ioana Ciornei   drivers: base: me...
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
  	case MEM_ONLINE:
  		len = sprintf(buf, "online
  ");
  		break;
  	case MEM_OFFLINE:
  		len = sprintf(buf, "offline
  ");
  		break;
  	case MEM_GOING_OFFLINE:
  		len = sprintf(buf, "going-offline
  ");
  		break;
  	default:
  		len = sprintf(buf, "ERROR-UNKNOWN-%ld
  ",
  				mem->state);
  		WARN_ON(1);
  		break;
3947be196   Dave Hansen   [PATCH] memory ho...
163
164
165
166
  	}
  
  	return len;
  }
7b78d335a   Yasunori Goto   memory hotplug: r...
167
  int memory_notify(unsigned long val, void *v)
3947be196   Dave Hansen   [PATCH] memory ho...
168
  {
e041c6834   Alan Stern   [PATCH] Notifier ...
169
  	return blocking_notifier_call_chain(&memory_chain, val, v);
3947be196   Dave Hansen   [PATCH] memory ho...
170
  }
925cc71e5   Robert Jennings   mm: Add notifier ...
171
172
173
174
  int memory_isolate_notify(unsigned long val, void *v)
  {
  	return atomic_notifier_call_chain(&memory_isolate_chain, val, v);
  }
3947be196   Dave Hansen   [PATCH] memory ho...
175
  /*
2bbcb8788   Mel Gorman   mm: memory hotplu...
176
177
178
   * The probe routines leave the pages reserved, just as the bootmem code does.
   * Make sure they're still that way.
   */
6056d619a   Tang Chen   mm: Remove unused...
179
  static bool pages_correctly_reserved(unsigned long start_pfn)
2bbcb8788   Mel Gorman   mm: memory hotplu...
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
  {
  	int i, j;
  	struct page *page;
  	unsigned long pfn = start_pfn;
  
  	/*
  	 * memmap between sections is not contiguous except with
  	 * SPARSEMEM_VMEMMAP. We lookup the page once per section
  	 * and assume memmap is contiguous within each section
  	 */
  	for (i = 0; i < sections_per_block; i++, pfn += PAGES_PER_SECTION) {
  		if (WARN_ON_ONCE(!pfn_valid(pfn)))
  			return false;
  		page = pfn_to_page(pfn);
  
  		for (j = 0; j < PAGES_PER_SECTION; j++) {
  			if (PageReserved(page + j))
  				continue;
  
  			printk(KERN_WARNING "section number %ld page number %d "
  				"not reserved, was it already online?
  ",
  				pfn_to_section_nr(pfn), j);
  
  			return false;
  		}
  	}
  
  	return true;
  }
  
  /*
3947be196   Dave Hansen   [PATCH] memory ho...
212
213
   * MEMORY_HOTPLUG depends on SPARSEMEM in mm/Kconfig, so it is
   * OK to have direct references to sparsemem variables in here.
30467e0b3   David Rientjes   mm, hotplug: fix ...
214
   * Must already be protected by mem_hotplug_begin().
3947be196   Dave Hansen   [PATCH] memory ho...
215
216
   */
  static int
511c2aba8   Lai Jiangshan   mm, memory-hotplu...
217
  memory_block_action(unsigned long phys_index, unsigned long action, int online_type)
3947be196   Dave Hansen   [PATCH] memory ho...
218
  {
a16cee10c   Wen Congyang   memory-hotplug: p...
219
  	unsigned long start_pfn;
5409d2cd8   Anton Blanchard   memory hotplug: S...
220
  	unsigned long nr_pages = PAGES_PER_SECTION * sections_per_block;
de0ed36a3   Greg Kroah-Hartman   Revert "memory ho...
221
  	struct page *first_page;
3947be196   Dave Hansen   [PATCH] memory ho...
222
  	int ret;
3947be196   Dave Hansen   [PATCH] memory ho...
223

19c07d5e0   Sheng Yong   memory hotplug: u...
224
  	start_pfn = section_nr_to_pfn(phys_index);
71fbd556a   Zhang Zhen   memory-hotplug: r...
225
  	first_page = pfn_to_page(start_pfn);
de0ed36a3   Greg Kroah-Hartman   Revert "memory ho...
226

3947be196   Dave Hansen   [PATCH] memory ho...
227
  	switch (action) {
3d3af6afa   Ioana Ciornei   drivers: base: me...
228
229
230
231
232
233
234
235
236
237
238
239
240
241
  	case MEM_ONLINE:
  		if (!pages_correctly_reserved(start_pfn))
  			return -EBUSY;
  
  		ret = online_pages(start_pfn, nr_pages, online_type);
  		break;
  	case MEM_OFFLINE:
  		ret = offline_pages(start_pfn, nr_pages);
  		break;
  	default:
  		WARN(1, KERN_WARNING "%s(%ld, %ld) unknown action: "
  		     "%ld
  ", __func__, phys_index, action, action);
  		ret = -EINVAL;
3947be196   Dave Hansen   [PATCH] memory ho...
242
  	}
3947be196   Dave Hansen   [PATCH] memory ho...
243
244
245
  
  	return ret;
  }
31bc3858e   Vitaly Kuznetsov   memory-hotplug: a...
246
  int memory_block_change_state(struct memory_block *mem,
fa2be40fe   Seth Jennings   drivers: base: us...
247
  		unsigned long to_state, unsigned long from_state_req)
3947be196   Dave Hansen   [PATCH] memory ho...
248
  {
de0ed36a3   Greg Kroah-Hartman   Revert "memory ho...
249
  	int ret = 0;
0c2c99b1b   Nathan Fontenot   memory hotplug: A...
250

4960e05e2   Rafael J. Wysocki   Driver core: Intr...
251
252
  	if (mem->state != from_state_req)
  		return -EINVAL;
3947be196   Dave Hansen   [PATCH] memory ho...
253

0c2c99b1b   Nathan Fontenot   memory hotplug: A...
254
255
  	if (to_state == MEM_OFFLINE)
  		mem->state = MEM_GOING_OFFLINE;
fa2be40fe   Seth Jennings   drivers: base: us...
256
257
  	ret = memory_block_action(mem->start_section_nr, to_state,
  				mem->online_type);
b2c064b25   Rafael J. Wysocki   Driver core / mem...
258
  	mem->state = ret ? from_state_req : to_state;
fa2be40fe   Seth Jennings   drivers: base: us...
259

4960e05e2   Rafael J. Wysocki   Driver core: Intr...
260
261
  	return ret;
  }
0c2c99b1b   Nathan Fontenot   memory hotplug: A...
262

fa2be40fe   Seth Jennings   drivers: base: us...
263
  /* The device lock serializes operations on memory_subsys_[online|offline] */
4960e05e2   Rafael J. Wysocki   Driver core: Intr...
264
265
  static int memory_subsys_online(struct device *dev)
  {
7315f0ccf   Gu Zheng   drivers/base/memo...
266
  	struct memory_block *mem = to_memory_block(dev);
4960e05e2   Rafael J. Wysocki   Driver core: Intr...
267
  	int ret;
3947be196   Dave Hansen   [PATCH] memory ho...
268

fa2be40fe   Seth Jennings   drivers: base: us...
269
270
  	if (mem->state == MEM_ONLINE)
  		return 0;
4960e05e2   Rafael J. Wysocki   Driver core: Intr...
271

fa2be40fe   Seth Jennings   drivers: base: us...
272
273
274
275
276
277
  	/*
  	 * If we are called from store_mem_state(), online_type will be
  	 * set >= 0 Otherwise we were called from the device online
  	 * attribute and need to set the online_type.
  	 */
  	if (mem->online_type < 0)
4f7c6b49c   Tang Chen   mem-hotplug: intr...
278
  		mem->online_type = MMOP_ONLINE_KEEP;
4960e05e2   Rafael J. Wysocki   Driver core: Intr...
279

30467e0b3   David Rientjes   mm, hotplug: fix ...
280
  	/* Already under protection of mem_hotplug_begin() */
fa2be40fe   Seth Jennings   drivers: base: us...
281
  	ret = memory_block_change_state(mem, MEM_ONLINE, MEM_OFFLINE);
4960e05e2   Rafael J. Wysocki   Driver core: Intr...
282

fa2be40fe   Seth Jennings   drivers: base: us...
283
284
  	/* clear online_type */
  	mem->online_type = -1;
4960e05e2   Rafael J. Wysocki   Driver core: Intr...
285

4960e05e2   Rafael J. Wysocki   Driver core: Intr...
286
287
  	return ret;
  }
4960e05e2   Rafael J. Wysocki   Driver core: Intr...
288
  static int memory_subsys_offline(struct device *dev)
e90bdb7f5   Wen Congyang   memory-hotplug: u...
289
  {
7315f0ccf   Gu Zheng   drivers/base/memo...
290
  	struct memory_block *mem = to_memory_block(dev);
e90bdb7f5   Wen Congyang   memory-hotplug: u...
291

fa2be40fe   Seth Jennings   drivers: base: us...
292
293
  	if (mem->state == MEM_OFFLINE)
  		return 0;
e90bdb7f5   Wen Congyang   memory-hotplug: u...
294

26bbe7ef6   Seth Jennings   drivers/base/memo...
295
296
297
  	/* Can't offline block with non-present sections */
  	if (mem->section_count != sections_per_block)
  		return -EINVAL;
fa2be40fe   Seth Jennings   drivers: base: us...
298
  	return memory_block_change_state(mem, MEM_OFFLINE, MEM_ONLINE);
e90bdb7f5   Wen Congyang   memory-hotplug: u...
299
  }
4960e05e2   Rafael J. Wysocki   Driver core: Intr...
300

3947be196   Dave Hansen   [PATCH] memory ho...
301
  static ssize_t
10fbcf4c6   Kay Sievers   convert 'memory' ...
302
303
  store_mem_state(struct device *dev,
  		struct device_attribute *attr, const char *buf, size_t count)
3947be196   Dave Hansen   [PATCH] memory ho...
304
  {
7315f0ccf   Gu Zheng   drivers/base/memo...
305
  	struct memory_block *mem = to_memory_block(dev);
fa2be40fe   Seth Jennings   drivers: base: us...
306
  	int ret, online_type;
3947be196   Dave Hansen   [PATCH] memory ho...
307

5e33bc416   Rafael J. Wysocki   driver core / ACP...
308
309
310
  	ret = lock_device_hotplug_sysfs();
  	if (ret)
  		return ret;
4960e05e2   Rafael J. Wysocki   Driver core: Intr...
311

1f6a6cc82   Tang Chen   mem-hotplug: avoi...
312
  	if (sysfs_streq(buf, "online_kernel"))
4f7c6b49c   Tang Chen   mem-hotplug: intr...
313
  		online_type = MMOP_ONLINE_KERNEL;
1f6a6cc82   Tang Chen   mem-hotplug: avoi...
314
  	else if (sysfs_streq(buf, "online_movable"))
4f7c6b49c   Tang Chen   mem-hotplug: intr...
315
  		online_type = MMOP_ONLINE_MOVABLE;
1f6a6cc82   Tang Chen   mem-hotplug: avoi...
316
  	else if (sysfs_streq(buf, "online"))
4f7c6b49c   Tang Chen   mem-hotplug: intr...
317
  		online_type = MMOP_ONLINE_KEEP;
1f6a6cc82   Tang Chen   mem-hotplug: avoi...
318
  	else if (sysfs_streq(buf, "offline"))
4f7c6b49c   Tang Chen   mem-hotplug: intr...
319
  		online_type = MMOP_OFFLINE;
a37f86305   Yasuaki Ishimatsu   driver core: Rele...
320
321
322
323
  	else {
  		ret = -EINVAL;
  		goto err;
  	}
fa2be40fe   Seth Jennings   drivers: base: us...
324

30467e0b3   David Rientjes   mm, hotplug: fix ...
325
326
327
328
329
330
331
332
  	/*
  	 * Memory hotplug needs to hold mem_hotplug_begin() for probe to find
  	 * the correct memory block to online before doing device_online(dev),
  	 * which will take dev->mutex.  Take the lock early to prevent an
  	 * inversion, memory_subsys_online() callbacks will be implemented by
  	 * assuming it's already protected.
  	 */
  	mem_hotplug_begin();
fa2be40fe   Seth Jennings   drivers: base: us...
333
  	switch (online_type) {
4f7c6b49c   Tang Chen   mem-hotplug: intr...
334
335
336
  	case MMOP_ONLINE_KERNEL:
  	case MMOP_ONLINE_MOVABLE:
  	case MMOP_ONLINE_KEEP:
fa2be40fe   Seth Jennings   drivers: base: us...
337
338
339
  		mem->online_type = online_type;
  		ret = device_online(&mem->dev);
  		break;
4f7c6b49c   Tang Chen   mem-hotplug: intr...
340
  	case MMOP_OFFLINE:
fa2be40fe   Seth Jennings   drivers: base: us...
341
342
343
344
  		ret = device_offline(&mem->dev);
  		break;
  	default:
  		ret = -EINVAL; /* should never happen */
4960e05e2   Rafael J. Wysocki   Driver core: Intr...
345
  	}
4960e05e2   Rafael J. Wysocki   Driver core: Intr...
346

30467e0b3   David Rientjes   mm, hotplug: fix ...
347
  	mem_hotplug_done();
a37f86305   Yasuaki Ishimatsu   driver core: Rele...
348
  err:
4960e05e2   Rafael J. Wysocki   Driver core: Intr...
349
  	unlock_device_hotplug();
0c2c99b1b   Nathan Fontenot   memory hotplug: A...
350

d66ba15bd   Reza Arbab   memory-hotplug: f...
351
  	if (ret < 0)
3947be196   Dave Hansen   [PATCH] memory ho...
352
  		return ret;
d66ba15bd   Reza Arbab   memory-hotplug: f...
353
354
  	if (ret)
  		return -EINVAL;
3947be196   Dave Hansen   [PATCH] memory ho...
355
356
357
358
359
360
361
362
363
364
365
366
  	return count;
  }
  
  /*
   * phys_device is a bad name for this.  What I really want
   * is a way to differentiate between memory ranges that
   * are part of physical devices that constitute
   * a complete removable unit or fru.
   * i.e. do these ranges belong to the same physical device,
   * s.t. if I offline all of these sections I can then
   * remove the physical device?
   */
10fbcf4c6   Kay Sievers   convert 'memory' ...
367
368
  static ssize_t show_phys_device(struct device *dev,
  				struct device_attribute *attr, char *buf)
3947be196   Dave Hansen   [PATCH] memory ho...
369
  {
7315f0ccf   Gu Zheng   drivers/base/memo...
370
  	struct memory_block *mem = to_memory_block(dev);
3947be196   Dave Hansen   [PATCH] memory ho...
371
372
373
  	return sprintf(buf, "%d
  ", mem->phys_device);
  }
ed2f24009   Zhang Zhen   memory-hotplug: a...
374
375
376
377
378
379
  #ifdef CONFIG_MEMORY_HOTREMOVE
  static ssize_t show_valid_zones(struct device *dev,
  				struct device_attribute *attr, char *buf)
  {
  	struct memory_block *mem = to_memory_block(dev);
  	unsigned long start_pfn, end_pfn;
6cb0497ae   Toshi Kani   base/memory, hotp...
380
  	unsigned long valid_start, valid_end, valid_pages;
ed2f24009   Zhang Zhen   memory-hotplug: a...
381
  	unsigned long nr_pages = PAGES_PER_SECTION * sections_per_block;
ed2f24009   Zhang Zhen   memory-hotplug: a...
382
  	struct zone *zone;
a371d9f1c   Reza Arbab   memory-hotplug: u...
383
  	int zone_shift = 0;
ed2f24009   Zhang Zhen   memory-hotplug: a...
384
385
386
  
  	start_pfn = section_nr_to_pfn(mem->start_section_nr);
  	end_pfn = start_pfn + nr_pages;
ed2f24009   Zhang Zhen   memory-hotplug: a...
387
388
  
  	/* The block contains more than one zone can not be offlined. */
6cb0497ae   Toshi Kani   base/memory, hotp...
389
  	if (!test_pages_in_a_zone(start_pfn, end_pfn, &valid_start, &valid_end))
ed2f24009   Zhang Zhen   memory-hotplug: a...
390
391
  		return sprintf(buf, "none
  ");
6cb0497ae   Toshi Kani   base/memory, hotp...
392
393
  	zone = page_zone(pfn_to_page(valid_start));
  	valid_pages = valid_end - valid_start;
ed2f24009   Zhang Zhen   memory-hotplug: a...
394

a371d9f1c   Reza Arbab   memory-hotplug: u...
395
396
397
398
  	/* MMOP_ONLINE_KEEP */
  	sprintf(buf, "%s", zone->name);
  
  	/* MMOP_ONLINE_KERNEL */
6cb0497ae   Toshi Kani   base/memory, hotp...
399
  	zone_can_shift(valid_start, valid_pages, ZONE_NORMAL, &zone_shift);
a371d9f1c   Reza Arbab   memory-hotplug: u...
400
401
402
  	if (zone_shift) {
  		strcat(buf, " ");
  		strcat(buf, (zone + zone_shift)->name);
ed2f24009   Zhang Zhen   memory-hotplug: a...
403
  	}
a371d9f1c   Reza Arbab   memory-hotplug: u...
404
  	/* MMOP_ONLINE_MOVABLE */
6cb0497ae   Toshi Kani   base/memory, hotp...
405
  	zone_can_shift(valid_start, valid_pages, ZONE_MOVABLE, &zone_shift);
a371d9f1c   Reza Arbab   memory-hotplug: u...
406
407
408
  	if (zone_shift) {
  		strcat(buf, " ");
  		strcat(buf, (zone + zone_shift)->name);
ed2f24009   Zhang Zhen   memory-hotplug: a...
409
  	}
a371d9f1c   Reza Arbab   memory-hotplug: u...
410
411
412
413
  	strcat(buf, "
  ");
  
  	return strlen(buf);
ed2f24009   Zhang Zhen   memory-hotplug: a...
414
415
416
  }
  static DEVICE_ATTR(valid_zones, 0444, show_valid_zones, NULL);
  #endif
10fbcf4c6   Kay Sievers   convert 'memory' ...
417
  static DEVICE_ATTR(phys_index, 0444, show_mem_start_phys_index, NULL);
10fbcf4c6   Kay Sievers   convert 'memory' ...
418
419
420
  static DEVICE_ATTR(state, 0644, show_mem_state, store_mem_state);
  static DEVICE_ATTR(phys_device, 0444, show_phys_device, NULL);
  static DEVICE_ATTR(removable, 0444, show_mem_removable, NULL);
3947be196   Dave Hansen   [PATCH] memory ho...
421

3947be196   Dave Hansen   [PATCH] memory ho...
422
423
424
425
  /*
   * Block size attribute stuff
   */
  static ssize_t
10fbcf4c6   Kay Sievers   convert 'memory' ...
426
  print_block_size(struct device *dev, struct device_attribute *attr,
8564a6c14   Andi Kleen   sysdev: Fix type ...
427
  		 char *buf)
3947be196   Dave Hansen   [PATCH] memory ho...
428
  {
0c2c99b1b   Nathan Fontenot   memory hotplug: A...
429
430
  	return sprintf(buf, "%lx
  ", get_memory_block_size());
3947be196   Dave Hansen   [PATCH] memory ho...
431
  }
10fbcf4c6   Kay Sievers   convert 'memory' ...
432
  static DEVICE_ATTR(block_size_bytes, 0444, print_block_size, NULL);
3947be196   Dave Hansen   [PATCH] memory ho...
433

3947be196   Dave Hansen   [PATCH] memory ho...
434
  /*
31bc3858e   Vitaly Kuznetsov   memory-hotplug: a...
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
   * Memory auto online policy.
   */
  
  static ssize_t
  show_auto_online_blocks(struct device *dev, struct device_attribute *attr,
  			char *buf)
  {
  	if (memhp_auto_online)
  		return sprintf(buf, "online
  ");
  	else
  		return sprintf(buf, "offline
  ");
  }
  
  static ssize_t
  store_auto_online_blocks(struct device *dev, struct device_attribute *attr,
  			 const char *buf, size_t count)
  {
  	if (sysfs_streq(buf, "online"))
  		memhp_auto_online = true;
  	else if (sysfs_streq(buf, "offline"))
  		memhp_auto_online = false;
  	else
  		return -EINVAL;
  
  	return count;
  }
  
  static DEVICE_ATTR(auto_online_blocks, 0644, show_auto_online_blocks,
  		   store_auto_online_blocks);
  
  /*
3947be196   Dave Hansen   [PATCH] memory ho...
468
469
470
471
472
473
474
   * Some architectures will have custom drivers to do this, and
   * will not need to do it from userspace.  The fake hot-add code
   * as well as ppc64 will do all of their discovery in userspace
   * and will require this interface.
   */
  #ifdef CONFIG_ARCH_MEMORY_PROBE
  static ssize_t
10fbcf4c6   Kay Sievers   convert 'memory' ...
475
  memory_probe_store(struct device *dev, struct device_attribute *attr,
28812fe11   Andi Kleen   driver-core: Add ...
476
  		   const char *buf, size_t count)
3947be196   Dave Hansen   [PATCH] memory ho...
477
478
  {
  	u64 phys_addr;
cb5490a5e   John Allen   drivers/base/memo...
479
  	int nid, ret;
61b94feaf   Anton Blanchard   memory hotplug: R...
480
  	unsigned long pages_per_block = PAGES_PER_SECTION * sections_per_block;
3947be196   Dave Hansen   [PATCH] memory ho...
481

b69deb2b7   Zhang Zhen   mm/mem-hotplug: r...
482
483
484
  	ret = kstrtoull(buf, 0, &phys_addr);
  	if (ret)
  		return ret;
3947be196   Dave Hansen   [PATCH] memory ho...
485

61b94feaf   Anton Blanchard   memory hotplug: R...
486
487
  	if (phys_addr & ((pages_per_block << PAGE_SHIFT) - 1))
  		return -EINVAL;
cb5490a5e   John Allen   drivers/base/memo...
488
489
490
  	nid = memory_add_physaddr_to_nid(phys_addr);
  	ret = add_memory(nid, phys_addr,
  			 MIN_MEMORY_BLOCK_SIZE * sections_per_block);
6add7cd61   Nathan Fontenot   memory hotplug: s...
491

cb5490a5e   John Allen   drivers/base/memo...
492
493
  	if (ret)
  		goto out;
3947be196   Dave Hansen   [PATCH] memory ho...
494

9f0af69b2   Nikanth Karthikesan   sysfs-memory: fix...
495
496
497
  	ret = count;
  out:
  	return ret;
3947be196   Dave Hansen   [PATCH] memory ho...
498
  }
3947be196   Dave Hansen   [PATCH] memory ho...
499

96b2c0fc8   Nathan Fontenot   drivers/base: Use...
500
  static DEVICE_ATTR(probe, S_IWUSR, NULL, memory_probe_store);
3947be196   Dave Hansen   [PATCH] memory ho...
501
  #endif
facb6011f   Andi Kleen   HWPOISON: Add sof...
502
503
504
505
506
507
508
  #ifdef CONFIG_MEMORY_FAILURE
  /*
   * Support for offlining pages of memory
   */
  
  /* Soft offline a page */
  static ssize_t
10fbcf4c6   Kay Sievers   convert 'memory' ...
509
510
  store_soft_offline_page(struct device *dev,
  			struct device_attribute *attr,
28812fe11   Andi Kleen   driver-core: Add ...
511
  			const char *buf, size_t count)
facb6011f   Andi Kleen   HWPOISON: Add sof...
512
513
514
515
516
  {
  	int ret;
  	u64 pfn;
  	if (!capable(CAP_SYS_ADMIN))
  		return -EPERM;
34da5e677   Jingoo Han   driver core: repl...
517
  	if (kstrtoull(buf, 0, &pfn) < 0)
facb6011f   Andi Kleen   HWPOISON: Add sof...
518
519
520
521
522
523
524
525
526
527
  		return -EINVAL;
  	pfn >>= PAGE_SHIFT;
  	if (!pfn_valid(pfn))
  		return -ENXIO;
  	ret = soft_offline_page(pfn_to_page(pfn), 0);
  	return ret == 0 ? count : ret;
  }
  
  /* Forcibly offline a page, including killing processes. */
  static ssize_t
10fbcf4c6   Kay Sievers   convert 'memory' ...
528
529
  store_hard_offline_page(struct device *dev,
  			struct device_attribute *attr,
28812fe11   Andi Kleen   driver-core: Add ...
530
  			const char *buf, size_t count)
facb6011f   Andi Kleen   HWPOISON: Add sof...
531
532
533
534
535
  {
  	int ret;
  	u64 pfn;
  	if (!capable(CAP_SYS_ADMIN))
  		return -EPERM;
34da5e677   Jingoo Han   driver core: repl...
536
  	if (kstrtoull(buf, 0, &pfn) < 0)
facb6011f   Andi Kleen   HWPOISON: Add sof...
537
538
  		return -EINVAL;
  	pfn >>= PAGE_SHIFT;
cd42f4a3b   Tony Luck   HWPOISON: Clean u...
539
  	ret = memory_failure(pfn, 0, 0);
facb6011f   Andi Kleen   HWPOISON: Add sof...
540
541
  	return ret ? ret : count;
  }
74fef7a8f   Felipe Balbi   base: memory: fix...
542
543
  static DEVICE_ATTR(soft_offline_page, S_IWUSR, NULL, store_soft_offline_page);
  static DEVICE_ATTR(hard_offline_page, S_IWUSR, NULL, store_hard_offline_page);
facb6011f   Andi Kleen   HWPOISON: Add sof...
544
  #endif
3947be196   Dave Hansen   [PATCH] memory ho...
545
546
547
548
549
  /*
   * Note that phys_device is optional.  It is here to allow for
   * differentiation between which *physical* devices each
   * section belongs to...
   */
bc32df008   Heiko Carstens   memory hotplug: a...
550
551
552
553
  int __weak arch_get_memory_phys_device(unsigned long start_pfn)
  {
  	return 0;
  }
3947be196   Dave Hansen   [PATCH] memory ho...
554

10fbcf4c6   Kay Sievers   convert 'memory' ...
555
556
557
558
  /*
   * A reference for the returned object is held and the reference for the
   * hinted object is released.
   */
98383031e   Robin Holt   driver core: Intr...
559
560
  struct memory_block *find_memory_block_hinted(struct mem_section *section,
  					      struct memory_block *hint)
3947be196   Dave Hansen   [PATCH] memory ho...
561
  {
0c2c99b1b   Nathan Fontenot   memory hotplug: A...
562
  	int block_id = base_memory_block_id(__section_nr(section));
10fbcf4c6   Kay Sievers   convert 'memory' ...
563
564
  	struct device *hintdev = hint ? &hint->dev : NULL;
  	struct device *dev;
3947be196   Dave Hansen   [PATCH] memory ho...
565

10fbcf4c6   Kay Sievers   convert 'memory' ...
566
567
568
569
  	dev = subsys_find_device_by_id(&memory_subsys, block_id, hintdev);
  	if (hint)
  		put_device(&hint->dev);
  	if (!dev)
3947be196   Dave Hansen   [PATCH] memory ho...
570
  		return NULL;
7315f0ccf   Gu Zheng   drivers/base/memo...
571
  	return to_memory_block(dev);
3947be196   Dave Hansen   [PATCH] memory ho...
572
  }
98383031e   Robin Holt   driver core: Intr...
573
574
575
576
577
578
  /*
   * For now, we have a linear search to go find the appropriate
   * memory_block corresponding to a particular phys_index. If
   * this gets to be a real problem, we can always use a radix
   * tree or something here.
   *
10fbcf4c6   Kay Sievers   convert 'memory' ...
579
   * This could be made generic for all device subsystems.
98383031e   Robin Holt   driver core: Intr...
580
581
582
583
584
   */
  struct memory_block *find_memory_block(struct mem_section *section)
  {
  	return find_memory_block_hinted(section, NULL);
  }
96b2c0fc8   Nathan Fontenot   drivers/base: Use...
585
586
  static struct attribute *memory_memblk_attrs[] = {
  	&dev_attr_phys_index.attr,
96b2c0fc8   Nathan Fontenot   drivers/base: Use...
587
588
589
  	&dev_attr_state.attr,
  	&dev_attr_phys_device.attr,
  	&dev_attr_removable.attr,
ed2f24009   Zhang Zhen   memory-hotplug: a...
590
591
592
  #ifdef CONFIG_MEMORY_HOTREMOVE
  	&dev_attr_valid_zones.attr,
  #endif
96b2c0fc8   Nathan Fontenot   drivers/base: Use...
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
  	NULL
  };
  
  static struct attribute_group memory_memblk_attr_group = {
  	.attrs = memory_memblk_attrs,
  };
  
  static const struct attribute_group *memory_memblk_attr_groups[] = {
  	&memory_memblk_attr_group,
  	NULL,
  };
  
  /*
   * register_memory - Setup a sysfs device for a memory block
   */
  static
  int register_memory(struct memory_block *memory)
  {
96b2c0fc8   Nathan Fontenot   drivers/base: Use...
611
612
613
614
  	memory->dev.bus = &memory_subsys;
  	memory->dev.id = memory->start_section_nr / sections_per_block;
  	memory->dev.release = memory_block_release;
  	memory->dev.groups = memory_memblk_attr_groups;
f991fae5c   Linus Torvalds   Merge tag 'pm+acp...
615
  	memory->dev.offline = memory->state == MEM_OFFLINE;
96b2c0fc8   Nathan Fontenot   drivers/base: Use...
616

879f1bec8   Seth Jennings   drivers: base: re...
617
  	return device_register(&memory->dev);
96b2c0fc8   Nathan Fontenot   drivers/base: Use...
618
  }
0c2c99b1b   Nathan Fontenot   memory hotplug: A...
619
620
  static int init_memory_block(struct memory_block **memory,
  			     struct mem_section *section, unsigned long state)
e4619c857   Nathan Fontenot   Driver core: Move...
621
  {
0c2c99b1b   Nathan Fontenot   memory hotplug: A...
622
  	struct memory_block *mem;
e4619c857   Nathan Fontenot   Driver core: Move...
623
  	unsigned long start_pfn;
0c2c99b1b   Nathan Fontenot   memory hotplug: A...
624
  	int scn_nr;
e4619c857   Nathan Fontenot   Driver core: Move...
625
  	int ret = 0;
0c2c99b1b   Nathan Fontenot   memory hotplug: A...
626
  	mem = kzalloc(sizeof(*mem), GFP_KERNEL);
e4619c857   Nathan Fontenot   Driver core: Move...
627
628
  	if (!mem)
  		return -ENOMEM;
0c2c99b1b   Nathan Fontenot   memory hotplug: A...
629
  	scn_nr = __section_nr(section);
d33601644   Nathan Fontenot   memory hotplug: U...
630
631
632
  	mem->start_section_nr =
  			base_memory_block_id(scn_nr) * sections_per_block;
  	mem->end_section_nr = mem->start_section_nr + sections_per_block - 1;
e4619c857   Nathan Fontenot   Driver core: Move...
633
  	mem->state = state;
d33601644   Nathan Fontenot   memory hotplug: U...
634
  	start_pfn = section_nr_to_pfn(mem->start_section_nr);
e4619c857   Nathan Fontenot   Driver core: Move...
635
  	mem->phys_device = arch_get_memory_phys_device(start_pfn);
0c2c99b1b   Nathan Fontenot   memory hotplug: A...
636
  	ret = register_memory(mem);
0c2c99b1b   Nathan Fontenot   memory hotplug: A...
637
638
639
640
  
  	*memory = mem;
  	return ret;
  }
cb5e39b80   Seth Jennings   drivers: base: re...
641
  static int add_memory_block(int base_section_nr)
0c2c99b1b   Nathan Fontenot   memory hotplug: A...
642
  {
cb5e39b80   Seth Jennings   drivers: base: re...
643
644
  	struct memory_block *mem;
  	int i, ret, section_count = 0, section_nr;
0c2c99b1b   Nathan Fontenot   memory hotplug: A...
645

cb5e39b80   Seth Jennings   drivers: base: re...
646
647
648
649
650
651
652
653
  	for (i = base_section_nr;
  	     (i < base_section_nr + sections_per_block) && i < NR_MEM_SECTIONS;
  	     i++) {
  		if (!present_section_nr(i))
  			continue;
  		if (section_count == 0)
  			section_nr = i;
  		section_count++;
e4619c857   Nathan Fontenot   Driver core: Move...
654
  	}
cb5e39b80   Seth Jennings   drivers: base: re...
655
656
657
658
659
660
661
  	if (section_count == 0)
  		return 0;
  	ret = init_memory_block(&mem, __nr_to_section(section_nr), MEM_ONLINE);
  	if (ret)
  		return ret;
  	mem->section_count = section_count;
  	return 0;
e4619c857   Nathan Fontenot   Driver core: Move...
662
  }
260ae3f7d   Dan Williams   mm: skip memory b...
663
664
665
666
667
668
669
  static bool is_zone_device_section(struct mem_section *ms)
  {
  	struct page *page;
  
  	page = sparse_decode_mem_map(ms->section_mem_map, __section_nr(ms));
  	return is_zone_device_page(page);
  }
cb5e39b80   Seth Jennings   drivers: base: re...
670

4edd7ceff   David Rientjes   mm, hotplug: avoi...
671
672
673
674
675
676
  /*
   * need an interface for the VM to add new memory regions,
   * but without onlining it.
   */
  int register_new_memory(int nid, struct mem_section *section)
  {
d7f80530a   Seth Jennings   drivers: base: un...
677
678
  	int ret = 0;
  	struct memory_block *mem;
b1eaef3da   Seth Jennings   drivers: base: mo...
679

260ae3f7d   Dan Williams   mm: skip memory b...
680
681
  	if (is_zone_device_section(section))
  		return 0;
b1eaef3da   Seth Jennings   drivers: base: mo...
682
  	mutex_lock(&mem_sysfs_mutex);
b1eaef3da   Seth Jennings   drivers: base: mo...
683

d7f80530a   Seth Jennings   drivers: base: un...
684
685
686
687
688
689
690
691
  	mem = find_memory_block(section);
  	if (mem) {
  		mem->section_count++;
  		put_device(&mem->dev);
  	} else {
  		ret = init_memory_block(&mem, section, MEM_OFFLINE);
  		if (ret)
  			goto out;
56c6b5d3a   Seth Jennings   drivers/base/memo...
692
  		mem->section_count++;
d7f80530a   Seth Jennings   drivers: base: un...
693
694
695
696
697
698
  	}
  
  	if (mem->section_count == sections_per_block)
  		ret = register_mem_sect_under_node(mem, nid);
  out:
  	mutex_unlock(&mem_sysfs_mutex);
b1eaef3da   Seth Jennings   drivers: base: mo...
699
  	return ret;
4edd7ceff   David Rientjes   mm, hotplug: avoi...
700
701
702
703
704
705
706
707
708
  }
  
  #ifdef CONFIG_MEMORY_HOTREMOVE
  static void
  unregister_memory(struct memory_block *memory)
  {
  	BUG_ON(memory->dev.bus != &memory_subsys);
  
  	/* drop the ref. we got in remove_memory_block() */
df2b717c6   Seth Jennings   drivers: base: us...
709
  	put_device(&memory->dev);
4edd7ceff   David Rientjes   mm, hotplug: avoi...
710
711
  	device_unregister(&memory->dev);
  }
cc292b0b4   Seth Jennings   drivers/base/memo...
712
  static int remove_memory_section(unsigned long node_id,
4edd7ceff   David Rientjes   mm, hotplug: avoi...
713
  			       struct mem_section *section, int phys_device)
3947be196   Dave Hansen   [PATCH] memory ho...
714
715
  {
  	struct memory_block *mem;
260ae3f7d   Dan Williams   mm: skip memory b...
716
717
  	if (is_zone_device_section(section))
  		return 0;
2938ffbd4   Nathan Fontenot   Driver core: Add ...
718
  	mutex_lock(&mem_sysfs_mutex);
3947be196   Dave Hansen   [PATCH] memory ho...
719
  	mem = find_memory_block(section);
d33601644   Nathan Fontenot   memory hotplug: U...
720
  	unregister_mem_sect_under_nodes(mem, __section_nr(section));
076812159   Nathan Fontenot   Driver core: Add ...
721
722
  
  	mem->section_count--;
96b2c0fc8   Nathan Fontenot   drivers/base: Use...
723
  	if (mem->section_count == 0)
0c2c99b1b   Nathan Fontenot   memory hotplug: A...
724
  		unregister_memory(mem);
96b2c0fc8   Nathan Fontenot   drivers/base: Use...
725
  	else
df2b717c6   Seth Jennings   drivers: base: us...
726
  		put_device(&mem->dev);
3947be196   Dave Hansen   [PATCH] memory ho...
727

2938ffbd4   Nathan Fontenot   Driver core: Add ...
728
  	mutex_unlock(&mem_sysfs_mutex);
3947be196   Dave Hansen   [PATCH] memory ho...
729
730
  	return 0;
  }
3947be196   Dave Hansen   [PATCH] memory ho...
731
732
  int unregister_memory_section(struct mem_section *section)
  {
540557b94   Andy Whitcroft   sparsemem: record...
733
  	if (!present_section(section))
3947be196   Dave Hansen   [PATCH] memory ho...
734
  		return -EINVAL;
cc292b0b4   Seth Jennings   drivers/base/memo...
735
  	return remove_memory_section(0, section, 0);
3947be196   Dave Hansen   [PATCH] memory ho...
736
  }
4edd7ceff   David Rientjes   mm, hotplug: avoi...
737
  #endif /* CONFIG_MEMORY_HOTREMOVE */
3947be196   Dave Hansen   [PATCH] memory ho...
738

6677e3eaf   Yasuaki Ishimatsu   memory-hotplug: c...
739
740
741
742
743
  /* return true if the memory block is offlined, otherwise, return false */
  bool is_memblock_offlined(struct memory_block *mem)
  {
  	return mem->state == MEM_OFFLINE;
  }
96b2c0fc8   Nathan Fontenot   drivers/base: Use...
744
745
746
747
748
749
750
751
752
753
754
  static struct attribute *memory_root_attrs[] = {
  #ifdef CONFIG_ARCH_MEMORY_PROBE
  	&dev_attr_probe.attr,
  #endif
  
  #ifdef CONFIG_MEMORY_FAILURE
  	&dev_attr_soft_offline_page.attr,
  	&dev_attr_hard_offline_page.attr,
  #endif
  
  	&dev_attr_block_size_bytes.attr,
31bc3858e   Vitaly Kuznetsov   memory-hotplug: a...
755
  	&dev_attr_auto_online_blocks.attr,
96b2c0fc8   Nathan Fontenot   drivers/base: Use...
756
757
758
759
760
761
762
763
764
765
766
  	NULL
  };
  
  static struct attribute_group memory_root_attr_group = {
  	.attrs = memory_root_attrs,
  };
  
  static const struct attribute_group *memory_root_attr_groups[] = {
  	&memory_root_attr_group,
  	NULL,
  };
e90bdb7f5   Wen Congyang   memory-hotplug: u...
767
  /*
3947be196   Dave Hansen   [PATCH] memory ho...
768
769
770
771
772
773
   * Initialize the sysfs support for memory devices...
   */
  int __init memory_dev_init(void)
  {
  	unsigned int i;
  	int ret;
28ec24e23   Andrew Morton   [PATCH] driver/ba...
774
  	int err;
0c2c99b1b   Nathan Fontenot   memory hotplug: A...
775
  	unsigned long block_sz;
3947be196   Dave Hansen   [PATCH] memory ho...
776

96b2c0fc8   Nathan Fontenot   drivers/base: Use...
777
  	ret = subsys_system_register(&memory_subsys, memory_root_attr_groups);
28ec24e23   Andrew Morton   [PATCH] driver/ba...
778
779
  	if (ret)
  		goto out;
3947be196   Dave Hansen   [PATCH] memory ho...
780

0c2c99b1b   Nathan Fontenot   memory hotplug: A...
781
782
  	block_sz = get_memory_block_size();
  	sections_per_block = block_sz / MIN_MEMORY_BLOCK_SIZE;
3947be196   Dave Hansen   [PATCH] memory ho...
783
784
785
786
  	/*
  	 * Create entries for memory sections that were found
  	 * during boot and have been initialized
  	 */
b1eaef3da   Seth Jennings   drivers: base: mo...
787
  	mutex_lock(&mem_sysfs_mutex);
cb5e39b80   Seth Jennings   drivers: base: re...
788
789
  	for (i = 0; i < NR_MEM_SECTIONS; i += sections_per_block) {
  		err = add_memory_block(i);
28ec24e23   Andrew Morton   [PATCH] driver/ba...
790
791
  		if (!ret)
  			ret = err;
3947be196   Dave Hansen   [PATCH] memory ho...
792
  	}
b1eaef3da   Seth Jennings   drivers: base: mo...
793
  	mutex_unlock(&mem_sysfs_mutex);
3947be196   Dave Hansen   [PATCH] memory ho...
794

28ec24e23   Andrew Morton   [PATCH] driver/ba...
795
796
  out:
  	if (ret)
2b3a302a0   Harvey Harrison   driver core: repl...
797
798
  		printk(KERN_ERR "%s() failed: %d
  ", __func__, ret);
3947be196   Dave Hansen   [PATCH] memory ho...
799
800
  	return ret;
  }