Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f3c6ea1b authored by Rafael J. Wysocki's avatar Rafael J. Wysocki
Browse files

x86: Use syscore_ops instead of sysdev classes and sysdevs



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: default avatarRafael J. Wysocki <rjw@sisk.pl>
Reviewed-by: default avatarThomas Gleixner <tglx@linutronix.de>
Acked-by: default avatarIngo Molnar <mingo@elte.hu>
parent 4bbba111
Loading
Loading
Loading
Loading
+6 −20
Original line number Diff line number Diff line
@@ -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>
@@ -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;

@@ -1276,11 +1276,9 @@ 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();
@@ -1288,17 +1286,11 @@ static int amd_iommu_suspend(struct sys_device *dev, pm_message_t state)
	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
@@ -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;
@@ -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;

+9 −24
Original line number Diff line number Diff line
@@ -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>
@@ -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;
@@ -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;
		}

@@ -2162,8 +2160,6 @@ static int lapic_resume(struct sys_device *dev)
	}
restore:
	local_irq_restore(flags);

	return ret;
}

/*
@@ -2171,17 +2167,11 @@ static int lapic_resume(struct sys_device *dev)
 * 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;
@@ -2189,16 +2179,11 @@ static void __cpuinit apic_pm_activate(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? */
	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. */
+46 −51
Original line number Diff line number Diff line
@@ -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>
@@ -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;

	error = sysdev_class_register(&ioapic_sysdev_class);
	if (error)
		return error;
	int i;

	for (i = 0; i < nr_ioapics; i++) {
		size = sizeof(struct sys_device) + nr_ioapic_registers[i]
		unsigned int size;

		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
+12 −9
Original line number Diff line number Diff line
@@ -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>
@@ -1749,14 +1750,14 @@ 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();
}

/*
@@ -1764,14 +1765,18 @@ static int mce_shutdown(struct sys_device *dev)
 * 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));
@@ -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",
};

@@ -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);

+5 −5
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@
#include <linux/cpu.h>
#include <linux/pci.h>
#include <linux/smp.h>
#include <linux/syscore_ops.h>

#include <asm/processor.h>
#include <asm/e820.h>
@@ -630,7 +631,7 @@ struct mtrr_value {

static struct mtrr_value mtrr_value[MTRR_MAX_VAR_RANGES];

static int mtrr_save(struct sys_device *sysdev, pm_message_t state)
static int mtrr_save(void)
{
	int i;

@@ -642,7 +643,7 @@ static int mtrr_save(struct sys_device *sysdev, pm_message_t state)
	return 0;
}

static int mtrr_restore(struct sys_device *sysdev)
static void mtrr_restore(void)
{
	int i;

@@ -653,12 +654,11 @@ static int mtrr_restore(struct sys_device *sysdev)
				    mtrr_value[i].ltype);
		}
	}
	return 0;
}



static struct sysdev_driver mtrr_sysdev_driver = {
static struct syscore_ops mtrr_syscore_ops = {
	.suspend	= mtrr_save,
	.resume		= mtrr_restore,
};
@@ -839,7 +839,7 @@ static int __init mtrr_init_finialize(void)
	 * TBD: is there any system with such CPU which supports
	 * suspend/resume? If no, we should remove the code.
	 */
	sysdev_driver_register(&cpu_sysdev_class, &mtrr_sysdev_driver);
	register_syscore_ops(&mtrr_syscore_ops);

	return 0;
}
Loading