Skip to content

Commit

Permalink
x86: Use syscore_ops instead of sysdev classes and sysdevs
Browse files Browse the repository at this point in the history
Some subsystems in the x86 tree need to carry out suspend/resume and
shutdown operations with one CPU on-line and interrupts disabled and
they define sysdev classes and sysdevs or sysdev drivers for this
purpose.  This leads to unnecessarily complicated code and excessive
memory usage, so switch them to using struct syscore_ops objects for
this purpose instead.

Generally, there are three categories of subsystems that use
sysdevs for implementing PM operations: (1) subsystems whose
suspend/resume callbacks ignore their arguments entirely (the
majority), (2) subsystems whose suspend/resume callbacks use their
struct sys_device argument, but don't really need to do that,
because they can be implemented differently in an arguably simpler
way (io_apic.c), and (3) subsystems whose suspend/resume callbacks
use their struct sys_device argument, but the value of that argument
is always the same and could be ignored (microcode_core.c).  In all
of these cases the subsystems in question may be readily converted to
using struct syscore_ops objects for power management and shutdown.

Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Reviewed-by: Thomas Gleixner <tglx@linutronix.de>
Acked-by: Ingo Molnar <mingo@elte.hu>
  • Loading branch information
Rafael J. Wysocki committed Mar 23, 2011
1 parent 4bbba11 commit f3c6ea1
Show file tree
Hide file tree
Showing 10 changed files with 128 additions and 232 deletions.
26 changes: 6 additions & 20 deletions arch/x86/kernel/amd_iommu_init.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
#include <linux/acpi.h>
#include <linux/list.h>
#include <linux/slab.h>
#include <linux/sysdev.h>
#include <linux/syscore_ops.h>
#include <linux/interrupt.h>
#include <linux/msi.h>
#include <asm/pci-direct.h>
Expand Down Expand Up @@ -1260,7 +1260,7 @@ static void disable_iommus(void)
* disable suspend until real resume implemented
*/

static int amd_iommu_resume(struct sys_device *dev)
static void amd_iommu_resume(void)
{
struct amd_iommu *iommu;

Expand All @@ -1276,29 +1276,21 @@ static int amd_iommu_resume(struct sys_device *dev)
*/
amd_iommu_flush_all_devices();
amd_iommu_flush_all_domains();

return 0;
}

static int amd_iommu_suspend(struct sys_device *dev, pm_message_t state)
static int amd_iommu_suspend(void)
{
/* disable IOMMUs to go out of the way for BIOS */
disable_iommus();

return 0;
}

static struct sysdev_class amd_iommu_sysdev_class = {
.name = "amd_iommu",
static struct syscore_ops amd_iommu_syscore_ops = {
.suspend = amd_iommu_suspend,
.resume = amd_iommu_resume,
};

static struct sys_device device_amd_iommu = {
.id = 0,
.cls = &amd_iommu_sysdev_class,
};

/*
* This is the core init function for AMD IOMMU hardware in the system.
* This function is called from the generic x86 DMA layer initialization
Expand Down Expand Up @@ -1415,14 +1407,6 @@ static int __init amd_iommu_init(void)
goto free;
}

ret = sysdev_class_register(&amd_iommu_sysdev_class);
if (ret)
goto free;

ret = sysdev_register(&device_amd_iommu);
if (ret)
goto free;

ret = amd_iommu_init_devices();
if (ret)
goto free;
Expand All @@ -1441,6 +1425,8 @@ static int __init amd_iommu_init(void)

amd_iommu_init_notifier();

register_syscore_ops(&amd_iommu_syscore_ops);

if (iommu_pass_through)
goto out;

Expand Down
33 changes: 9 additions & 24 deletions arch/x86/kernel/apic/apic.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
#include <linux/ftrace.h>
#include <linux/ioport.h>
#include <linux/module.h>
#include <linux/sysdev.h>
#include <linux/syscore_ops.h>
#include <linux/delay.h>
#include <linux/timex.h>
#include <linux/dmar.h>
Expand Down Expand Up @@ -2046,7 +2046,7 @@ static struct {
unsigned int apic_thmr;
} apic_pm_state;

static int lapic_suspend(struct sys_device *dev, pm_message_t state)
static int lapic_suspend(void)
{
unsigned long flags;
int maxlvt;
Expand Down Expand Up @@ -2084,23 +2084,21 @@ static int lapic_suspend(struct sys_device *dev, pm_message_t state)
return 0;
}

static int lapic_resume(struct sys_device *dev)
static void lapic_resume(void)
{
unsigned int l, h;
unsigned long flags;
int maxlvt;
int ret = 0;
int maxlvt, ret;
struct IO_APIC_route_entry **ioapic_entries = NULL;

if (!apic_pm_state.active)
return 0;
return;

local_irq_save(flags);
if (intr_remapping_enabled) {
ioapic_entries = alloc_ioapic_entries();
if (!ioapic_entries) {
WARN(1, "Alloc ioapic_entries in lapic resume failed.");
ret = -ENOMEM;
goto restore;
}

Expand Down Expand Up @@ -2162,43 +2160,30 @@ static int lapic_resume(struct sys_device *dev)
}
restore:
local_irq_restore(flags);

return ret;
}

/*
* This device has no shutdown method - fully functioning local APICs
* are needed on every CPU up until machine_halt/restart/poweroff.
*/

static struct sysdev_class lapic_sysclass = {
.name = "lapic",
static struct syscore_ops lapic_syscore_ops = {
.resume = lapic_resume,
.suspend = lapic_suspend,
};

static struct sys_device device_lapic = {
.id = 0,
.cls = &lapic_sysclass,
};

static void __cpuinit apic_pm_activate(void)
{
apic_pm_state.active = 1;
}

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? */
if (cpu_has_apic)
register_syscore_ops(&lapic_syscore_ops);

error = sysdev_class_register(&lapic_sysclass);
if (!error)
error = sysdev_register(&device_lapic);
return error;
return 0;
}

/* local apic needs to resume before other devices access its registers. */
Expand Down
97 changes: 46 additions & 51 deletions arch/x86/kernel/apic/io_apic.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
#include <linux/compiler.h>
#include <linux/acpi.h>
#include <linux/module.h>
#include <linux/sysdev.h>
#include <linux/syscore_ops.h>
#include <linux/msi.h>
#include <linux/htirq.h>
#include <linux/freezer.h>
Expand Down Expand Up @@ -2918,89 +2918,84 @@ static int __init io_apic_bug_finalize(void)

late_initcall(io_apic_bug_finalize);

struct sysfs_ioapic_data {
struct sys_device dev;
struct IO_APIC_route_entry entry[0];
};
static struct sysfs_ioapic_data * mp_ioapic_data[MAX_IO_APICS];
static struct IO_APIC_route_entry *ioapic_saved_data[MAX_IO_APICS];

static int ioapic_suspend(struct sys_device *dev, pm_message_t state)
static void suspend_ioapic(int ioapic_id)
{
struct IO_APIC_route_entry *entry;
struct sysfs_ioapic_data *data;
struct IO_APIC_route_entry *saved_data = ioapic_saved_data[ioapic_id];
int i;

data = container_of(dev, struct sysfs_ioapic_data, dev);
entry = data->entry;
for (i = 0; i < nr_ioapic_registers[dev->id]; i ++, entry ++ )
*entry = ioapic_read_entry(dev->id, i);
if (!saved_data)
return;

for (i = 0; i < nr_ioapic_registers[ioapic_id]; i++)
saved_data[i] = ioapic_read_entry(ioapic_id, i);
}

static int ioapic_suspend(void)
{
int ioapic_id;

for (ioapic_id = 0; ioapic_id < nr_ioapics; ioapic_id++)
suspend_ioapic(ioapic_id);

return 0;
}

static int ioapic_resume(struct sys_device *dev)
static void resume_ioapic(int ioapic_id)
{
struct IO_APIC_route_entry *entry;
struct sysfs_ioapic_data *data;
struct IO_APIC_route_entry *saved_data = ioapic_saved_data[ioapic_id];
unsigned long flags;
union IO_APIC_reg_00 reg_00;
int i;

data = container_of(dev, struct sysfs_ioapic_data, dev);
entry = data->entry;
if (!saved_data)
return;

raw_spin_lock_irqsave(&ioapic_lock, flags);
reg_00.raw = io_apic_read(dev->id, 0);
if (reg_00.bits.ID != mp_ioapics[dev->id].apicid) {
reg_00.bits.ID = mp_ioapics[dev->id].apicid;
io_apic_write(dev->id, 0, reg_00.raw);
reg_00.raw = io_apic_read(ioapic_id, 0);
if (reg_00.bits.ID != mp_ioapics[ioapic_id].apicid) {
reg_00.bits.ID = mp_ioapics[ioapic_id].apicid;
io_apic_write(ioapic_id, 0, reg_00.raw);
}
raw_spin_unlock_irqrestore(&ioapic_lock, flags);
for (i = 0; i < nr_ioapic_registers[dev->id]; i++)
ioapic_write_entry(dev->id, i, entry[i]);
for (i = 0; i < nr_ioapic_registers[ioapic_id]; i++)
ioapic_write_entry(ioapic_id, i, saved_data[i]);
}

return 0;
static void ioapic_resume(void)
{
int ioapic_id;

for (ioapic_id = nr_ioapics - 1; ioapic_id >= 0; ioapic_id--)
resume_ioapic(ioapic_id);
}

static struct sysdev_class ioapic_sysdev_class = {
.name = "ioapic",
static struct syscore_ops ioapic_syscore_ops = {
.suspend = ioapic_suspend,
.resume = ioapic_resume,
};

static int __init ioapic_init_sysfs(void)
static int __init ioapic_init_ops(void)
{
struct sys_device * dev;
int i, size, error;
int i;

error = sysdev_class_register(&ioapic_sysdev_class);
if (error)
return error;
for (i = 0; i < nr_ioapics; i++) {
unsigned int size;

for (i = 0; i < nr_ioapics; i++ ) {
size = sizeof(struct sys_device) + nr_ioapic_registers[i]
size = nr_ioapic_registers[i]
* sizeof(struct IO_APIC_route_entry);
mp_ioapic_data[i] = kzalloc(size, GFP_KERNEL);
if (!mp_ioapic_data[i]) {
printk(KERN_ERR "Can't suspend/resume IOAPIC %d\n", i);
continue;
}
dev = &mp_ioapic_data[i]->dev;
dev->id = i;
dev->cls = &ioapic_sysdev_class;
error = sysdev_register(dev);
if (error) {
kfree(mp_ioapic_data[i]);
mp_ioapic_data[i] = NULL;
printk(KERN_ERR "Can't suspend/resume IOAPIC %d\n", i);
continue;
}
ioapic_saved_data[i] = kzalloc(size, GFP_KERNEL);
if (!ioapic_saved_data[i])
pr_err("IOAPIC %d: suspend/resume impossible!\n", i);
}

register_syscore_ops(&ioapic_syscore_ops);

return 0;
}

device_initcall(ioapic_init_sysfs);
device_initcall(ioapic_init_ops);

/*
* Dynamic irq allocate and deallocation
Expand Down
21 changes: 12 additions & 9 deletions arch/x86/kernel/cpu/mcheck/mce.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include <linux/percpu.h>
#include <linux/string.h>
#include <linux/sysdev.h>
#include <linux/syscore_ops.h>
#include <linux/delay.h>
#include <linux/ctype.h>
#include <linux/sched.h>
Expand Down Expand Up @@ -1749,29 +1750,33 @@ static int mce_disable_error_reporting(void)
return 0;
}

static int mce_suspend(struct sys_device *dev, pm_message_t state)
static int mce_suspend(void)
{
return mce_disable_error_reporting();
}

static int mce_shutdown(struct sys_device *dev)
static void mce_shutdown(void)
{
return mce_disable_error_reporting();
mce_disable_error_reporting();
}

/*
* On resume clear all MCE state. Don't want to see leftovers from the BIOS.
* Only one CPU is active at this time, the others get re-added later using
* CPU hotplug:
*/
static int mce_resume(struct sys_device *dev)
static void mce_resume(void)
{
__mcheck_cpu_init_generic();
__mcheck_cpu_init_vendor(__this_cpu_ptr(&cpu_info));

return 0;
}

static struct syscore_ops mce_syscore_ops = {
.suspend = mce_suspend,
.shutdown = mce_shutdown,
.resume = mce_resume,
};

static void mce_cpu_restart(void *data)
{
del_timer_sync(&__get_cpu_var(mce_timer));
Expand Down Expand Up @@ -1808,9 +1813,6 @@ static void mce_enable_ce(void *all)
}

static struct sysdev_class mce_sysclass = {
.suspend = mce_suspend,
.shutdown = mce_shutdown,
.resume = mce_resume,
.name = "machinecheck",
};

Expand Down Expand Up @@ -2139,6 +2141,7 @@ static __init int mcheck_init_device(void)
return err;
}

register_syscore_ops(&mce_syscore_ops);
register_hotcpu_notifier(&mce_cpu_notifier);
misc_register(&mce_log_device);

Expand Down
Loading

0 comments on commit f3c6ea1

Please sign in to comment.