summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@home.transmeta.com>2003-06-10 01:46:36 -0700
committerLinus Torvalds <torvalds@home.transmeta.com>2003-06-10 01:46:36 -0700
commitb7f523b5dfd0cc3ca3209e8f6d0519ee63bd8bf6 (patch)
tree8bf659f35245772aa42c797443947652fe6e2afc
parent201be7ab47dce6e31d8b8599abf24a72cb7a37ce (diff)
parent6508e77cc78d7abb04617bec00de21218e7d6df8 (diff)
Merge bk://ldm.bkbits.net/linux-2.5-core
into home.transmeta.com:/home/torvalds/v2.5/linux
-rw-r--r--arch/arm/kernel/pm.c8
-rw-r--r--arch/i386/kernel/apic.c45
-rw-r--r--arch/i386/kernel/cpu/mtrr/main.c60
-rw-r--r--arch/i386/kernel/i8259.c62
-rw-r--r--arch/i386/kernel/nmi.c38
-rw-r--r--arch/i386/kernel/time.c16
-rw-r--r--arch/i386/oprofile/nmi_int.c33
-rw-r--r--arch/x86_64/kernel/i8259.c28
-rw-r--r--drivers/base/cpu.c46
-rw-r--r--drivers/base/memblk.c31
-rw-r--r--drivers/base/node.c41
-rw-r--r--drivers/base/power.c43
-rw-r--r--drivers/base/sys.c467
-rw-r--r--drivers/s390/block/xpram.c23
-rw-r--r--fs/sysfs/file.c4
-rw-r--r--include/linux/cpu.h5
-rw-r--r--include/linux/cpufreq.h4
-rw-r--r--include/linux/device.h24
-rw-r--r--include/linux/kobject.h8
-rw-r--r--include/linux/list.h14
-rw-r--r--include/linux/node.h4
-rw-r--r--include/linux/sysdev.h98
-rw-r--r--kernel/cpufreq.c83
23 files changed, 792 insertions, 393 deletions
diff --git a/arch/arm/kernel/pm.c b/arch/arm/kernel/pm.c
index 03fcb771b579..e80142d9304b 100644
--- a/arch/arm/kernel/pm.c
+++ b/arch/arm/kernel/pm.c
@@ -11,7 +11,6 @@
#include <linux/config.h>
#include <linux/pm.h>
#include <linux/device.h>
-#include <linux/cpufreq.h>
#include <asm/leds.h>
#include <asm/system.h>
@@ -67,13 +66,6 @@ int suspend(void)
device_resume(RESUME_POWER_ON);
/*
- * Restore the CPU frequency settings.
- */
-#ifdef CONFIG_CPU_FREQ
- cpufreq_restore();
-#endif
-
- /*
* Resume LDM devices.
*/
device_resume(RESUME_RESTORE_STATE);
diff --git a/arch/i386/kernel/apic.c b/arch/i386/kernel/apic.c
index 3f1216c60f44..00d1a2ba56a1 100644
--- a/arch/i386/kernel/apic.c
+++ b/arch/i386/kernel/apic.c
@@ -25,6 +25,9 @@
#include <linux/interrupt.h>
#include <linux/mc146818rtc.h>
#include <linux/kernel_stat.h>
+#include <linux/sysdev.h>
+#include <linux/module.h>
+
#include <asm/atomic.h>
#include <asm/smp.h>
@@ -460,9 +463,6 @@ void __init setup_local_APIC (void)
#ifdef CONFIG_PM
-#include <linux/device.h>
-#include <linux/module.h>
-
static struct {
/* 'active' is true if the local APIC was enabled by us and
not the BIOS; this signifies that we are also responsible
@@ -484,13 +484,11 @@ static struct {
unsigned int apic_thmr;
} apic_pm_state;
-static int lapic_suspend(struct device *dev, u32 state, u32 level)
+static int lapic_suspend(struct sys_device *dev, u32 state)
{
unsigned int l, h;
unsigned long flags;
- if (level != SUSPEND_POWER_DOWN)
- return 0;
if (!apic_pm_state.active)
return 0;
@@ -517,13 +515,11 @@ static int lapic_suspend(struct device *dev, u32 state, u32 level)
return 0;
}
-static int lapic_resume(struct device *dev, u32 level)
+static int lapic_resume(struct sys_device *dev)
{
unsigned int l, h;
unsigned long flags;
- if (level != RESUME_POWER_ON)
- return 0;
if (!apic_pm_state.active)
return 0;
@@ -557,38 +553,37 @@ static int lapic_resume(struct device *dev, u32 level)
return 0;
}
-static struct device_driver lapic_driver = {
- .name = "lapic",
- .bus = &system_bus_type,
+
+static struct sysdev_class lapic_sysclass = {
+ set_kset_name("lapic"),
.resume = lapic_resume,
.suspend = lapic_suspend,
};
-/* not static, needed by child devices */
-struct sys_device device_lapic = {
- .name = "lapic",
- .id = 0,
- .dev = {
- .name = "lapic",
- .driver = &lapic_driver,
- },
+static struct sys_device device_lapic = {
+ .id = 0,
+ .cls = &lapic_sysclass,
};
-EXPORT_SYMBOL(device_lapic);
static void __init apic_pm_activate(void)
{
apic_pm_state.active = 1;
}
-static int __init init_lapic_devicefs(void)
+static int __init init_lapic_sysfs(void)
{
+ int error;
+
if (!cpu_has_apic)
return 0;
/* XXX: remove suspend/resume procs if !apic_pm_state.active? */
- driver_register(&lapic_driver);
- return sys_device_register(&device_lapic);
+
+ error = sysdev_class_register(&lapic_sysclass);
+ if (!error)
+ error = sys_device_register(&device_lapic);
+ return error;
}
-device_initcall(init_lapic_devicefs);
+device_initcall(init_lapic_sysfs);
#else /* CONFIG_PM */
diff --git a/arch/i386/kernel/cpu/mtrr/main.c b/arch/i386/kernel/cpu/mtrr/main.c
index 5b82d52983db..3db7d11848a4 100644
--- a/arch/i386/kernel/cpu/mtrr/main.c
+++ b/arch/i386/kernel/cpu/mtrr/main.c
@@ -35,6 +35,7 @@
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/smp.h>
+#include <linux/cpu.h>
#include <asm/mtrr.h>
@@ -546,6 +547,58 @@ static void init_other_cpus(void)
}
}
+
+struct mtrr_value {
+ mtrr_type ltype;
+ unsigned long lbase;
+ unsigned int lsize;
+};
+
+static struct mtrr_value * mtrr_state;
+
+static int mtrr_save(struct sys_device * sysdev, u32 state)
+{
+ int i;
+ int size = num_var_ranges * sizeof(struct mtrr_value);
+
+ mtrr_state = kmalloc(size,GFP_KERNEL);
+ if (mtrr_state)
+ memset(mtrr_state,0,size);
+ else
+ return -ENOMEM;
+
+ for (i = 0; i < num_var_ranges; i++) {
+ mtrr_if->get(i,
+ &mtrr_state[i].lbase,
+ &mtrr_state[i].lsize,
+ &mtrr_state[i].ltype);
+ }
+ return 0;
+}
+
+static int mtrr_restore(struct sys_device * sysdev)
+{
+ int i;
+
+ for (i = 0; i < num_var_ranges; i++) {
+ if (mtrr_state[i].lsize)
+ set_mtrr(i,
+ mtrr_state[i].lbase,
+ mtrr_state[i].lsize,
+ mtrr_state[i].ltype);
+ }
+ kfree(mtrr_state);
+ return 0;
+}
+
+
+
+static struct sysdev_driver mtrr_sysdev_driver = {
+ .save = mtrr_save,
+ .restore = mtrr_restore,
+};
+
+
/**
* mtrr_init - initialie mtrrs on the boot CPU
*
@@ -630,8 +683,11 @@ static int __init mtrr_init(void)
set_num_var_ranges();
init_table();
init_other_cpus();
+
+ return sysdev_driver_register(&cpu_sysdev_class,
+ &mtrr_sysdev_driver);
}
- return mtrr_if ? -ENXIO : 0;
+ return -ENXIO;
}
char *mtrr_strings[MTRR_NUM_TYPES] =
@@ -645,5 +701,5 @@ char *mtrr_strings[MTRR_NUM_TYPES] =
"write-back", /* 6 */
};
-core_initcall(mtrr_init);
+subsys_initcall(mtrr_init);
diff --git a/arch/i386/kernel/i8259.c b/arch/i386/kernel/i8259.c
index fb6d35da09e7..bc1268725f34 100644
--- a/arch/i386/kernel/i8259.c
+++ b/arch/i386/kernel/i8259.c
@@ -10,7 +10,7 @@
#include <linux/smp_lock.h>
#include <linux/init.h>
#include <linux/kernel_stat.h>
-#include <linux/device.h>
+#include <linux/sysdev.h>
#include <asm/atomic.h>
#include <asm/system.h>
@@ -238,35 +238,31 @@ spurious_8259A_irq:
}
}
-static int i8259A_resume(struct device *dev, u32 level)
+static int i8259A_resume(struct sys_device *dev)
{
- if (level == RESUME_POWER_ON)
- init_8259A(0);
+ init_8259A(0);
return 0;
}
-static struct device_driver i8259A_driver = {
- .name = "pic",
- .bus = &system_bus_type,
- .resume = i8259A_resume,
+static struct sysdev_class i8259_sysdev_class = {
+ set_kset_name("i8259"),
+ .resume = i8259A_resume,
};
static struct sys_device device_i8259A = {
- .name = "pic",
- .id = 0,
- .dev = {
- .name = "i8259A PIC",
- .driver = &i8259A_driver,
- },
+ .id = 0,
+ .cls = &i8259_sysdev_class,
};
-static int __init init_8259A_devicefs(void)
+static int __init i8259A_init_sysfs(void)
{
- driver_register(&i8259A_driver);
- return sys_device_register(&device_i8259A);
+ int error = sysdev_class_register(&i8259_sysdev_class);
+ if (!error)
+ error = sys_device_register(&device_i8259A);
+ return error;
}
-device_initcall(init_8259A_devicefs);
+device_initcall(i8259A_init_sysfs);
void init_8259A(int auto_eoi)
{
@@ -385,35 +381,31 @@ static void setup_timer(void)
spin_unlock_irqrestore(&i8253_lock, flags);
}
-static int timer_resume(struct device *dev, u32 level)
+static int timer_resume(struct sys_device *dev)
{
- if (level == RESUME_POWER_ON)
- setup_timer();
+ setup_timer();
return 0;
}
-static struct device_driver timer_driver = {
- .name = "timer",
- .bus = &system_bus_type,
- .resume = timer_resume,
+static struct sysdev_class timer_sysclass = {
+ set_kset_name("timer"),
+ .resume = timer_resume,
};
static struct sys_device device_timer = {
- .name = "timer",
- .id = 0,
- .dev = {
- .name = "timer",
- .driver = &timer_driver,
- },
+ .id = 0,
+ .cls = &timer_sysclass,
};
-static int __init init_timer_devicefs(void)
+static int __init init_timer_sysfs(void)
{
- driver_register(&timer_driver);
- return sys_device_register(&device_timer);
+ int error = sysdev_class_register(&timer_sysclass);
+ if (!error)
+ error = sys_device_register(&device_timer);
+ return error;
}
-device_initcall(init_timer_devicefs);
+device_initcall(init_timer_sysfs);
void __init init_IRQ(void)
{
diff --git a/arch/i386/kernel/nmi.c b/arch/i386/kernel/nmi.c
index e8910adcd6bb..656eb3bcff58 100644
--- a/arch/i386/kernel/nmi.c
+++ b/arch/i386/kernel/nmi.c
@@ -23,6 +23,7 @@
#include <linux/mc146818rtc.h>
#include <linux/kernel_stat.h>
#include <linux/module.h>
+#include <linux/sysdev.h>
#include <asm/smp.h>
#include <asm/mtrr.h>
@@ -180,53 +181,48 @@ void enable_lapic_nmi_watchdog(void)
#ifdef CONFIG_PM
-#include <linux/device.h>
static int nmi_pm_active; /* nmi_active before suspend */
-static int lapic_nmi_suspend(struct device *dev, u32 state, u32 level)
+static int lapic_nmi_suspend(struct sys_device *dev, u32 state)
{
- if (level != SUSPEND_POWER_DOWN)
- return 0;
nmi_pm_active = nmi_active;
disable_lapic_nmi_watchdog();
return 0;
}
-static int lapic_nmi_resume(struct device *dev, u32 level)
+static int lapic_nmi_resume(struct sys_device *dev)
{
- if (level != RESUME_POWER_ON)
- return 0;
if (nmi_pm_active > 0)
enable_lapic_nmi_watchdog();
return 0;
}
-static struct device_driver lapic_nmi_driver = {
- .name = "lapic_nmi",
- .bus = &system_bus_type,
+
+static struct sysdev_class nmi_sysclass = {
+ set_kset_name("lapic_nmi"),
.resume = lapic_nmi_resume,
.suspend = lapic_nmi_suspend,
};
static struct sys_device device_lapic_nmi = {
- .name = "lapic_nmi",
- .id = 0,
- .dev = {
- .name = "lapic_nmi",
- .driver = &lapic_nmi_driver,
- .parent = &device_lapic.dev,
- },
+ .id = 0,
+ .cls = &nmi_sysclass,
};
-static int __init init_lapic_nmi_devicefs(void)
+static int __init init_lapic_nmi_sysfs(void)
{
+ int error;
+
if (nmi_active == 0)
return 0;
- driver_register(&lapic_nmi_driver);
- return sys_device_register(&device_lapic_nmi);
+
+ error = sysdev_class_register(&nmi_sysclass);
+ if (!error)
+ error = sys_device_register(&device_lapic_nmi);
+ return error;
}
/* must come after the local APIC's device_initcall() */
-late_initcall(init_lapic_nmi_devicefs);
+late_initcall(init_lapic_nmi_sysfs);
#endif /* CONFIG_PM */
diff --git a/arch/i386/kernel/time.c b/arch/i386/kernel/time.c
index 2acbd3d6b0b3..13a6b41ddcd8 100644
--- a/arch/i386/kernel/time.c
+++ b/arch/i386/kernel/time.c
@@ -42,7 +42,7 @@
#include <linux/init.h>
#include <linux/smp.h>
#include <linux/module.h>
-#include <linux/device.h>
+#include <linux/sysdev.h>
#include <linux/bcd.h>
#include <asm/io.h>
@@ -278,18 +278,22 @@ unsigned long get_cmos_time(void)
return retval;
}
+static struct sysdev_class rtc_sysclass = {
+ set_kset_name("rtc"),
+};
+
/* XXX this driverfs stuff should probably go elsewhere later -john */
static struct sys_device device_i8253 = {
- .name = "rtc",
.id = 0,
- .dev = {
- .name = "i8253 Real Time Clock",
- },
+ .cls = &rtc_sysclass,
};
static int time_init_device(void)
{
- return sys_device_register(&device_i8253);
+ int error = sysdev_class_register(&rtc_sysclass);
+ if (!error)
+ error = sys_device_register(&device_i8253);
+ return error;
}
device_initcall(time_init_device);
diff --git a/arch/i386/oprofile/nmi_int.c b/arch/i386/oprofile/nmi_int.c
index b6841b98a3ac..030f0fa8c45a 100644
--- a/arch/i386/oprofile/nmi_int.c
+++ b/arch/i386/oprofile/nmi_int.c
@@ -11,7 +11,7 @@
#include <linux/notifier.h>
#include <linux/smp.h>
#include <linux/oprofile.h>
-#include <linux/device.h>
+#include <linux/sysdev.h>
#include <asm/nmi.h>
#include <asm/msr.h>
#include <asm/apic.h>
@@ -31,53 +31,48 @@ static int nmi_enabled = 0;
#ifdef CONFIG_PM
-static int nmi_suspend(struct device *dev, u32 state, u32 level)
+static int nmi_suspend(struct sys_device *dev, u32 state)
{
- if (level != SUSPEND_POWER_DOWN)
- return 0;
if (nmi_enabled == 1)
nmi_stop();
return 0;
}
-static int nmi_resume(struct device *dev, u32 level)
+static int nmi_resume(struct sys_device *dev)
{
- if (level != RESUME_POWER_ON)
- return 0;
if (nmi_enabled == 1)
nmi_start();
return 0;
}
-static struct device_driver nmi_driver = {
- .name = "oprofile",
- .bus = &system_bus_type,
+static struct sysdev_class oprofile_sysclass = {
+ set_kset_name("oprofile"),
.resume = nmi_resume,
.suspend = nmi_suspend,
};
-static struct device device_nmi = {
- .name = "oprofile",
- .bus_id = "oprofile",
- .driver = &nmi_driver,
- .parent = &device_lapic.dev,
+static struct sys_device device_oprofile = {
+ .id = 0,
+ .cls = &oprofile_sysclass,
};
static int __init init_driverfs(void)
{
- driver_register(&nmi_driver);
- return device_register(&device_nmi);
+ int error;
+ if (!(error = sysdev_class_register(&oprofile_sysclass)))
+ error = sys_device_register(&device_oprofile);
+ return error;
}
static void __exit exit_driverfs(void)
{
- device_unregister(&device_nmi);
- driver_unregister(&nmi_driver);
+ sys_device_unregister(&device_oprofile);
+ sysdev_class_unregister(&oprofile_sysclass);
}
#else
diff --git a/arch/x86_64/kernel/i8259.c b/arch/x86_64/kernel/i8259.c
index 61eb01ca8716..ce6ea7a396be 100644
--- a/arch/x86_64/kernel/i8259.c
+++ b/arch/x86_64/kernel/i8259.c
@@ -11,7 +11,7 @@
#include <linux/smp_lock.h>
#include <linux/init.h>
#include <linux/kernel_stat.h>
-#include <linux/device.h>
+#include <linux/sysdev.h>
#include <asm/atomic.h>
#include <asm/system.h>
@@ -413,35 +413,31 @@ static void setup_timer(void)
outb(LATCH >> 8 , 0x40); /* MSB */
}
-static int timer_resume(struct device *dev, u32 level)
+static int timer_resume(struct sys_device *dev)
{
- if (level == RESUME_POWER_ON)
- setup_timer();
+ setup_timer();
return 0;
}
-static struct device_driver timer_driver = {
- .name = "timer",
- .bus = &system_bus_type,
+static struct sysdev_class timer_sysclass = {
+ set_kset_name("timer"),
.resume = timer_resume,
};
static struct sys_device device_timer = {
- .name = "timer",
.id = 0,
- .dev = {
- .name = "timer",
- .driver = &timer_driver,
- },
+ .cls &timer_sysclass,
};
-static int __init init_timer_devicefs(void)
+static int __init init_timer_sysfs(void)
{
- driver_register(&timer_driver);
- return sys_device_register(&device_timer);
+ int error = sysdev_class_register(&timer_sysclass);
+ if (!error)
+ error = sys_device_register(&device_timer);
+ return error;
}
-device_initcall(init_timer_devicefs);
+device_initcall(init_timer_sysfs);
void __init init_IRQ(void)
{
diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c
index 78a9f57e48f3..4456bceabeaf 100644
--- a/drivers/base/cpu.c
+++ b/drivers/base/cpu.c
@@ -2,23 +2,18 @@
* drivers/base/cpu.c - basic CPU class support
*/
-#include <linux/device.h>
+#include <linux/sysdev.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/cpu.h>
#include <linux/topology.h>
-struct class cpu_class = {
- .name = "cpu",
+struct sysdev_class cpu_sysdev_class = {
+ set_kset_name("cpu"),
};
-struct device_driver cpu_driver = {
- .name = "cpu",
- .bus = &system_bus_type,
-};
-
/*
* register_cpu - Setup a driverfs device for a CPU.
* @num - CPU number to use when creating the device.
@@ -27,42 +22,15 @@ struct device_driver cpu_driver = {
*/
int __init register_cpu(struct cpu *cpu, int num, struct node *root)
{
- int retval;
-
cpu->node_id = cpu_to_node(num);
- cpu->sysdev.name = "cpu";
cpu->sysdev.id = num;
- if (root)
- cpu->sysdev.root = &root->sysroot;
- snprintf(cpu->sysdev.dev.name, DEVICE_NAME_SIZE, "CPU %u", num);
- cpu->sysdev.dev.driver = &cpu_driver;
- retval = sys_device_register(&cpu->sysdev);
- if (retval)
- return retval;
- memset(&cpu->sysdev.class_dev, 0x00, sizeof(struct class_device));
- cpu->sysdev.class_dev.dev = &cpu->sysdev.dev;
- cpu->sysdev.class_dev.class = &cpu_class;
- snprintf(cpu->sysdev.class_dev.class_id, BUS_ID_SIZE, "cpu%d", num);
- retval = class_device_register(&cpu->sysdev.class_dev);
- if (retval) {
- sys_device_unregister(&cpu->sysdev);
- return retval;
- }
- return 0;
+ cpu->sysdev.cls = &cpu_sysdev_class;
+ return sys_device_register(&cpu->sysdev);
}
+
int __init cpu_dev_init(void)
{
- int error;
-
- error = class_register(&cpu_class);
- if (error)
- goto out;
-
- error = driver_register(&cpu_driver);
- if (error)
- class_unregister(&cpu_class);
-out:
- return error;
+ return sysdev_class_register(&cpu_sysdev_class);
}
diff --git a/drivers/base/memblk.c b/drivers/base/memblk.c
index cbaa98b3dce1..f3f3fdf7292c 100644
--- a/drivers/base/memblk.c
+++ b/drivers/base/memblk.c
@@ -2,7 +2,6 @@
* drivers/base/memblk.c - basic Memory Block class support
*/
-#include <linux/device.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/memblk.h>
@@ -10,8 +9,8 @@
#include <linux/topology.h>
-static struct class memblk_class = {
- .name = "memblk",
+static struct sysdev_class memblk_class = {
+ set_kset_name("memblk"),
};
@@ -29,27 +28,23 @@ static struct device_driver memblk_driver = {
*/
int __init register_memblk(struct memblk *memblk, int num, struct node *root)
{
+ int error;
+
memblk->node_id = memblk_to_node(num);
- memblk->sysdev.name = "memblk";
+ memblk->sysdev.cls = &memblk_class,
memblk->sysdev.id = num;
- if (root)
- memblk->sysdev.root = &root->sysroot;
- snprintf(memblk->sysdev.dev.name, DEVICE_NAME_SIZE, "Memory Block %u", num);
- memblk->sysdev.dev.driver = &memblk_driver;
- return sys_device_register(&memblk->sysdev);
+
+ error = sys_device_register(&memblk->sysdev);
+ if (!error)
+ error = sysfs_create_link(&root->sysdev.kobj,
+ &memblk->sysdev,kobj,
+ memblk->sysdev.kobj.name);
+ return error;
}
int __init register_memblk_type(void)
{
- int error;
-
- error = class_register(&memblk_class);
- if (!error) {
- error = driver_register(&memblk_driver);
- if (error)
- class_unregister(&memblk_class);
- }
- return error;
+ return sysdev_class_register(&memblk_class);
}
postcore_initcall(register_memblk_type);
diff --git a/drivers/base/node.c b/drivers/base/node.c
index 2f77b0afb862..08e7c52c68e6 100644
--- a/drivers/base/node.c
+++ b/drivers/base/node.c
@@ -9,15 +9,8 @@
#include <linux/node.h>
#include <linux/topology.h>
-
-static struct class node_class = {
- .name = "node",
-};
-
-
-static struct device_driver node_driver = {
- .name = "node",
- .bus = &system_bus_type,
+static struct sysdev_class node_class = {
+ set_kset_name("node"),
};
@@ -26,7 +19,7 @@ static ssize_t node_read_cpumap(struct device * dev, char * buf)
struct node *node_dev = to_node(to_root(dev));
return sprintf(buf,"%lx\n",node_dev->cpumap);
}
-static DEVICE_ATTR(cpumap,S_IRUGO,node_read_cpumap,NULL);
+static SYSDEV_ATTR(cpumap,S_IRUGO,node_read_cpumap,NULL);
#define K(x) ((x) << (PAGE_SHIFT - 10))
static ssize_t node_read_meminfo(struct device * dev, char * buf)
@@ -52,7 +45,7 @@ static ssize_t node_read_meminfo(struct device * dev, char * buf)
nid, K(i.freeram-i.freehigh));
}
#undef K
-static DEVICE_ATTR(meminfo,S_IRUGO,node_read_meminfo,NULL);
+static SYSDEV_ATTR(meminfo,S_IRUGO,node_read_meminfo,NULL);
/*
@@ -66,17 +59,13 @@ int __init register_node(struct node *node, int num, struct node *parent)
int error;
node->cpumap = node_to_cpumask(num);
- node->sysroot.id = num;
- if (parent)
- node->sysroot.dev.parent = &parent->sysroot.sysdev;
- snprintf(node->sysroot.dev.name, DEVICE_NAME_SIZE, "Node %u", num);
- snprintf(node->sysroot.dev.bus_id, BUS_ID_SIZE, "node%u", num);
- node->sysroot.dev.driver = &node_driver;
- node->sysroot.dev.bus = &system_bus_type;
- error = sys_register_root(&node->sysroot);
+ node->sysdev.id = num;
+ node->sysdev.cls = &node_class;
+ error = sys_device_register(&node->sysdev);
+
if (!error){
- device_create_file(&node->sysroot.dev, &dev_attr_cpumap);
- device_create_file(&node->sysroot.dev, &dev_attr_meminfo);
+ sys_device_create_file(&node->sysroot.dev, &attr_cpumap);
+ sys_device_create_file(&node->sysroot.dev, &attr_meminfo);
}
return error;
}
@@ -84,14 +73,6 @@ int __init register_node(struct node *node, int num, struct node *parent)
int __init register_node_type(void)
{
- int error;
-
- error = class_register(&node_class);
- if (!error) {
- error = driver_register(&node_driver);
- if (error)
- class_unregister(&node_class);
- }
- return error;
+ return sysdev_class_register(&node_class);
}
postcore_initcall(register_node_type);
diff --git a/drivers/base/power.c b/drivers/base/power.c
index e389891c574d..7f5a6abc4e00 100644
--- a/drivers/base/power.c
+++ b/drivers/base/power.c
@@ -22,6 +22,21 @@
extern struct subsystem devices_subsys;
/**
+ * We handle system devices differently - we suspend and shut them
+ * down first and resume them first. That way, we do anything stupid like
+ * shutting down the interrupt controller before any devices..
+ *
+ * Note that there are not different stages for power management calls -
+ * they only get one called once when interrupts are disabled.
+ */
+
+extern int sysdev_shutdown(void);
+extern int sysdev_save(u32 state);
+extern int sysdev_suspend(u32 state);
+extern int sysdev_resume(void);
+extern int sysdev_restore(void);
+
+/**
* device_suspend - suspend/remove all devices on the device ree
* @state: state we're entering
* @level: what stage of the suspend process we're at
@@ -50,6 +65,21 @@ int device_suspend(u32 state, u32 level)
}
}
up_write(&devices_subsys.rwsem);
+
+ /*
+ * Make sure system devices are suspended.
+ */
+ switch(level) {
+ case SUSPEND_SAVE_STATE:
+ sysdev_save(state);
+ break;
+ case SUSPEND_POWER_DOWN:
+ sysdev_suspend(state);
+ break;
+ default:
+ break;
+ }
+
return error;
}
@@ -65,6 +95,17 @@ void device_resume(u32 level)
{
struct list_head * node;
+ switch (level) {
+ case RESUME_POWER_ON:
+ sysdev_resume();
+ break;
+ case RESUME_RESTORE_STATE:
+ sysdev_restore();
+ break;
+ default:
+ break;
+ }
+
down_write(&devices_subsys.rwsem);
list_for_each_prev(node,&devices_subsys.kset.list) {
struct device * dev = to_dev(node);
@@ -98,6 +139,8 @@ void device_shutdown(void)
pr_debug("Ignored.\n");
}
up_write(&devices_subsys.rwsem);
+
+ sysdev_shutdown();
}
EXPORT_SYMBOL(device_suspend);
diff --git a/drivers/base/sys.c b/drivers/base/sys.c
index 5ae457170548..34001cb52fa1 100644
--- a/drivers/base/sys.c
+++ b/drivers/base/sys.c
@@ -12,9 +12,9 @@
* add themselves as children of the system bus.
*/
-#undef DEBUG
+#define DEBUG
-#include <linux/device.h>
+#include <linux/sysdev.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/kernel.h>
@@ -22,130 +22,435 @@
#include <linux/slab.h>
#include <linux/string.h>
-/* The default system device parent. */
-static struct device system_bus = {
- .name = "System Bus",
- .bus_id = "sys",
+
+extern struct subsystem devices_subsys;
+
+#define to_sysdev(k) container_of(k,struct sys_device,kobj)
+#define to_sysdev_attr(a) container_of(a,struct sysdev_attribute,attr)
+
+
+static ssize_t
+sysdev_show(struct kobject * kobj, struct attribute * attr, char * buffer)
+{
+ struct sys_device * sysdev = to_sysdev(kobj);
+ struct sysdev_attribute * sysdev_attr = to_sysdev_attr(attr);
+
+ if (sysdev_attr->show)
+ return sysdev_attr->show(sysdev,buffer);
+ return 0;
+}
+
+
+static ssize_t
+sysdev_store(struct kobject * kobj, struct attribute * attr,
+ const char * buffer, size_t count)
+{
+ struct sys_device * sysdev = to_sysdev(kobj);
+ struct sysdev_attribute * sysdev_attr = to_sysdev_attr(attr);
+
+ if (sysdev_attr->store)
+ return sysdev_attr->store(sysdev,buffer,count);
+ return 0;
+}
+
+static struct sysfs_ops sysfs_ops = {
+ .show = sysdev_show,
+ .store = sysdev_store,
+};
+
+static struct kobj_type ktype_sysdev = {
+ .sysfs_ops = &sysfs_ops,
};
+/*
+ * declare system_subsys
+ */
+decl_subsys(system,&ktype_sysdev,NULL);
+
+int sysdev_class_register(struct sysdev_class * cls)
+{
+ pr_debug("Registering sysdev class '%s'\n",cls->kset.kobj.name);
+ INIT_LIST_HEAD(&cls->drivers);
+ cls->kset.subsys = &system_subsys;
+ kset_set_kset_s(cls,system_subsys);
+ return kset_register(&cls->kset);
+}
+
+void sysdev_class_unregister(struct sysdev_class * cls)
+{
+ pr_debug("Unregistering sysdev class '%s'\n",cls->kset.kobj.name);
+ kset_unregister(&cls->kset);
+}
+
+EXPORT_SYMBOL(sysdev_class_register);
+EXPORT_SYMBOL(sysdev_class_unregister);
+
+
+static LIST_HEAD(global_drivers);
/**
- * sys_register_root - add a subordinate system root
- * @root: new root
- *
- * This is for NUMA-like systems so they can accurately
- * represent the topology of the entire system.
- * As boards are discovered, a new struct sys_root should
- * be allocated and registered.
- * The discovery mechanism should initialize the id field
- * of the struture, as well as much of the embedded device
- * structure as possible, inlcuding the name, the bus_id
- * and parent fields.
+ * sysdev_driver_register - Register auxillary driver
+ * @cls: Device class driver belongs to.
+ * @drv: Driver.
*
- * This simply calls device_register on the embedded device.
- * On success, it will use the struct @root->sysdev
- * device to create a pseudo-parent for system devices
- * on that board.
+ * If @cls is valid, then @drv is inserted into @cls->drivers to be
+ * called on each operation on devices of that class. The refcount
+ * of @cls is incremented.
+ * Otherwise, @drv is inserted into global_drivers, and called for
+ * each device.
+ */
+
+int sysdev_driver_register(struct sysdev_class * cls,
+ struct sysdev_driver * drv)
+{
+ down_write(&system_subsys.rwsem);
+ if (cls && kset_get(&cls->kset))
+ list_add_tail(&drv->entry,&cls->drivers);
+ else
+ list_add_tail(&drv->entry,&global_drivers);
+ up_write(&system_subsys.rwsem);
+ return 0;
+}
+
+
+/**
+ * sysdev_driver_unregister - Remove an auxillary driver.
+ * @cls: Class driver belongs to.
+ * @drv: Driver.
+ */
+void sysdev_driver_unregister(struct sysdev_class * cls,
+ struct sysdev_driver * drv)
+{
+ down_write(&system_subsys.rwsem);
+ list_del_init(&drv->entry);
+ if (cls)
+ kset_put(&cls->kset);
+ up_write(&system_subsys.rwsem);
+}
+
+
+/**
+ * sys_device_register - add a system device to the tree
+ * @sysdev: device in question
*
- * The platform code can then use @root to specifiy the
- * controlling board when discovering and registering
- * system devices.
*/
-int sys_register_root(struct sys_root * root)
+int sys_device_register(struct sys_device * sysdev)
{
- int error = 0;
+ int error;
+ struct sysdev_class * cls = sysdev->cls;
- if (!root)
+ if (!cls)
return -EINVAL;
- if (!root->dev.parent)
- root->dev.parent = &system_bus;
+ /* Make sure the kset is set */
+ sysdev->kobj.kset = &cls->kset;
+
+ /* set the kobject name */
+ snprintf(sysdev->kobj.name,KOBJ_NAME_LEN,"%s%d",
+ cls->kset.kobj.name,sysdev->id);
- pr_debug("Registering system board %d\n",root->id);
+ pr_debug("Registering sys device '%s'\n",sysdev->kobj.name);
+
+ /* Register the object */
+ error = kobject_register(&sysdev->kobj);
- error = device_register(&root->dev);
if (!error) {
- strlcpy(root->sysdev.bus_id,"sys",BUS_ID_SIZE);
- strlcpy(root->sysdev.name,"System Bus",DEVICE_NAME_SIZE);
- root->sysdev.parent = &root->dev;
- error = device_register(&root->sysdev);
- };
+ struct sysdev_driver * drv;
+
+ down_read(&system_subsys.rwsem);
+ /* Generic notification is implicit, because it's that
+ * code that should have called us.
+ */
+ /* Notify global drivers */
+ list_for_each_entry(drv,&global_drivers,entry) {
+ if (drv->add)
+ drv->add(sysdev);
+ }
+
+ /* Notify class auxillary drivers */
+ list_for_each_entry(drv,&cls->drivers,entry) {
+ if (drv->add)
+ drv->add(sysdev);
+ }
+ up_read(&system_subsys.rwsem);
+ }
return error;
}
+void sys_device_unregister(struct sys_device * sysdev)
+{
+ struct sysdev_driver * drv;
+
+ down_read(&system_subsys.rwsem);
+ list_for_each_entry(drv,&global_drivers,entry) {
+ if (drv->remove)
+ drv->remove(sysdev);
+ }
+
+ list_for_each_entry(drv,&sysdev->cls->drivers,entry) {
+ if (drv->remove)
+ drv->remove(sysdev);
+ }
+ up_read(&system_subsys.rwsem);
+
+ kobject_unregister(&sysdev->kobj);
+}
+
+
+
/**
- * sys_unregister_root - remove subordinate root from tree
- * @root: subordinate root in question.
+ * sysdev_shutdown - Shut down all system devices.
+ *
+ * Loop over each class of system devices, and the devices in each
+ * of those classes. For each device, we call the shutdown method for
+ * each driver registered for the device - the globals, the auxillaries,
+ * and the class driver.
*
- * We only decrement the reference count on @root->sysdev
- * and @root->dev.
- * If both are 0, they will be cleaned up by the core.
+ * Note: The list is iterated in reverse order, so that we shut down
+ * child devices before we shut down thier parents. The list ordering
+ * is guaranteed by virtue of the fact that child devices are registered
+ * after their parents.
*/
-void sys_unregister_root(struct sys_root *root)
+
+void sysdev_shutdown(void)
{
- device_unregister(&root->sysdev);
- device_unregister(&root->dev);
+ struct sysdev_class * cls;
+
+ pr_debug("Shutting Down System Devices\n");
+
+ down_write(&system_subsys.rwsem);
+ list_for_each_entry_reverse(cls,&system_subsys.kset.list,
+ kset.kobj.entry) {
+ struct sys_device * sysdev;
+
+ pr_debug("Shutting down type '%s':\n",cls->kset.kobj.name);
+
+ list_for_each_entry(sysdev,&cls->kset.list,kobj.entry) {
+ struct sysdev_driver * drv;
+ pr_debug(" %s\n",sysdev->kobj.name);
+
+ /* Call global drivers first. */
+ list_for_each_entry(drv,&global_drivers,entry) {
+ if (drv->shutdown)
+ drv->shutdown(sysdev);
+ }
+
+ /* Call auxillary drivers next. */
+ list_for_each_entry(drv,&cls->drivers,entry) {
+ if (drv->shutdown)
+ drv->shutdown(sysdev);
+ }
+
+ /* Now call the generic one */
+ if (cls->shutdown)
+ cls->shutdown(sysdev);
+ }
+ }
+ up_write(&system_subsys.rwsem);
}
+
/**
- * sys_device_register - add a system device to the tree
- * @sysdev: device in question
+ * sysdev_save - Save system device state
+ * @state: Power state we're entering.
*
- * The hardest part about this is getting the ancestry right.
- * If the device has a parent - super! We do nothing.
- * If the device doesn't, but @dev->root is set, then we're
- * dealing with a NUMA like architecture where each root
- * has a system pseudo-bus to foster the device.
- * If not, then we fallback to system_bus (at the top of
- * this file).
+ * This is called when the system is going to sleep, but before interrupts
+ * have been disabled. This allows system device drivers to allocate and
+ * save device state, including sleeping during the process..
+ */
+
+int sysdev_save(u32 state)
+{
+ struct sysdev_class * cls;
+
+ pr_debug("Saving System Device State\n");
+
+ down_write(&system_subsys.rwsem);
+
+ list_for_each_entry_reverse(cls,&system_subsys.kset.list,
+ kset.kobj.entry) {
+ struct sys_device * sysdev;
+ pr_debug("Saving state for type '%s':\n",cls->kset.kobj.name);
+
+ list_for_each_entry(sysdev,&cls->kset.list,kobj.entry) {
+ struct sysdev_driver * drv;
+
+ pr_debug(" %s\n",sysdev->kobj.name);
+
+ list_for_each_entry(drv,&global_drivers,entry) {
+ if (drv->save)
+ drv->save(sysdev,state);
+ }
+
+ list_for_each_entry(drv,&cls->drivers,entry) {
+ if (drv->save)
+ drv->save(sysdev,state);
+ }
+
+ if (cls->save)
+ cls->save(sysdev,state);
+ }
+ }
+ up_write(&system_subsys.rwsem);
+ return 0;
+}
+
+
+/**
+ * sysdev_suspend - Suspend all system devices.
+ * @state: Power state to enter.
*
- * One way or another, we call device_register() on it and
- * are done.
+ * We perform an almost identical operation as sys_device_shutdown()
+ * above, though calling ->suspend() instead.
*
- * The caller is also responsible for initializing the bus_id
- * and name fields of @sysdev->dev.
+ * Note: Interrupts are disabled when called, so we can't sleep when
+ * trying to get the subsystem's rwsem. If that happens, print a nasty
+ * warning and return an error.
*/
-int sys_device_register(struct sys_device * sysdev)
+
+int sysdev_suspend(u32 state)
{
- if (!sysdev)
- return -EINVAL;
+ struct sysdev_class * cls;
+
+ pr_debug("Suspending System Devices\n");
- if (!sysdev->dev.parent) {
- if (sysdev->root)
- sysdev->dev.parent = &sysdev->root->sysdev;
- else
- sysdev->dev.parent = &system_bus;
+ if (!down_write_trylock(&system_subsys.rwsem)) {
+ printk("%s: Cannot acquire semaphore; Failing\n",__FUNCTION__);
+ return -EFAULT;
}
- /* make sure bus type is set */
- if (!sysdev->dev.bus)
- sysdev->dev.bus = &system_bus_type;
+ list_for_each_entry_reverse(cls,&system_subsys.kset.list,
+ kset.kobj.entry) {
+ struct sys_device * sysdev;
+
+ pr_debug("Suspending type '%s':\n",cls->kset.kobj.name);
+
+ list_for_each_entry(sysdev,&cls->kset.list,kobj.entry) {
+ struct sysdev_driver * drv;
+ pr_debug(" %s\n",sysdev->kobj.name);
- /* construct bus_id */
- snprintf(sysdev->dev.bus_id,BUS_ID_SIZE,"%s%u",sysdev->name,sysdev->id);
+ /* Call global drivers first. */
+ list_for_each_entry(drv,&global_drivers,entry) {
+ if (drv->suspend)
+ drv->suspend(sysdev,state);
+ }
- pr_debug("Registering system device %s\n", sysdev->dev.bus_id);
+ /* Call auxillary drivers next. */
+ list_for_each_entry(drv,&cls->drivers,entry) {
+ if (drv->suspend)
+ drv->suspend(sysdev,state);
+ }
- return device_register(&sysdev->dev);
+ /* Now call the generic one */
+ if (cls->suspend)
+ cls->suspend(sysdev,state);
+ }
+ }
+ up_write(&system_subsys.rwsem);
+
+ return 0;
}
-void sys_device_unregister(struct sys_device * sysdev)
+
+/**
+ * sysdev_resume - Bring system devices back to life.
+ *
+ * Similar to sys_device_suspend(), but we iterate the list forwards
+ * to guarantee that parent devices are resumed before their children.
+ *
+ * Note: Interrupts are disabled when called.
+ */
+
+int sysdev_resume(void)
{
- if (sysdev)
- device_unregister(&sysdev->dev);
+ struct sysdev_class * cls;
+
+ pr_debug("Resuming System Devices\n");
+
+ if(!down_write_trylock(&system_subsys.rwsem))
+ return -EFAULT;
+
+ list_for_each_entry(cls,&system_subsys.kset.list,kset.kobj.entry) {
+ struct sys_device * sysdev;
+
+ pr_debug("Resuming type '%s':\n",cls->kset.kobj.name);
+
+ list_for_each_entry(sysdev,&cls->kset.list,kobj.entry) {
+ struct sysdev_driver * drv;
+ pr_debug(" %s\n",sysdev->kobj.name);
+
+ /* First, call the class-specific one */
+ if (cls->resume)
+ cls->resume(sysdev);
+
+ /* Call auxillary drivers next. */
+ list_for_each_entry(drv,&cls->drivers,entry) {
+ if (drv->resume)
+ drv->resume(sysdev);
+ }
+
+ /* Call global drivers. */
+ list_for_each_entry(drv,&global_drivers,entry) {
+ if (drv->resume)
+ drv->resume(sysdev);
+ }
+
+ }
+ }
+ up_write(&system_subsys.rwsem);
+ return 0;
+}
+
+
+/**
+ * sysdev_restore - Restore system device state
+ *
+ * This is called during a suspend/resume cycle last, after interrupts
+ * have been re-enabled. This is intended for auxillary drivers, etc,
+ * that may sleep when restoring state.
+ */
+
+int sysdev_restore(void)
+{
+ struct sysdev_class * cls;
+
+ down_write(&system_subsys.rwsem);
+ pr_debug("Restoring System Device State\n");
+
+ list_for_each_entry(cls,&system_subsys.kset.list,kset.kobj.entry) {
+ struct sys_device * sysdev;
+
+ pr_debug("Restoring state for type '%s':\n",cls->kset.kobj.name);
+ list_for_each_entry(sysdev,&cls->kset.list,kobj.entry) {
+ struct sysdev_driver * drv;
+ pr_debug(" %s\n",sysdev->kobj.name);
+
+ if (cls->restore)
+ cls->restore(sysdev);
+
+ list_for_each_entry(drv,&cls->drivers,entry) {
+ if (drv->restore)
+ drv->restore(sysdev);
+ }
+
+ list_for_each_entry(drv,&global_drivers,entry) {
+ if (drv->restore)
+ drv->restore(sysdev);
+ }
+ }
+ }
+
+ up_write(&system_subsys.rwsem);
+ return 0;
}
-struct bus_type system_bus_type = {
- .name = "system",
-};
int __init sys_bus_init(void)
{
- bus_register(&system_bus_type);
- return device_register(&system_bus);
+ system_subsys.kset.kobj.parent = &devices_subsys.kset.kobj;
+ return subsystem_register(&system_subsys);
}
-EXPORT_SYMBOL(system_bus_type);
EXPORT_SYMBOL(sys_device_register);
EXPORT_SYMBOL(sys_device_unregister);
diff --git a/drivers/s390/block/xpram.c b/drivers/s390/block/xpram.c
index fbb02dd40042..486e0111891d 100644
--- a/drivers/s390/block/xpram.c
+++ b/drivers/s390/block/xpram.c
@@ -34,7 +34,7 @@
#include <linux/blk.h>
#include <linux/blkpg.h>
#include <linux/hdreg.h> /* HDIO_GETGEO */
-#include <linux/device.h>
+#include <linux/sysdev.h>
#include <linux/bio.h>
#include <linux/devfs_fs_kernel.h>
#include <asm/uaccess.h>
@@ -48,12 +48,14 @@
#define PRINT_WARN(x...) printk(KERN_WARNING XPRAM_NAME " warning:" x)
#define PRINT_ERR(x...) printk(KERN_ERR XPRAM_NAME " error:" x)
+
+static struct sysdev_class xpram_sysclass = {
+ set_kset_name("xpram"),
+};
+
static struct sys_device xpram_sys_device = {
- .name = "S/390 expanded memory RAM disk",
- .dev = {
- .name = "S/390 expanded memory RAM disk",
- .bus_id = "xpram",
- },
+ .id = 0,
+ .cls = &xpram_sysclass,
};
typedef struct {
@@ -485,6 +487,7 @@ static void __exit xpram_exit(void)
unregister_blkdev(XPRAM_MAJOR, XPRAM_NAME);
devfs_remove("slram");
sys_device_unregister(&xpram_sys_device);
+ sysdev_class_unregister(&xpram_sys_class);
}
static int __init xpram_init(void)
@@ -502,9 +505,15 @@ static int __init xpram_init(void)
rc = xpram_setup_sizes(xpram_pages);
if (rc)
return rc;
- rc = sys_device_register(&xpram_sys_device);
+ rc = sysdev_class_register(&xpram_sysclass);
if (rc)
return rc;
+
+ rc = sys_device_register(&xpram_sys_device);
+ if (rc) {
+ sysdev_class_unregister(&xpram_syclass);
+ return rc;
+ }
rc = xpram_setup_blkdev();
if (rc)
sys_device_unregister(&xpram_sys_device);
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c
index 26796e91bb16..3c9f3ef77a54 100644
--- a/fs/sysfs/file.c
+++ b/fs/sysfs/file.c
@@ -84,7 +84,7 @@ static int fill_read_buffer(struct file * file, struct sysfs_buffer * buffer)
ssize_t count;
if (!buffer->page)
- buffer->page = (char *) __get_free_page(GFP_KERNEL);
+ buffer->page = (char *) get_zeroed_page(GFP_KERNEL);
if (!buffer->page)
return -ENOMEM;
@@ -174,7 +174,7 @@ fill_write_buffer(struct sysfs_buffer * buffer, const char * buf, size_t count)
int error;
if (!buffer->page)
- buffer->page = (char *)__get_free_page(GFP_KERNEL);
+ buffer->page = (char *)get_zeroed_page(GFP_KERNEL);
if (!buffer->page)
return -ENOMEM;
diff --git a/include/linux/cpu.h b/include/linux/cpu.h
index 93853448aeb9..2f374d79f157 100644
--- a/include/linux/cpu.h
+++ b/include/linux/cpu.h
@@ -19,7 +19,7 @@
#ifndef _LINUX_CPU_H_
#define _LINUX_CPU_H_
-#include <linux/device.h>
+#include <linux/sysdev.h>
#include <linux/node.h>
#include <asm/semaphore.h>
@@ -29,8 +29,6 @@ struct cpu {
};
extern int register_cpu(struct cpu *, int, struct node *);
-extern struct class cpu_class;
-
struct notifier_block;
#ifdef CONFIG_SMP
@@ -48,6 +46,7 @@ static inline void unregister_cpu_notifier(struct notifier_block *nb)
{
}
#endif /* CONFIG_SMP */
+extern struct sysdev_class cpu_sysdev_class;
/* Stop CPUs going up and down. */
extern struct semaphore cpucontrol;
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
index 3dc9062bd414..1bdb797bf9bd 100644
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -205,10 +205,6 @@ struct freq_attr {
int cpufreq_set_policy(struct cpufreq_policy *policy);
int cpufreq_get_policy(struct cpufreq_policy *policy, unsigned int cpu);
-#ifdef CONFIG_PM
-int cpufreq_restore(void);
-#endif
-
/* the proc_intf.c needs this */
int cpufreq_parse_governor (char *str_governor, unsigned int *policy, struct cpufreq_governor **governor);
diff --git a/include/linux/device.h b/include/linux/device.h
index 3604d351f3f0..1bd92551c077 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -351,30 +351,6 @@ extern int (*platform_notify_remove)(struct device * dev);
extern struct device * get_device(struct device * dev);
extern void put_device(struct device * dev);
-/* drivers/base/sys.c */
-
-struct sys_root {
- u32 id;
- struct device dev;
- struct device sysdev;
-};
-
-extern int sys_register_root(struct sys_root *);
-extern void sys_unregister_root(struct sys_root *);
-
-
-struct sys_device {
- char * name;
- u32 id;
- struct sys_root * root;
- struct device dev;
- struct class_device class_dev;
-};
-
-extern int sys_device_register(struct sys_device *);
-extern void sys_device_unregister(struct sys_device *);
-
-extern struct bus_type system_bus_type;
/* drivers/base/platform.c */
diff --git a/include/linux/kobject.h b/include/linux/kobject.h
index c982391cf8d6..5d42248dd95f 100644
--- a/include/linux/kobject.h
+++ b/include/linux/kobject.h
@@ -118,6 +118,14 @@ static inline struct kobj_type * get_ktype(struct kobject * k)
extern struct kobject * kset_find_obj(struct kset *, const char *);
+/**
+ * Use this when initializing an embedded kset with no other
+ * fields to initialize.
+ */
+#define set_kset_name(str) .kset = { .kobj = { .name = str } }
+
+
+
struct subsystem {
struct kset kset;
struct rw_semaphore rwsem;
diff --git a/include/linux/list.h b/include/linux/list.h
index d6305f84bfe6..eed55ea5860a 100644
--- a/include/linux/list.h
+++ b/include/linux/list.h
@@ -310,6 +310,20 @@ static inline void list_splice_init(struct list_head *list,
prefetch(pos->member.next))
/**
+ * list_for_each_entry_reverse - iterate backwards over list of given type.
+ * @pos: the type * to use as a loop counter.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_reverse(pos, head, member) \
+ for (pos = list_entry((head)->prev, typeof(*pos), member), \
+ prefetch(pos->member.prev); \
+ &pos->member != (head); \
+ pos = list_entry(pos->member.prev, typeof(*pos), member), \
+ prefetch(pos->member.prev))
+
+
+/**
* list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
* @pos: the type * to use as a loop counter.
* @n: another type * to use as temporary storage
diff --git a/include/linux/node.h b/include/linux/node.h
index 294606bbff5a..90543a94b86e 100644
--- a/include/linux/node.h
+++ b/include/linux/node.h
@@ -19,11 +19,11 @@
#ifndef _LINUX_NODE_H_
#define _LINUX_NODE_H_
-#include <linux/device.h>
+#include <linux/sysdev.h>
struct node {
unsigned long cpumap; /* Bitmap of CPUs on the Node */
- struct sys_root sysroot;
+ struct sys_device sysdev;
};
extern int register_node(struct node *, int, struct node *);
diff --git a/include/linux/sysdev.h b/include/linux/sysdev.h
new file mode 100644
index 000000000000..4bc3e22b5104
--- /dev/null
+++ b/include/linux/sysdev.h
@@ -0,0 +1,98 @@
+/**
+ * System devices follow a slightly different driver model.
+ * They don't need to do dynammic driver binding, can't be probed,
+ * and don't reside on any type of peripheral bus.
+ * So, we represent and treat them a little differently.
+ *
+ * We still have a notion of a driver for a system device, because we still
+ * want to perform basic operations on these devices.
+ *
+ * We also support auxillary drivers binding to devices of a certain class.
+ *
+ * This allows configurable drivers to register themselves for devices of
+ * a certain type. And, it allows class definitions to reside in generic
+ * code while arch-specific code can register specific drivers.
+ *
+ * Auxillary drivers registered with a NULL cls are registered as drivers
+ * for all system devices, and get notification calls for each device.
+ */
+
+
+#ifndef _SYSDEV_H_
+#define _SYSDEV_H_
+
+#include <linux/kobject.h>
+
+
+struct sys_device;
+
+struct sysdev_class {
+ struct list_head drivers;
+
+ /* Default operations for these types of devices */
+ int (*shutdown)(struct sys_device *);
+ int (*save)(struct sys_device *, u32 state);
+ int (*suspend)(struct sys_device *, u32 state);
+ int (*resume)(struct sys_device *);
+ int (*restore)(struct sys_device *);
+ struct kset kset;
+};
+
+
+extern int sysdev_class_register(struct sysdev_class *);
+extern void sysdev_class_unregister(struct sysdev_class *);
+
+
+/**
+ * Auxillary system device drivers.
+ */
+
+struct sysdev_driver {
+ struct list_head entry;
+ int (*add)(struct sys_device *);
+ int (*remove)(struct sys_device *);
+ int (*shutdown)(struct sys_device *);
+ int (*save)(struct sys_device *, u32 state);
+ int (*suspend)(struct sys_device *, u32 state);
+ int (*resume)(struct sys_device *);
+ int (*restore)(struct sys_device *);
+};
+
+
+extern int sysdev_driver_register(struct sysdev_class *, struct sysdev_driver *);
+extern void sysdev_driver_unregister(struct sysdev_class *, struct sysdev_driver *);
+
+
+/**
+ * sys_devices can be simplified a lot from regular devices, because they're
+ * simply not as versatile.
+ */
+
+struct sys_device {
+ u32 id;
+ struct sysdev_class * cls;
+ struct kobject kobj;
+};
+
+extern int sys_device_register(struct sys_device *);
+extern void sys_device_unregister(struct sys_device *);
+
+
+struct sysdev_attribute {
+ struct attribute attr;
+ ssize_t (*show)(struct sys_device *, char *);
+ ssize_t (*store)(struct sys_device *, const char *, size_t);
+};
+
+
+#define SYSDEV_ATTR(_name,_mode,_show,_store) \
+struct sysdev_attribute attr_##_name = { \
+ .attr = {.name = __stringify(_name), .mode = _mode }, \
+ .show = _show, \
+ .store = _store, \
+};
+
+extern int sysdev_create_file(struct sys_device *, struct sysdev_attribute *);
+extern void sysdev_remove_file(struct sys_device *, struct sysdev_attribute *);
+
+#endif /* _SYSDEV_H_ */
diff --git a/kernel/cpufreq.c b/kernel/cpufreq.c
index ab772ccf9c59..6ae2b821830e 100644
--- a/kernel/cpufreq.c
+++ b/kernel/cpufreq.c
@@ -49,8 +49,6 @@ static DECLARE_RWSEM (cpufreq_notifier_rwsem);
static LIST_HEAD(cpufreq_governor_list);
static DECLARE_MUTEX (cpufreq_governor_sem);
-static struct class_interface cpufreq_interface;
-
static int cpufreq_cpu_get(unsigned int cpu)
{
if (cpu >= NR_CPUS)
@@ -113,24 +111,8 @@ int cpufreq_parse_governor (char *str_governor, unsigned int *policy,
EXPORT_SYMBOL_GPL(cpufreq_parse_governor);
-/* forward declarations */
-static int cpufreq_add_dev (struct class_device * dev);
-static void cpufreq_remove_dev (struct class_device * dev);
-
/* drivers/base/cpu.c */
-extern struct device_class cpu_devclass;
-
-static struct class_interface cpufreq_interface = {
- .class = &cpu_class,
- .add = &cpufreq_add_dev,
- .remove = &cpufreq_remove_dev,
-};
-
-static inline int to_cpu_nr (struct class_device *dev)
-{
- struct sys_device * cpu_sys_dev = container_of(dev->dev, struct sys_device, dev);
- return (cpu_sys_dev->id);
-}
+extern struct sysdev_class cpu_sysdev_class;
/**
@@ -331,9 +313,9 @@ static struct kobj_type ktype_cpufreq = {
*
* Adds the cpufreq interface for a CPU device.
*/
-static int cpufreq_add_dev (struct class_device * class_dev)
+static int cpufreq_add_dev (struct sys_device * sys_dev)
{
- unsigned int cpu = to_cpu_nr(class_dev);
+ unsigned int cpu = sys_dev->id;
int ret = 0;
struct cpufreq_policy new_policy;
struct cpufreq_policy *policy;
@@ -358,14 +340,12 @@ static int cpufreq_add_dev (struct class_device * class_dev)
memcpy(&new_policy,
policy,
sizeof(struct cpufreq_policy));
- class_set_devdata(class_dev, policy);
up(&cpufreq_driver_sem);
init_MUTEX(&policy->lock);
/* prepare interface data */
- policy->kobj.parent = &class_dev->kobj;
+ policy->kobj.parent = &sys_dev->kobj;
policy->kobj.ktype = &ktype_cpufreq;
-// policy->dev = dev->dev;
strlcpy(policy->kobj.name, "cpufreq", KOBJ_NAME_LEN);
ret = kobject_register(&policy->kobj);
@@ -396,12 +376,12 @@ static int cpufreq_add_dev (struct class_device * class_dev)
*
* Removes the cpufreq interface for a CPU device.
*/
-static void cpufreq_remove_dev (struct class_device * class_dev)
+static int cpufreq_remove_dev (struct sys_device * sys_dev)
{
- unsigned int cpu = to_cpu_nr(class_dev);
+ unsigned int cpu = sys_dev->id;
if (!kobject_get(&cpufreq_driver->policy[cpu].kobj))
- return;
+ return -EFAULT;
down(&cpufreq_driver_sem);
if ((cpufreq_driver->target) &&
@@ -421,9 +401,17 @@ static void cpufreq_remove_dev (struct class_device * class_dev)
up(&cpufreq_driver_sem);
kobject_put(&cpufreq_driver->policy[cpu].kobj);
- return;
+ return 0;
}
+static int cpufreq_restore(struct sys_device *);
+
+static struct sysdev_driver cpufreq_sysdev_driver = {
+ .add = cpufreq_add_dev,
+ .remove = cpufreq_remove_dev,
+ .restore = cpufreq_restore,
+};
+
/*********************************************************************
* NOTIFIER LISTS INTERFACE *
@@ -843,7 +831,7 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
memset(cpufreq_driver->policy, 0, NR_CPUS * sizeof(struct cpufreq_policy));
- return class_interface_register(&cpufreq_interface);
+ return sysdev_driver_register(&cpu_sysdev_class,&cpufreq_sysdev_driver);
}
EXPORT_SYMBOL_GPL(cpufreq_register_driver);
@@ -861,7 +849,7 @@ int cpufreq_unregister_driver(struct cpufreq_driver *driver)
if (!cpufreq_driver || (driver != cpufreq_driver))
return -EINVAL;
- class_interface_unregister(&cpufreq_interface);
+ sysdev_driver_unregister(&cpu_sysdev_class, &cpufreq_sysdev_driver);
down(&cpufreq_driver_sem);
kfree(cpufreq_driver->policy);
@@ -874,41 +862,34 @@ EXPORT_SYMBOL_GPL(cpufreq_unregister_driver);
#ifdef CONFIG_PM
+
/**
* cpufreq_restore - restore the CPU clock frequency after resume
*
* Restore the CPU clock frequency so that our idea of the current
* frequency reflects the actual hardware.
*/
-int cpufreq_restore(void)
+static int cpufreq_restore(struct sys_device * sysdev)
{
- struct cpufreq_policy policy;
- unsigned int i;
+ int cpu = sysdev->id;
unsigned int ret = 0;
+ struct cpufreq_policy policy;
- if (in_interrupt())
- panic("cpufreq_restore() called from interrupt context!");
-
- if (!try_module_get(cpufreq_driver->owner))
- goto error_out;
-
- for (i=0;i<NR_CPUS;i++) {
- if (!cpu_online(i) || !cpufreq_cpu_get(i))
- continue;
-
+ if (cpu_online(cpu) && cpufreq_cpu_get(cpu)) {
down(&cpufreq_driver_sem);
- memcpy(&policy, &cpufreq_driver->policy[i], sizeof(struct cpufreq_policy));
+ memcpy(&policy, &cpufreq_driver->policy[cpu],
+ sizeof(struct cpufreq_policy));
up(&cpufreq_driver_sem);
- ret += cpufreq_set_policy(&policy);
-
- cpufreq_cpu_put(i);
+ ret = cpufreq_set_policy(&policy);
+ cpufreq_cpu_put(cpu);
}
- module_put(cpufreq_driver->owner);
- error_out:
return ret;
}
-EXPORT_SYMBOL_GPL(cpufreq_restore);
+
#else
-#define cpufreq_restore() do {} while (0)
+static int cpufreq_restore(struct sys_device * sysdev)
+{
+ return 0;
+}
#endif /* CONFIG_PM */