@@ -10,6 +10,7 @@
*
*/
+#include <linux/cpu.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/init.h>
@@ -742,6 +743,12 @@ static struct kobject *get_device_parent(struct device *dev,
return &block_class.p->subsys.kobj;
}
#endif
+ /*
+ * if the device is in cpu class, then use the default/legacy
+ * /sys/devices/system/cpu/.. path
+ */
+ if (dev->class == cpu_class)
+ return &parent->kobj;
/*
* If we have no parent, we live in "virtual".
@@ -808,11 +815,17 @@ static int device_add_class_symlinks(struct device *dev)
if (!dev->class)
return 0;
- error = sysfs_create_link(&dev->kobj,
- &dev->class->p->subsys.kobj,
- "subsystem");
- if (error)
- goto out;
+ /*
+ * the subsystem symlink in each cpu device needs to continue
+ * pointing to cpu bus
+ */
+ if (dev->bus != &cpu_subsys) {
+ error = sysfs_create_link(&dev->kobj,
+ &dev->class->p->subsys.kobj,
+ "subsystem");
+ if (error)
+ goto out;
+ }
if (dev->parent && device_is_not_partition(dev)) {
error = sysfs_create_link(&dev->kobj, &dev->parent->kobj,
@@ -826,6 +839,13 @@ static int device_add_class_symlinks(struct device *dev)
if (sysfs_deprecated && dev->class == &block_class)
return 0;
#endif
+ /*
+ * don't create a link in the cpu class directory pointing to the
+ * device as there would be per-cpu instance of these devices with
+ * the same name
+ */
+ if (dev->class == cpu_class)
+ return 0;
/* link in the class directory pointing to the device */
error = sysfs_create_link(&dev->class->p->subsys.kobj,
@@ -851,11 +871,18 @@ static void device_remove_class_symlinks(struct device *dev)
if (dev->parent && device_is_not_partition(dev))
sysfs_remove_link(&dev->kobj, "device");
- sysfs_remove_link(&dev->kobj, "subsystem");
+
+ /* if subsystem points to cpu bus, bus_remove_device will remove it */
+ if (dev->bus != &cpu_subsys)
+ sysfs_remove_link(&dev->kobj, "subsystem");
#ifdef CONFIG_BLOCK
if (sysfs_deprecated && dev->class == &block_class)
return;
#endif
+ /* symlinks are not created for cpu class devices, nothing to remove */
+ if (dev->class == cpu_class)
+ return;
+
sysfs_delete_link(&dev->class->p->subsys.kobj, &dev->kobj, dev_name(dev));
}
@@ -322,6 +322,7 @@ static int cpu_uevent(struct device *dev, struct kobj_uevent_env *env)
}
#endif
+struct class *cpu_class;
/*
* register_cpu - Setup a sysfs device for a CPU.
* @cpu - cpu->hotpluggable field set to 1 will generate a control file in
@@ -338,6 +339,8 @@ int register_cpu(struct cpu *cpu, int num)
memset(&cpu->dev, 0x00, sizeof(struct device));
cpu->dev.id = num;
cpu->dev.bus = &cpu_subsys;
+ cpu->dev.parent = cpu_subsys.dev_root;
+ cpu->dev.class = cpu_class;
cpu->dev.release = cpu_device_release;
cpu->dev.offline_disabled = !cpu->hotpluggable;
cpu->dev.offline = !cpu_online(num);
@@ -423,5 +426,9 @@ void __init cpu_dev_init(void)
if (subsys_system_register(&cpu_subsys, cpu_root_attr_groups))
panic("Failed to register CPU subsystem");
+ cpu_class = class_create(THIS_MODULE, "cpu");
+ if (IS_ERR(cpu_class))
+ panic("Failed to register CPU class");
+
cpu_dev_register_generic();
}
@@ -39,6 +39,8 @@ extern void cpu_remove_dev_attr(struct device_attribute *attr);
extern int cpu_add_dev_attr_group(struct attribute_group *attrs);
extern void cpu_remove_dev_attr_group(struct attribute_group *attrs);
+extern struct class *cpu_class;
+
#ifdef CONFIG_HOTPLUG_CPU
extern void unregister_cpu(struct cpu *cpu);
extern ssize_t arch_cpu_probe(const char *, size_t);