diff options
Diffstat (limited to 'drivers/base/memory.c')
-rw-r--r-- | drivers/base/memory.c | 160 |
1 files changed, 66 insertions, 94 deletions
diff --git a/drivers/base/memory.c b/drivers/base/memory.c index 8272d92d22c0..f17e3ea041c0 100644 --- a/drivers/base/memory.c +++ b/drivers/base/memory.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * drivers/base/memory.c - basic Memory class support | 2 | * Memory subsystem support |
3 | * | 3 | * |
4 | * Written by Matt Tolentino <matthew.e.tolentino@intel.com> | 4 | * Written by Matt Tolentino <matthew.e.tolentino@intel.com> |
5 | * Dave Hansen <haveblue@us.ibm.com> | 5 | * Dave Hansen <haveblue@us.ibm.com> |
@@ -10,7 +10,6 @@ | |||
10 | * SPARSEMEM should be contained here, or in mm/memory_hotplug.c. | 10 | * SPARSEMEM should be contained here, or in mm/memory_hotplug.c. |
11 | */ | 11 | */ |
12 | 12 | ||
13 | #include <linux/sysdev.h> | ||
14 | #include <linux/module.h> | 13 | #include <linux/module.h> |
15 | #include <linux/init.h> | 14 | #include <linux/init.h> |
16 | #include <linux/topology.h> | 15 | #include <linux/topology.h> |
@@ -38,26 +37,9 @@ static inline int base_memory_block_id(int section_nr) | |||
38 | return section_nr / sections_per_block; | 37 | return section_nr / sections_per_block; |
39 | } | 38 | } |
40 | 39 | ||
41 | static struct sysdev_class memory_sysdev_class = { | 40 | static struct bus_type memory_subsys = { |
42 | .name = MEMORY_CLASS_NAME, | 41 | .name = MEMORY_CLASS_NAME, |
43 | }; | 42 | .dev_name = MEMORY_CLASS_NAME, |
44 | |||
45 | static const char *memory_uevent_name(struct kset *kset, struct kobject *kobj) | ||
46 | { | ||
47 | return MEMORY_CLASS_NAME; | ||
48 | } | ||
49 | |||
50 | static int memory_uevent(struct kset *kset, struct kobject *obj, | ||
51 | struct kobj_uevent_env *env) | ||
52 | { | ||
53 | int retval = 0; | ||
54 | |||
55 | return retval; | ||
56 | } | ||
57 | |||
58 | static const struct kset_uevent_ops memory_uevent_ops = { | ||
59 | .name = memory_uevent_name, | ||
60 | .uevent = memory_uevent, | ||
61 | }; | 43 | }; |
62 | 44 | ||
63 | static BLOCKING_NOTIFIER_HEAD(memory_chain); | 45 | static BLOCKING_NOTIFIER_HEAD(memory_chain); |
@@ -96,21 +78,21 @@ int register_memory(struct memory_block *memory) | |||
96 | { | 78 | { |
97 | int error; | 79 | int error; |
98 | 80 | ||
99 | memory->sysdev.cls = &memory_sysdev_class; | 81 | memory->dev.bus = &memory_subsys; |
100 | memory->sysdev.id = memory->start_section_nr / sections_per_block; | 82 | memory->dev.id = memory->start_section_nr / sections_per_block; |
101 | 83 | ||
102 | error = sysdev_register(&memory->sysdev); | 84 | error = device_register(&memory->dev); |
103 | return error; | 85 | return error; |
104 | } | 86 | } |
105 | 87 | ||
106 | static void | 88 | static void |
107 | unregister_memory(struct memory_block *memory) | 89 | unregister_memory(struct memory_block *memory) |
108 | { | 90 | { |
109 | BUG_ON(memory->sysdev.cls != &memory_sysdev_class); | 91 | BUG_ON(memory->dev.bus != &memory_subsys); |
110 | 92 | ||
111 | /* drop the ref. we got in remove_memory_block() */ | 93 | /* drop the ref. we got in remove_memory_block() */ |
112 | kobject_put(&memory->sysdev.kobj); | 94 | kobject_put(&memory->dev.kobj); |
113 | sysdev_unregister(&memory->sysdev); | 95 | device_unregister(&memory->dev); |
114 | } | 96 | } |
115 | 97 | ||
116 | unsigned long __weak memory_block_size_bytes(void) | 98 | unsigned long __weak memory_block_size_bytes(void) |
@@ -138,22 +120,22 @@ static unsigned long get_memory_block_size(void) | |||
138 | * uses. | 120 | * uses. |
139 | */ | 121 | */ |
140 | 122 | ||
141 | static ssize_t show_mem_start_phys_index(struct sys_device *dev, | 123 | static ssize_t show_mem_start_phys_index(struct device *dev, |
142 | struct sysdev_attribute *attr, char *buf) | 124 | struct device_attribute *attr, char *buf) |
143 | { | 125 | { |
144 | struct memory_block *mem = | 126 | struct memory_block *mem = |
145 | container_of(dev, struct memory_block, sysdev); | 127 | container_of(dev, struct memory_block, dev); |
146 | unsigned long phys_index; | 128 | unsigned long phys_index; |
147 | 129 | ||
148 | phys_index = mem->start_section_nr / sections_per_block; | 130 | phys_index = mem->start_section_nr / sections_per_block; |
149 | return sprintf(buf, "%08lx\n", phys_index); | 131 | return sprintf(buf, "%08lx\n", phys_index); |
150 | } | 132 | } |
151 | 133 | ||
152 | static ssize_t show_mem_end_phys_index(struct sys_device *dev, | 134 | static ssize_t show_mem_end_phys_index(struct device *dev, |
153 | struct sysdev_attribute *attr, char *buf) | 135 | struct device_attribute *attr, char *buf) |
154 | { | 136 | { |
155 | struct memory_block *mem = | 137 | struct memory_block *mem = |
156 | container_of(dev, struct memory_block, sysdev); | 138 | container_of(dev, struct memory_block, dev); |
157 | unsigned long phys_index; | 139 | unsigned long phys_index; |
158 | 140 | ||
159 | phys_index = mem->end_section_nr / sections_per_block; | 141 | phys_index = mem->end_section_nr / sections_per_block; |
@@ -163,13 +145,13 @@ static ssize_t show_mem_end_phys_index(struct sys_device *dev, | |||
163 | /* | 145 | /* |
164 | * Show whether the section of memory is likely to be hot-removable | 146 | * Show whether the section of memory is likely to be hot-removable |
165 | */ | 147 | */ |
166 | static ssize_t show_mem_removable(struct sys_device *dev, | 148 | static ssize_t show_mem_removable(struct device *dev, |
167 | struct sysdev_attribute *attr, char *buf) | 149 | struct device_attribute *attr, char *buf) |
168 | { | 150 | { |
169 | unsigned long i, pfn; | 151 | unsigned long i, pfn; |
170 | int ret = 1; | 152 | int ret = 1; |
171 | struct memory_block *mem = | 153 | struct memory_block *mem = |
172 | container_of(dev, struct memory_block, sysdev); | 154 | container_of(dev, struct memory_block, dev); |
173 | 155 | ||
174 | for (i = 0; i < sections_per_block; i++) { | 156 | for (i = 0; i < sections_per_block; i++) { |
175 | pfn = section_nr_to_pfn(mem->start_section_nr + i); | 157 | pfn = section_nr_to_pfn(mem->start_section_nr + i); |
@@ -182,11 +164,11 @@ static ssize_t show_mem_removable(struct sys_device *dev, | |||
182 | /* | 164 | /* |
183 | * online, offline, going offline, etc. | 165 | * online, offline, going offline, etc. |
184 | */ | 166 | */ |
185 | static ssize_t show_mem_state(struct sys_device *dev, | 167 | static ssize_t show_mem_state(struct device *dev, |
186 | struct sysdev_attribute *attr, char *buf) | 168 | struct device_attribute *attr, char *buf) |
187 | { | 169 | { |
188 | struct memory_block *mem = | 170 | struct memory_block *mem = |
189 | container_of(dev, struct memory_block, sysdev); | 171 | container_of(dev, struct memory_block, dev); |
190 | ssize_t len = 0; | 172 | ssize_t len = 0; |
191 | 173 | ||
192 | /* | 174 | /* |
@@ -324,13 +306,13 @@ out: | |||
324 | } | 306 | } |
325 | 307 | ||
326 | static ssize_t | 308 | static ssize_t |
327 | store_mem_state(struct sys_device *dev, | 309 | store_mem_state(struct device *dev, |
328 | struct sysdev_attribute *attr, const char *buf, size_t count) | 310 | struct device_attribute *attr, const char *buf, size_t count) |
329 | { | 311 | { |
330 | struct memory_block *mem; | 312 | struct memory_block *mem; |
331 | int ret = -EINVAL; | 313 | int ret = -EINVAL; |
332 | 314 | ||
333 | mem = container_of(dev, struct memory_block, sysdev); | 315 | mem = container_of(dev, struct memory_block, dev); |
334 | 316 | ||
335 | if (!strncmp(buf, "online", min((int)count, 6))) | 317 | if (!strncmp(buf, "online", min((int)count, 6))) |
336 | ret = memory_block_change_state(mem, MEM_ONLINE, MEM_OFFLINE); | 318 | ret = memory_block_change_state(mem, MEM_ONLINE, MEM_OFFLINE); |
@@ -351,41 +333,41 @@ store_mem_state(struct sys_device *dev, | |||
351 | * s.t. if I offline all of these sections I can then | 333 | * s.t. if I offline all of these sections I can then |
352 | * remove the physical device? | 334 | * remove the physical device? |
353 | */ | 335 | */ |
354 | static ssize_t show_phys_device(struct sys_device *dev, | 336 | static ssize_t show_phys_device(struct device *dev, |
355 | struct sysdev_attribute *attr, char *buf) | 337 | struct device_attribute *attr, char *buf) |
356 | { | 338 | { |
357 | struct memory_block *mem = | 339 | struct memory_block *mem = |
358 | container_of(dev, struct memory_block, sysdev); | 340 | container_of(dev, struct memory_block, dev); |
359 | return sprintf(buf, "%d\n", mem->phys_device); | 341 | return sprintf(buf, "%d\n", mem->phys_device); |
360 | } | 342 | } |
361 | 343 | ||
362 | static SYSDEV_ATTR(phys_index, 0444, show_mem_start_phys_index, NULL); | 344 | static DEVICE_ATTR(phys_index, 0444, show_mem_start_phys_index, NULL); |
363 | static SYSDEV_ATTR(end_phys_index, 0444, show_mem_end_phys_index, NULL); | 345 | static DEVICE_ATTR(end_phys_index, 0444, show_mem_end_phys_index, NULL); |
364 | static SYSDEV_ATTR(state, 0644, show_mem_state, store_mem_state); | 346 | static DEVICE_ATTR(state, 0644, show_mem_state, store_mem_state); |
365 | static SYSDEV_ATTR(phys_device, 0444, show_phys_device, NULL); | 347 | static DEVICE_ATTR(phys_device, 0444, show_phys_device, NULL); |
366 | static SYSDEV_ATTR(removable, 0444, show_mem_removable, NULL); | 348 | static DEVICE_ATTR(removable, 0444, show_mem_removable, NULL); |
367 | 349 | ||
368 | #define mem_create_simple_file(mem, attr_name) \ | 350 | #define mem_create_simple_file(mem, attr_name) \ |
369 | sysdev_create_file(&mem->sysdev, &attr_##attr_name) | 351 | device_create_file(&mem->dev, &dev_attr_##attr_name) |
370 | #define mem_remove_simple_file(mem, attr_name) \ | 352 | #define mem_remove_simple_file(mem, attr_name) \ |
371 | sysdev_remove_file(&mem->sysdev, &attr_##attr_name) | 353 | device_remove_file(&mem->dev, &dev_attr_##attr_name) |
372 | 354 | ||
373 | /* | 355 | /* |
374 | * Block size attribute stuff | 356 | * Block size attribute stuff |
375 | */ | 357 | */ |
376 | static ssize_t | 358 | static ssize_t |
377 | print_block_size(struct sysdev_class *class, struct sysdev_class_attribute *attr, | 359 | print_block_size(struct device *dev, struct device_attribute *attr, |
378 | char *buf) | 360 | char *buf) |
379 | { | 361 | { |
380 | return sprintf(buf, "%lx\n", get_memory_block_size()); | 362 | return sprintf(buf, "%lx\n", get_memory_block_size()); |
381 | } | 363 | } |
382 | 364 | ||
383 | static SYSDEV_CLASS_ATTR(block_size_bytes, 0444, print_block_size, NULL); | 365 | static DEVICE_ATTR(block_size_bytes, 0444, print_block_size, NULL); |
384 | 366 | ||
385 | static int block_size_init(void) | 367 | static int block_size_init(void) |
386 | { | 368 | { |
387 | return sysfs_create_file(&memory_sysdev_class.kset.kobj, | 369 | return device_create_file(memory_subsys.dev_root, |
388 | &attr_block_size_bytes.attr); | 370 | &dev_attr_block_size_bytes); |
389 | } | 371 | } |
390 | 372 | ||
391 | /* | 373 | /* |
@@ -396,7 +378,7 @@ static int block_size_init(void) | |||
396 | */ | 378 | */ |
397 | #ifdef CONFIG_ARCH_MEMORY_PROBE | 379 | #ifdef CONFIG_ARCH_MEMORY_PROBE |
398 | static ssize_t | 380 | static ssize_t |
399 | memory_probe_store(struct class *class, struct class_attribute *attr, | 381 | memory_probe_store(struct device *dev, struct device_attribute *attr, |
400 | const char *buf, size_t count) | 382 | const char *buf, size_t count) |
401 | { | 383 | { |
402 | u64 phys_addr; | 384 | u64 phys_addr; |
@@ -423,12 +405,11 @@ memory_probe_store(struct class *class, struct class_attribute *attr, | |||
423 | out: | 405 | out: |
424 | return ret; | 406 | return ret; |
425 | } | 407 | } |
426 | static CLASS_ATTR(probe, S_IWUSR, NULL, memory_probe_store); | 408 | static DEVICE_ATTR(probe, S_IWUSR, NULL, memory_probe_store); |
427 | 409 | ||
428 | static int memory_probe_init(void) | 410 | static int memory_probe_init(void) |
429 | { | 411 | { |
430 | return sysfs_create_file(&memory_sysdev_class.kset.kobj, | 412 | return device_create_file(memory_subsys.dev_root, &dev_attr_probe); |
431 | &class_attr_probe.attr); | ||
432 | } | 413 | } |
433 | #else | 414 | #else |
434 | static inline int memory_probe_init(void) | 415 | static inline int memory_probe_init(void) |
@@ -444,8 +425,8 @@ static inline int memory_probe_init(void) | |||
444 | 425 | ||
445 | /* Soft offline a page */ | 426 | /* Soft offline a page */ |
446 | static ssize_t | 427 | static ssize_t |
447 | store_soft_offline_page(struct class *class, | 428 | store_soft_offline_page(struct device *dev, |
448 | struct class_attribute *attr, | 429 | struct device_attribute *attr, |
449 | const char *buf, size_t count) | 430 | const char *buf, size_t count) |
450 | { | 431 | { |
451 | int ret; | 432 | int ret; |
@@ -463,8 +444,8 @@ store_soft_offline_page(struct class *class, | |||
463 | 444 | ||
464 | /* Forcibly offline a page, including killing processes. */ | 445 | /* Forcibly offline a page, including killing processes. */ |
465 | static ssize_t | 446 | static ssize_t |
466 | store_hard_offline_page(struct class *class, | 447 | store_hard_offline_page(struct device *dev, |
467 | struct class_attribute *attr, | 448 | struct device_attribute *attr, |
468 | const char *buf, size_t count) | 449 | const char *buf, size_t count) |
469 | { | 450 | { |
470 | int ret; | 451 | int ret; |
@@ -478,18 +459,18 @@ store_hard_offline_page(struct class *class, | |||
478 | return ret ? ret : count; | 459 | return ret ? ret : count; |
479 | } | 460 | } |
480 | 461 | ||
481 | static CLASS_ATTR(soft_offline_page, 0644, NULL, store_soft_offline_page); | 462 | static DEVICE_ATTR(soft_offline_page, 0644, NULL, store_soft_offline_page); |
482 | static CLASS_ATTR(hard_offline_page, 0644, NULL, store_hard_offline_page); | 463 | static DEVICE_ATTR(hard_offline_page, 0644, NULL, store_hard_offline_page); |
483 | 464 | ||
484 | static __init int memory_fail_init(void) | 465 | static __init int memory_fail_init(void) |
485 | { | 466 | { |
486 | int err; | 467 | int err; |
487 | 468 | ||
488 | err = sysfs_create_file(&memory_sysdev_class.kset.kobj, | 469 | err = device_create_file(memory_subsys.dev_root, |
489 | &class_attr_soft_offline_page.attr); | 470 | &dev_attr_soft_offline_page); |
490 | if (!err) | 471 | if (!err) |
491 | err = sysfs_create_file(&memory_sysdev_class.kset.kobj, | 472 | err = device_create_file(memory_subsys.dev_root, |
492 | &class_attr_hard_offline_page.attr); | 473 | &dev_attr_hard_offline_page); |
493 | return err; | 474 | return err; |
494 | } | 475 | } |
495 | #else | 476 | #else |
@@ -509,31 +490,23 @@ int __weak arch_get_memory_phys_device(unsigned long start_pfn) | |||
509 | return 0; | 490 | return 0; |
510 | } | 491 | } |
511 | 492 | ||
493 | /* | ||
494 | * A reference for the returned object is held and the reference for the | ||
495 | * hinted object is released. | ||
496 | */ | ||
512 | struct memory_block *find_memory_block_hinted(struct mem_section *section, | 497 | struct memory_block *find_memory_block_hinted(struct mem_section *section, |
513 | struct memory_block *hint) | 498 | struct memory_block *hint) |
514 | { | 499 | { |
515 | struct kobject *kobj; | ||
516 | struct sys_device *sysdev; | ||
517 | struct memory_block *mem; | ||
518 | char name[sizeof(MEMORY_CLASS_NAME) + 9 + 1]; | ||
519 | int block_id = base_memory_block_id(__section_nr(section)); | 500 | int block_id = base_memory_block_id(__section_nr(section)); |
501 | struct device *hintdev = hint ? &hint->dev : NULL; | ||
502 | struct device *dev; | ||
520 | 503 | ||
521 | kobj = hint ? &hint->sysdev.kobj : NULL; | 504 | dev = subsys_find_device_by_id(&memory_subsys, block_id, hintdev); |
522 | 505 | if (hint) | |
523 | /* | 506 | put_device(&hint->dev); |
524 | * This only works because we know that section == sysdev->id | 507 | if (!dev) |
525 | * slightly redundant with sysdev_register() | ||
526 | */ | ||
527 | sprintf(&name[0], "%s%d", MEMORY_CLASS_NAME, block_id); | ||
528 | |||
529 | kobj = kset_find_obj_hinted(&memory_sysdev_class.kset, name, kobj); | ||
530 | if (!kobj) | ||
531 | return NULL; | 508 | return NULL; |
532 | 509 | return container_of(dev, struct memory_block, dev); | |
533 | sysdev = container_of(kobj, struct sys_device, kobj); | ||
534 | mem = container_of(sysdev, struct memory_block, sysdev); | ||
535 | |||
536 | return mem; | ||
537 | } | 510 | } |
538 | 511 | ||
539 | /* | 512 | /* |
@@ -542,7 +515,7 @@ struct memory_block *find_memory_block_hinted(struct mem_section *section, | |||
542 | * this gets to be a real problem, we can always use a radix | 515 | * this gets to be a real problem, we can always use a radix |
543 | * tree or something here. | 516 | * tree or something here. |
544 | * | 517 | * |
545 | * This could be made generic for all sysdev classes. | 518 | * This could be made generic for all device subsystems. |
546 | */ | 519 | */ |
547 | struct memory_block *find_memory_block(struct mem_section *section) | 520 | struct memory_block *find_memory_block(struct mem_section *section) |
548 | { | 521 | { |
@@ -598,7 +571,7 @@ static int add_memory_section(int nid, struct mem_section *section, | |||
598 | mem = find_memory_block(section); | 571 | mem = find_memory_block(section); |
599 | if (mem) { | 572 | if (mem) { |
600 | mem->section_count++; | 573 | mem->section_count++; |
601 | kobject_put(&mem->sysdev.kobj); | 574 | kobject_put(&mem->dev.kobj); |
602 | } else | 575 | } else |
603 | ret = init_memory_block(&mem, section, state); | 576 | ret = init_memory_block(&mem, section, state); |
604 | 577 | ||
@@ -631,7 +604,7 @@ int remove_memory_block(unsigned long node_id, struct mem_section *section, | |||
631 | unregister_memory(mem); | 604 | unregister_memory(mem); |
632 | kfree(mem); | 605 | kfree(mem); |
633 | } else | 606 | } else |
634 | kobject_put(&mem->sysdev.kobj); | 607 | kobject_put(&mem->dev.kobj); |
635 | 608 | ||
636 | mutex_unlock(&mem_sysfs_mutex); | 609 | mutex_unlock(&mem_sysfs_mutex); |
637 | return 0; | 610 | return 0; |
@@ -664,8 +637,7 @@ int __init memory_dev_init(void) | |||
664 | int err; | 637 | int err; |
665 | unsigned long block_sz; | 638 | unsigned long block_sz; |
666 | 639 | ||
667 | memory_sysdev_class.kset.uevent_ops = &memory_uevent_ops; | 640 | ret = subsys_system_register(&memory_subsys, NULL); |
668 | ret = sysdev_class_register(&memory_sysdev_class); | ||
669 | if (ret) | 641 | if (ret) |
670 | goto out; | 642 | goto out; |
671 | 643 | ||