diff options
Diffstat (limited to 'drivers/base/memory.c')
-rw-r--r-- | drivers/base/memory.c | 114 |
1 files changed, 74 insertions, 40 deletions
diff --git a/drivers/base/memory.c b/drivers/base/memory.c index 14f8a6954da0..4ebf97f99fae 100644 --- a/drivers/base/memory.c +++ b/drivers/base/memory.c | |||
@@ -37,9 +37,14 @@ static inline int base_memory_block_id(int section_nr) | |||
37 | return section_nr / sections_per_block; | 37 | return section_nr / sections_per_block; |
38 | } | 38 | } |
39 | 39 | ||
40 | static int memory_subsys_online(struct device *dev); | ||
41 | static int memory_subsys_offline(struct device *dev); | ||
42 | |||
40 | static struct bus_type memory_subsys = { | 43 | static struct bus_type memory_subsys = { |
41 | .name = MEMORY_CLASS_NAME, | 44 | .name = MEMORY_CLASS_NAME, |
42 | .dev_name = MEMORY_CLASS_NAME, | 45 | .dev_name = MEMORY_CLASS_NAME, |
46 | .online = memory_subsys_online, | ||
47 | .offline = memory_subsys_offline, | ||
43 | }; | 48 | }; |
44 | 49 | ||
45 | static BLOCKING_NOTIFIER_HEAD(memory_chain); | 50 | static BLOCKING_NOTIFIER_HEAD(memory_chain); |
@@ -88,6 +93,7 @@ int register_memory(struct memory_block *memory) | |||
88 | memory->dev.bus = &memory_subsys; | 93 | memory->dev.bus = &memory_subsys; |
89 | memory->dev.id = memory->start_section_nr / sections_per_block; | 94 | memory->dev.id = memory->start_section_nr / sections_per_block; |
90 | memory->dev.release = memory_block_release; | 95 | memory->dev.release = memory_block_release; |
96 | memory->dev.offline = memory->state == MEM_OFFLINE; | ||
91 | 97 | ||
92 | error = device_register(&memory->dev); | 98 | error = device_register(&memory->dev); |
93 | return error; | 99 | return error; |
@@ -278,33 +284,64 @@ static int __memory_block_change_state(struct memory_block *mem, | |||
278 | { | 284 | { |
279 | int ret = 0; | 285 | int ret = 0; |
280 | 286 | ||
281 | if (mem->state != from_state_req) { | 287 | if (mem->state != from_state_req) |
282 | ret = -EINVAL; | 288 | return -EINVAL; |
283 | goto out; | ||
284 | } | ||
285 | 289 | ||
286 | if (to_state == MEM_OFFLINE) | 290 | if (to_state == MEM_OFFLINE) |
287 | mem->state = MEM_GOING_OFFLINE; | 291 | mem->state = MEM_GOING_OFFLINE; |
288 | 292 | ||
289 | ret = memory_block_action(mem->start_section_nr, to_state, online_type); | 293 | ret = memory_block_action(mem->start_section_nr, to_state, online_type); |
294 | mem->state = ret ? from_state_req : to_state; | ||
295 | return ret; | ||
296 | } | ||
290 | 297 | ||
291 | if (ret) { | 298 | static int memory_subsys_online(struct device *dev) |
292 | mem->state = from_state_req; | 299 | { |
293 | goto out; | 300 | struct memory_block *mem = container_of(dev, struct memory_block, dev); |
294 | } | 301 | int ret; |
295 | 302 | ||
296 | mem->state = to_state; | 303 | mutex_lock(&mem->state_mutex); |
297 | switch (mem->state) { | 304 | |
298 | case MEM_OFFLINE: | 305 | ret = mem->state == MEM_ONLINE ? 0 : |
299 | kobject_uevent(&mem->dev.kobj, KOBJ_OFFLINE); | 306 | __memory_block_change_state(mem, MEM_ONLINE, MEM_OFFLINE, |
300 | break; | 307 | ONLINE_KEEP); |
301 | case MEM_ONLINE: | 308 | |
302 | kobject_uevent(&mem->dev.kobj, KOBJ_ONLINE); | 309 | mutex_unlock(&mem->state_mutex); |
303 | break; | 310 | return ret; |
304 | default: | 311 | } |
305 | break; | 312 | |
313 | static int memory_subsys_offline(struct device *dev) | ||
314 | { | ||
315 | struct memory_block *mem = container_of(dev, struct memory_block, dev); | ||
316 | int ret; | ||
317 | |||
318 | mutex_lock(&mem->state_mutex); | ||
319 | |||
320 | ret = mem->state == MEM_OFFLINE ? 0 : | ||
321 | __memory_block_change_state(mem, MEM_OFFLINE, MEM_ONLINE, -1); | ||
322 | |||
323 | mutex_unlock(&mem->state_mutex); | ||
324 | return ret; | ||
325 | } | ||
326 | |||
327 | static int __memory_block_change_state_uevent(struct memory_block *mem, | ||
328 | unsigned long to_state, unsigned long from_state_req, | ||
329 | int online_type) | ||
330 | { | ||
331 | int ret = __memory_block_change_state(mem, to_state, from_state_req, | ||
332 | online_type); | ||
333 | if (!ret) { | ||
334 | switch (mem->state) { | ||
335 | case MEM_OFFLINE: | ||
336 | kobject_uevent(&mem->dev.kobj, KOBJ_OFFLINE); | ||
337 | break; | ||
338 | case MEM_ONLINE: | ||
339 | kobject_uevent(&mem->dev.kobj, KOBJ_ONLINE); | ||
340 | break; | ||
341 | default: | ||
342 | break; | ||
343 | } | ||
306 | } | 344 | } |
307 | out: | ||
308 | return ret; | 345 | return ret; |
309 | } | 346 | } |
310 | 347 | ||
@@ -315,8 +352,8 @@ static int memory_block_change_state(struct memory_block *mem, | |||
315 | int ret; | 352 | int ret; |
316 | 353 | ||
317 | mutex_lock(&mem->state_mutex); | 354 | mutex_lock(&mem->state_mutex); |
318 | ret = __memory_block_change_state(mem, to_state, from_state_req, | 355 | ret = __memory_block_change_state_uevent(mem, to_state, from_state_req, |
319 | online_type); | 356 | online_type); |
320 | mutex_unlock(&mem->state_mutex); | 357 | mutex_unlock(&mem->state_mutex); |
321 | 358 | ||
322 | return ret; | 359 | return ret; |
@@ -326,22 +363,34 @@ store_mem_state(struct device *dev, | |||
326 | struct device_attribute *attr, const char *buf, size_t count) | 363 | struct device_attribute *attr, const char *buf, size_t count) |
327 | { | 364 | { |
328 | struct memory_block *mem; | 365 | struct memory_block *mem; |
366 | bool offline; | ||
329 | int ret = -EINVAL; | 367 | int ret = -EINVAL; |
330 | 368 | ||
331 | mem = container_of(dev, struct memory_block, dev); | 369 | mem = container_of(dev, struct memory_block, dev); |
332 | 370 | ||
333 | if (!strncmp(buf, "online_kernel", min_t(int, count, 13))) | 371 | lock_device_hotplug(); |
372 | |||
373 | if (!strncmp(buf, "online_kernel", min_t(int, count, 13))) { | ||
374 | offline = false; | ||
334 | ret = memory_block_change_state(mem, MEM_ONLINE, | 375 | ret = memory_block_change_state(mem, MEM_ONLINE, |
335 | MEM_OFFLINE, ONLINE_KERNEL); | 376 | MEM_OFFLINE, ONLINE_KERNEL); |
336 | else if (!strncmp(buf, "online_movable", min_t(int, count, 14))) | 377 | } else if (!strncmp(buf, "online_movable", min_t(int, count, 14))) { |
378 | offline = false; | ||
337 | ret = memory_block_change_state(mem, MEM_ONLINE, | 379 | ret = memory_block_change_state(mem, MEM_ONLINE, |
338 | MEM_OFFLINE, ONLINE_MOVABLE); | 380 | MEM_OFFLINE, ONLINE_MOVABLE); |
339 | else if (!strncmp(buf, "online", min_t(int, count, 6))) | 381 | } else if (!strncmp(buf, "online", min_t(int, count, 6))) { |
382 | offline = false; | ||
340 | ret = memory_block_change_state(mem, MEM_ONLINE, | 383 | ret = memory_block_change_state(mem, MEM_ONLINE, |
341 | MEM_OFFLINE, ONLINE_KEEP); | 384 | MEM_OFFLINE, ONLINE_KEEP); |
342 | else if(!strncmp(buf, "offline", min_t(int, count, 7))) | 385 | } else if(!strncmp(buf, "offline", min_t(int, count, 7))) { |
386 | offline = true; | ||
343 | ret = memory_block_change_state(mem, MEM_OFFLINE, | 387 | ret = memory_block_change_state(mem, MEM_OFFLINE, |
344 | MEM_ONLINE, -1); | 388 | MEM_ONLINE, -1); |
389 | } | ||
390 | if (!ret) | ||
391 | dev->offline = offline; | ||
392 | |||
393 | unlock_device_hotplug(); | ||
345 | 394 | ||
346 | if (ret) | 395 | if (ret) |
347 | return ret; | 396 | return ret; |
@@ -679,21 +728,6 @@ int unregister_memory_section(struct mem_section *section) | |||
679 | } | 728 | } |
680 | #endif /* CONFIG_MEMORY_HOTREMOVE */ | 729 | #endif /* CONFIG_MEMORY_HOTREMOVE */ |
681 | 730 | ||
682 | /* | ||
683 | * offline one memory block. If the memory block has been offlined, do nothing. | ||
684 | */ | ||
685 | int offline_memory_block(struct memory_block *mem) | ||
686 | { | ||
687 | int ret = 0; | ||
688 | |||
689 | mutex_lock(&mem->state_mutex); | ||
690 | if (mem->state != MEM_OFFLINE) | ||
691 | ret = __memory_block_change_state(mem, MEM_OFFLINE, MEM_ONLINE, -1); | ||
692 | mutex_unlock(&mem->state_mutex); | ||
693 | |||
694 | return ret; | ||
695 | } | ||
696 | |||
697 | /* return true if the memory block is offlined, otherwise, return false */ | 731 | /* return true if the memory block is offlined, otherwise, return false */ |
698 | bool is_memblock_offlined(struct memory_block *mem) | 732 | bool is_memblock_offlined(struct memory_block *mem) |
699 | { | 733 | { |