aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base/memory.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/base/memory.c')
-rw-r--r--drivers/base/memory.c114
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
40static int memory_subsys_online(struct device *dev);
41static int memory_subsys_offline(struct device *dev);
42
40static struct bus_type memory_subsys = { 43static 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
45static BLOCKING_NOTIFIER_HEAD(memory_chain); 50static 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) { 298static 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
313static 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
327static 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 }
307out:
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 */
685int 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 */
698bool is_memblock_offlined(struct memory_block *mem) 732bool is_memblock_offlined(struct memory_block *mem)
699{ 733{