|
@@ -1,5 +1,5 @@
|
|
|
/*
|
|
|
- * drivers/base/memory.c - basic Memory class support
|
|
|
+ * Memory subsystem support
|
|
|
*
|
|
|
* Written by Matt Tolentino <matthew.e.tolentino@intel.com>
|
|
|
* Dave Hansen <haveblue@us.ibm.com>
|
|
@@ -10,7 +10,6 @@
|
|
|
* SPARSEMEM should be contained here, or in mm/memory_hotplug.c.
|
|
|
*/
|
|
|
|
|
|
-#include <linux/sysdev.h>
|
|
|
#include <linux/module.h>
|
|
|
#include <linux/init.h>
|
|
|
#include <linux/topology.h>
|
|
@@ -38,26 +37,9 @@ static inline int base_memory_block_id(int section_nr)
|
|
|
return section_nr / sections_per_block;
|
|
|
}
|
|
|
|
|
|
-static struct sysdev_class memory_sysdev_class = {
|
|
|
+static struct bus_type memory_subsys = {
|
|
|
.name = MEMORY_CLASS_NAME,
|
|
|
-};
|
|
|
-
|
|
|
-static const char *memory_uevent_name(struct kset *kset, struct kobject *kobj)
|
|
|
-{
|
|
|
- return MEMORY_CLASS_NAME;
|
|
|
-}
|
|
|
-
|
|
|
-static int memory_uevent(struct kset *kset, struct kobject *obj,
|
|
|
- struct kobj_uevent_env *env)
|
|
|
-{
|
|
|
- int retval = 0;
|
|
|
-
|
|
|
- return retval;
|
|
|
-}
|
|
|
-
|
|
|
-static const struct kset_uevent_ops memory_uevent_ops = {
|
|
|
- .name = memory_uevent_name,
|
|
|
- .uevent = memory_uevent,
|
|
|
+ .dev_name = MEMORY_CLASS_NAME,
|
|
|
};
|
|
|
|
|
|
static BLOCKING_NOTIFIER_HEAD(memory_chain);
|
|
@@ -96,21 +78,21 @@ int register_memory(struct memory_block *memory)
|
|
|
{
|
|
|
int error;
|
|
|
|
|
|
- memory->sysdev.cls = &memory_sysdev_class;
|
|
|
- memory->sysdev.id = memory->start_section_nr / sections_per_block;
|
|
|
+ memory->dev.bus = &memory_subsys;
|
|
|
+ memory->dev.id = memory->start_section_nr / sections_per_block;
|
|
|
|
|
|
- error = sysdev_register(&memory->sysdev);
|
|
|
+ error = device_register(&memory->dev);
|
|
|
return error;
|
|
|
}
|
|
|
|
|
|
static void
|
|
|
unregister_memory(struct memory_block *memory)
|
|
|
{
|
|
|
- BUG_ON(memory->sysdev.cls != &memory_sysdev_class);
|
|
|
+ BUG_ON(memory->dev.bus != &memory_subsys);
|
|
|
|
|
|
/* drop the ref. we got in remove_memory_block() */
|
|
|
- kobject_put(&memory->sysdev.kobj);
|
|
|
- sysdev_unregister(&memory->sysdev);
|
|
|
+ kobject_put(&memory->dev.kobj);
|
|
|
+ device_unregister(&memory->dev);
|
|
|
}
|
|
|
|
|
|
unsigned long __weak memory_block_size_bytes(void)
|
|
@@ -138,22 +120,22 @@ static unsigned long get_memory_block_size(void)
|
|
|
* uses.
|
|
|
*/
|
|
|
|
|
|
-static ssize_t show_mem_start_phys_index(struct sys_device *dev,
|
|
|
- struct sysdev_attribute *attr, char *buf)
|
|
|
+static ssize_t show_mem_start_phys_index(struct device *dev,
|
|
|
+ struct device_attribute *attr, char *buf)
|
|
|
{
|
|
|
struct memory_block *mem =
|
|
|
- container_of(dev, struct memory_block, sysdev);
|
|
|
+ container_of(dev, struct memory_block, dev);
|
|
|
unsigned long phys_index;
|
|
|
|
|
|
phys_index = mem->start_section_nr / sections_per_block;
|
|
|
return sprintf(buf, "%08lx\n", phys_index);
|
|
|
}
|
|
|
|
|
|
-static ssize_t show_mem_end_phys_index(struct sys_device *dev,
|
|
|
- struct sysdev_attribute *attr, char *buf)
|
|
|
+static ssize_t show_mem_end_phys_index(struct device *dev,
|
|
|
+ struct device_attribute *attr, char *buf)
|
|
|
{
|
|
|
struct memory_block *mem =
|
|
|
- container_of(dev, struct memory_block, sysdev);
|
|
|
+ container_of(dev, struct memory_block, dev);
|
|
|
unsigned long phys_index;
|
|
|
|
|
|
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,
|
|
|
/*
|
|
|
* Show whether the section of memory is likely to be hot-removable
|
|
|
*/
|
|
|
-static ssize_t show_mem_removable(struct sys_device *dev,
|
|
|
- struct sysdev_attribute *attr, char *buf)
|
|
|
+static ssize_t show_mem_removable(struct device *dev,
|
|
|
+ struct device_attribute *attr, char *buf)
|
|
|
{
|
|
|
unsigned long i, pfn;
|
|
|
int ret = 1;
|
|
|
struct memory_block *mem =
|
|
|
- container_of(dev, struct memory_block, sysdev);
|
|
|
+ container_of(dev, struct memory_block, dev);
|
|
|
|
|
|
for (i = 0; i < sections_per_block; i++) {
|
|
|
pfn = section_nr_to_pfn(mem->start_section_nr + i);
|
|
@@ -182,11 +164,11 @@ static ssize_t show_mem_removable(struct sys_device *dev,
|
|
|
/*
|
|
|
* online, offline, going offline, etc.
|
|
|
*/
|
|
|
-static ssize_t show_mem_state(struct sys_device *dev,
|
|
|
- struct sysdev_attribute *attr, char *buf)
|
|
|
+static ssize_t show_mem_state(struct device *dev,
|
|
|
+ struct device_attribute *attr, char *buf)
|
|
|
{
|
|
|
struct memory_block *mem =
|
|
|
- container_of(dev, struct memory_block, sysdev);
|
|
|
+ container_of(dev, struct memory_block, dev);
|
|
|
ssize_t len = 0;
|
|
|
|
|
|
/*
|
|
@@ -324,13 +306,13 @@ out:
|
|
|
}
|
|
|
|
|
|
static ssize_t
|
|
|
-store_mem_state(struct sys_device *dev,
|
|
|
- struct sysdev_attribute *attr, const char *buf, size_t count)
|
|
|
+store_mem_state(struct device *dev,
|
|
|
+ struct device_attribute *attr, const char *buf, size_t count)
|
|
|
{
|
|
|
struct memory_block *mem;
|
|
|
int ret = -EINVAL;
|
|
|
|
|
|
- mem = container_of(dev, struct memory_block, sysdev);
|
|
|
+ mem = container_of(dev, struct memory_block, dev);
|
|
|
|
|
|
if (!strncmp(buf, "online", min((int)count, 6)))
|
|
|
ret = memory_block_change_state(mem, MEM_ONLINE, MEM_OFFLINE);
|
|
@@ -351,41 +333,41 @@ store_mem_state(struct sys_device *dev,
|
|
|
* s.t. if I offline all of these sections I can then
|
|
|
* remove the physical device?
|
|
|
*/
|
|
|
-static ssize_t show_phys_device(struct sys_device *dev,
|
|
|
- struct sysdev_attribute *attr, char *buf)
|
|
|
+static ssize_t show_phys_device(struct device *dev,
|
|
|
+ struct device_attribute *attr, char *buf)
|
|
|
{
|
|
|
struct memory_block *mem =
|
|
|
- container_of(dev, struct memory_block, sysdev);
|
|
|
+ container_of(dev, struct memory_block, dev);
|
|
|
return sprintf(buf, "%d\n", mem->phys_device);
|
|
|
}
|
|
|
|
|
|
-static SYSDEV_ATTR(phys_index, 0444, show_mem_start_phys_index, NULL);
|
|
|
-static SYSDEV_ATTR(end_phys_index, 0444, show_mem_end_phys_index, NULL);
|
|
|
-static SYSDEV_ATTR(state, 0644, show_mem_state, store_mem_state);
|
|
|
-static SYSDEV_ATTR(phys_device, 0444, show_phys_device, NULL);
|
|
|
-static SYSDEV_ATTR(removable, 0444, show_mem_removable, NULL);
|
|
|
+static DEVICE_ATTR(phys_index, 0444, show_mem_start_phys_index, NULL);
|
|
|
+static DEVICE_ATTR(end_phys_index, 0444, show_mem_end_phys_index, NULL);
|
|
|
+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);
|
|
|
|
|
|
#define mem_create_simple_file(mem, attr_name) \
|
|
|
- sysdev_create_file(&mem->sysdev, &attr_##attr_name)
|
|
|
+ device_create_file(&mem->dev, &dev_attr_##attr_name)
|
|
|
#define mem_remove_simple_file(mem, attr_name) \
|
|
|
- sysdev_remove_file(&mem->sysdev, &attr_##attr_name)
|
|
|
+ device_remove_file(&mem->dev, &dev_attr_##attr_name)
|
|
|
|
|
|
/*
|
|
|
* Block size attribute stuff
|
|
|
*/
|
|
|
static ssize_t
|
|
|
-print_block_size(struct sysdev_class *class, struct sysdev_class_attribute *attr,
|
|
|
+print_block_size(struct device *dev, struct device_attribute *attr,
|
|
|
char *buf)
|
|
|
{
|
|
|
return sprintf(buf, "%lx\n", get_memory_block_size());
|
|
|
}
|
|
|
|
|
|
-static SYSDEV_CLASS_ATTR(block_size_bytes, 0444, print_block_size, NULL);
|
|
|
+static DEVICE_ATTR(block_size_bytes, 0444, print_block_size, NULL);
|
|
|
|
|
|
static int block_size_init(void)
|
|
|
{
|
|
|
- return sysfs_create_file(&memory_sysdev_class.kset.kobj,
|
|
|
- &attr_block_size_bytes.attr);
|
|
|
+ return device_create_file(memory_subsys.dev_root,
|
|
|
+ &dev_attr_block_size_bytes);
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -396,7 +378,7 @@ static int block_size_init(void)
|
|
|
*/
|
|
|
#ifdef CONFIG_ARCH_MEMORY_PROBE
|
|
|
static ssize_t
|
|
|
-memory_probe_store(struct class *class, struct class_attribute *attr,
|
|
|
+memory_probe_store(struct device *dev, struct device_attribute *attr,
|
|
|
const char *buf, size_t count)
|
|
|
{
|
|
|
u64 phys_addr;
|
|
@@ -423,12 +405,11 @@ memory_probe_store(struct class *class, struct class_attribute *attr,
|
|
|
out:
|
|
|
return ret;
|
|
|
}
|
|
|
-static CLASS_ATTR(probe, S_IWUSR, NULL, memory_probe_store);
|
|
|
+static DEVICE_ATTR(probe, S_IWUSR, NULL, memory_probe_store);
|
|
|
|
|
|
static int memory_probe_init(void)
|
|
|
{
|
|
|
- return sysfs_create_file(&memory_sysdev_class.kset.kobj,
|
|
|
- &class_attr_probe.attr);
|
|
|
+ return device_create_file(memory_subsys.dev_root, &dev_attr_probe);
|
|
|
}
|
|
|
#else
|
|
|
static inline int memory_probe_init(void)
|
|
@@ -444,8 +425,8 @@ static inline int memory_probe_init(void)
|
|
|
|
|
|
/* Soft offline a page */
|
|
|
static ssize_t
|
|
|
-store_soft_offline_page(struct class *class,
|
|
|
- struct class_attribute *attr,
|
|
|
+store_soft_offline_page(struct device *dev,
|
|
|
+ struct device_attribute *attr,
|
|
|
const char *buf, size_t count)
|
|
|
{
|
|
|
int ret;
|
|
@@ -463,8 +444,8 @@ store_soft_offline_page(struct class *class,
|
|
|
|
|
|
/* Forcibly offline a page, including killing processes. */
|
|
|
static ssize_t
|
|
|
-store_hard_offline_page(struct class *class,
|
|
|
- struct class_attribute *attr,
|
|
|
+store_hard_offline_page(struct device *dev,
|
|
|
+ struct device_attribute *attr,
|
|
|
const char *buf, size_t count)
|
|
|
{
|
|
|
int ret;
|
|
@@ -478,18 +459,18 @@ store_hard_offline_page(struct class *class,
|
|
|
return ret ? ret : count;
|
|
|
}
|
|
|
|
|
|
-static CLASS_ATTR(soft_offline_page, 0644, NULL, store_soft_offline_page);
|
|
|
-static CLASS_ATTR(hard_offline_page, 0644, NULL, store_hard_offline_page);
|
|
|
+static DEVICE_ATTR(soft_offline_page, 0644, NULL, store_soft_offline_page);
|
|
|
+static DEVICE_ATTR(hard_offline_page, 0644, NULL, store_hard_offline_page);
|
|
|
|
|
|
static __init int memory_fail_init(void)
|
|
|
{
|
|
|
int err;
|
|
|
|
|
|
- err = sysfs_create_file(&memory_sysdev_class.kset.kobj,
|
|
|
- &class_attr_soft_offline_page.attr);
|
|
|
+ err = device_create_file(memory_subsys.dev_root,
|
|
|
+ &dev_attr_soft_offline_page);
|
|
|
if (!err)
|
|
|
- err = sysfs_create_file(&memory_sysdev_class.kset.kobj,
|
|
|
- &class_attr_hard_offline_page.attr);
|
|
|
+ err = device_create_file(memory_subsys.dev_root,
|
|
|
+ &dev_attr_hard_offline_page);
|
|
|
return err;
|
|
|
}
|
|
|
#else
|
|
@@ -509,31 +490,23 @@ int __weak arch_get_memory_phys_device(unsigned long start_pfn)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * A reference for the returned object is held and the reference for the
|
|
|
+ * hinted object is released.
|
|
|
+ */
|
|
|
struct memory_block *find_memory_block_hinted(struct mem_section *section,
|
|
|
struct memory_block *hint)
|
|
|
{
|
|
|
- struct kobject *kobj;
|
|
|
- struct sys_device *sysdev;
|
|
|
- struct memory_block *mem;
|
|
|
- char name[sizeof(MEMORY_CLASS_NAME) + 9 + 1];
|
|
|
int block_id = base_memory_block_id(__section_nr(section));
|
|
|
+ struct device *hintdev = hint ? &hint->dev : NULL;
|
|
|
+ struct device *dev;
|
|
|
|
|
|
- kobj = hint ? &hint->sysdev.kobj : NULL;
|
|
|
-
|
|
|
- /*
|
|
|
- * This only works because we know that section == sysdev->id
|
|
|
- * slightly redundant with sysdev_register()
|
|
|
- */
|
|
|
- sprintf(&name[0], "%s%d", MEMORY_CLASS_NAME, block_id);
|
|
|
-
|
|
|
- kobj = kset_find_obj_hinted(&memory_sysdev_class.kset, name, kobj);
|
|
|
- if (!kobj)
|
|
|
+ dev = subsys_find_device_by_id(&memory_subsys, block_id, hintdev);
|
|
|
+ if (hint)
|
|
|
+ put_device(&hint->dev);
|
|
|
+ if (!dev)
|
|
|
return NULL;
|
|
|
-
|
|
|
- sysdev = container_of(kobj, struct sys_device, kobj);
|
|
|
- mem = container_of(sysdev, struct memory_block, sysdev);
|
|
|
-
|
|
|
- return mem;
|
|
|
+ return container_of(dev, struct memory_block, dev);
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -542,7 +515,7 @@ struct memory_block *find_memory_block_hinted(struct mem_section *section,
|
|
|
* this gets to be a real problem, we can always use a radix
|
|
|
* tree or something here.
|
|
|
*
|
|
|
- * This could be made generic for all sysdev classes.
|
|
|
+ * This could be made generic for all device subsystems.
|
|
|
*/
|
|
|
struct memory_block *find_memory_block(struct mem_section *section)
|
|
|
{
|
|
@@ -598,7 +571,7 @@ static int add_memory_section(int nid, struct mem_section *section,
|
|
|
mem = find_memory_block(section);
|
|
|
if (mem) {
|
|
|
mem->section_count++;
|
|
|
- kobject_put(&mem->sysdev.kobj);
|
|
|
+ kobject_put(&mem->dev.kobj);
|
|
|
} else
|
|
|
ret = init_memory_block(&mem, section, state);
|
|
|
|
|
@@ -631,7 +604,7 @@ int remove_memory_block(unsigned long node_id, struct mem_section *section,
|
|
|
unregister_memory(mem);
|
|
|
kfree(mem);
|
|
|
} else
|
|
|
- kobject_put(&mem->sysdev.kobj);
|
|
|
+ kobject_put(&mem->dev.kobj);
|
|
|
|
|
|
mutex_unlock(&mem_sysfs_mutex);
|
|
|
return 0;
|
|
@@ -664,8 +637,7 @@ int __init memory_dev_init(void)
|
|
|
int err;
|
|
|
unsigned long block_sz;
|
|
|
|
|
|
- memory_sysdev_class.kset.uevent_ops = &memory_uevent_ops;
|
|
|
- ret = sysdev_class_register(&memory_sysdev_class);
|
|
|
+ ret = subsys_system_register(&memory_subsys, NULL);
|
|
|
if (ret)
|
|
|
goto out;
|
|
|
|