Commit f86054c2 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/suspend-2.6

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/suspend-2.6: (23 commits)
  at_hdmac: Rework suspend_late()/resume_early()
  PM: Reset transition_started at dpm_resume_noirq
  PM: Update kerneldoc comments in drivers/base/power/main.c
  PM: Add convenience macro to make switching to dev_pm_ops less error-prone
  hp-wmi: Switch driver to dev_pm_ops
  floppy: Switch driver to dev_pm_ops
  PM: Trivial fixes
  PM / Hibernate / Memory hotplug: Always use for_each_populated_zone()
  PM/Hibernate: Do not try to allocate too much memory too hard (rev. 2)
  PM/Hibernate: Do not release preallocated memory unnecessarily (rev. 2)
  PM/Hibernate: Rework shrinking of memory
  PM: Fix typo in label name s/Platofrm_finish/Platform_finish/
  PM: Run-time PM platform device bus support
  PM: Introduce core framework for run-time PM of I/O devices (rev. 17)
  Driver Core: Make PM operations a const pointer
  PM: Remove platform device suspend_late()/resume_early() V2
  USB: Rework musb suspend()/resume_early()
  I2C: Rework i2c-s3c2410 suspend_late()/resume() V2
  I2C: Rework i2c-pxa suspend_late()/resume_early()
  DMA: Rework txx9dmac suspend_late()/resume_early()
  ...

Fix trivial conflict in drivers/base/platform.c (due to same
constification patch being merged in both sides, along with some other
PM work in the PM branch)
parents c91d7d54 33f82d14
This diff is collapsed.
...@@ -12,4 +12,7 @@ struct dev_archdata { ...@@ -12,4 +12,7 @@ struct dev_archdata {
#endif #endif
}; };
struct pdev_archdata {
};
#endif #endif
...@@ -281,24 +281,27 @@ static int /* __init */ fpga_probe(struct platform_device *pdev) ...@@ -281,24 +281,27 @@ static int /* __init */ fpga_probe(struct platform_device *pdev)
return 0; return 0;
} }
static int fpga_suspend_late(struct platform_device *pdev, pm_message_t mesg) static int fpga_suspend_noirq(struct device *dev)
{ {
__raw_writew(~0, &fpga->leds); __raw_writew(~0, &fpga->leds);
return 0; return 0;
} }
static int fpga_resume_early(struct platform_device *pdev) static int fpga_resume_noirq(struct device *dev)
{ {
__raw_writew(~hw_led_state, &fpga->leds); __raw_writew(~hw_led_state, &fpga->leds);
return 0; return 0;
} }
static struct dev_pm_ops fpga_dev_pm_ops = {
.suspend_noirq = fpga_suspend_noirq,
.resume_noirq = fpga_resume_noirq,
};
static struct platform_driver led_driver = { static struct platform_driver led_driver = {
.driver.name = "omap_dbg_led", .driver.name = "omap_dbg_led",
.driver.pm = &fpga_dev_pm_ops,
.probe = fpga_probe, .probe = fpga_probe,
.suspend_late = fpga_suspend_late,
.resume_early = fpga_resume_early,
}; };
static int __init fpga_init(void) static int __init fpga_init(void)
......
...@@ -1418,8 +1418,9 @@ static struct irq_chip mpuio_irq_chip = { ...@@ -1418,8 +1418,9 @@ static struct irq_chip mpuio_irq_chip = {
#include <linux/platform_device.h> #include <linux/platform_device.h>
static int omap_mpuio_suspend_late(struct platform_device *pdev, pm_message_t mesg) static int omap_mpuio_suspend_noirq(struct device *dev)
{ {
struct platform_device *pdev = to_platform_device(dev);
struct gpio_bank *bank = platform_get_drvdata(pdev); struct gpio_bank *bank = platform_get_drvdata(pdev);
void __iomem *mask_reg = bank->base + OMAP_MPUIO_GPIO_MASKIT; void __iomem *mask_reg = bank->base + OMAP_MPUIO_GPIO_MASKIT;
unsigned long flags; unsigned long flags;
...@@ -1432,8 +1433,9 @@ static int omap_mpuio_suspend_late(struct platform_device *pdev, pm_message_t me ...@@ -1432,8 +1433,9 @@ static int omap_mpuio_suspend_late(struct platform_device *pdev, pm_message_t me
return 0; return 0;
} }
static int omap_mpuio_resume_early(struct platform_device *pdev) static int omap_mpuio_resume_noirq(struct device *dev)
{ {
struct platform_device *pdev = to_platform_device(dev);
struct gpio_bank *bank = platform_get_drvdata(pdev); struct gpio_bank *bank = platform_get_drvdata(pdev);
void __iomem *mask_reg = bank->base + OMAP_MPUIO_GPIO_MASKIT; void __iomem *mask_reg = bank->base + OMAP_MPUIO_GPIO_MASKIT;
unsigned long flags; unsigned long flags;
...@@ -1445,14 +1447,18 @@ static int omap_mpuio_resume_early(struct platform_device *pdev) ...@@ -1445,14 +1447,18 @@ static int omap_mpuio_resume_early(struct platform_device *pdev)
return 0; return 0;
} }
static struct dev_pm_ops omap_mpuio_dev_pm_ops = {
.suspend_noirq = omap_mpuio_suspend_noirq,
.resume_noirq = omap_mpuio_resume_noirq,
};
/* use platform_driver for this, now that there's no longer any /* use platform_driver for this, now that there's no longer any
* point to sys_device (other than not disturbing old code). * point to sys_device (other than not disturbing old code).
*/ */
static struct platform_driver omap_mpuio_driver = { static struct platform_driver omap_mpuio_driver = {
.suspend_late = omap_mpuio_suspend_late,
.resume_early = omap_mpuio_resume_early,
.driver = { .driver = {
.name = "mpuio", .name = "mpuio",
.pm = &omap_mpuio_dev_pm_ops,
}, },
}; };
......
...@@ -15,4 +15,7 @@ struct dev_archdata { ...@@ -15,4 +15,7 @@ struct dev_archdata {
#endif #endif
}; };
struct pdev_archdata {
};
#endif /* _ASM_IA64_DEVICE_H */ #endif /* _ASM_IA64_DEVICE_H */
...@@ -16,6 +16,9 @@ struct dev_archdata { ...@@ -16,6 +16,9 @@ struct dev_archdata {
struct device_node *of_node; struct device_node *of_node;
}; };
struct pdev_archdata {
};
#endif /* _ASM_MICROBLAZE_DEVICE_H */ #endif /* _ASM_MICROBLAZE_DEVICE_H */
...@@ -30,4 +30,7 @@ dev_archdata_get_node(const struct dev_archdata *ad) ...@@ -30,4 +30,7 @@ dev_archdata_get_node(const struct dev_archdata *ad)
return ad->of_node; return ad->of_node;
} }
struct pdev_archdata {
};
#endif /* _ASM_POWERPC_DEVICE_H */ #endif /* _ASM_POWERPC_DEVICE_H */
...@@ -32,4 +32,7 @@ dev_archdata_get_node(const struct dev_archdata *ad) ...@@ -32,4 +32,7 @@ dev_archdata_get_node(const struct dev_archdata *ad)
return ad->prom_node; return ad->prom_node;
} }
struct pdev_archdata {
};
#endif /* _ASM_SPARC_DEVICE_H */ #endif /* _ASM_SPARC_DEVICE_H */
...@@ -13,4 +13,7 @@ struct dma_map_ops *dma_ops; ...@@ -13,4 +13,7 @@ struct dma_map_ops *dma_ops;
#endif #endif
}; };
struct pdev_archdata {
};
#endif /* _ASM_X86_DEVICE_H */ #endif /* _ASM_X86_DEVICE_H */
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include <linux/kthread.h> #include <linux/kthread.h>
#include <linux/wait.h> #include <linux/wait.h>
#include <linux/async.h> #include <linux/async.h>
#include <linux/pm_runtime.h>
#include "base.h" #include "base.h"
#include "power/power.h" #include "power/power.h"
...@@ -202,7 +203,10 @@ int driver_probe_device(struct device_driver *drv, struct device *dev) ...@@ -202,7 +203,10 @@ int driver_probe_device(struct device_driver *drv, struct device *dev)
pr_debug("bus: '%s': %s: matched device %s with driver %s\n", pr_debug("bus: '%s': %s: matched device %s with driver %s\n",
drv->bus->name, __func__, dev_name(dev), drv->name); drv->bus->name, __func__, dev_name(dev), drv->name);
pm_runtime_get_noresume(dev);
pm_runtime_barrier(dev);
ret = really_probe(dev, drv); ret = really_probe(dev, drv);
pm_runtime_put_sync(dev);
return ret; return ret;
} }
...@@ -245,7 +249,9 @@ int device_attach(struct device *dev) ...@@ -245,7 +249,9 @@ int device_attach(struct device *dev)
ret = 0; ret = 0;
} }
} else { } else {
pm_runtime_get_noresume(dev);
ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach); ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach);
pm_runtime_put_sync(dev);
} }
up(&dev->sem); up(&dev->sem);
return ret; return ret;
...@@ -306,6 +312,9 @@ static void __device_release_driver(struct device *dev) ...@@ -306,6 +312,9 @@ static void __device_release_driver(struct device *dev)
drv = dev->driver; drv = dev->driver;
if (drv) { if (drv) {
pm_runtime_get_noresume(dev);
pm_runtime_barrier(dev);
driver_sysfs_remove(dev); driver_sysfs_remove(dev);
if (dev->bus) if (dev->bus)
...@@ -324,6 +333,8 @@ static void __device_release_driver(struct device *dev) ...@@ -324,6 +333,8 @@ static void __device_release_driver(struct device *dev)
blocking_notifier_call_chain(&dev->bus->p->bus_notifier, blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
BUS_NOTIFY_UNBOUND_DRIVER, BUS_NOTIFY_UNBOUND_DRIVER,
dev); dev);
pm_runtime_put_sync(dev);
} }
} }
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <linux/bootmem.h> #include <linux/bootmem.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/pm_runtime.h>
#include "base.h" #include "base.h"
...@@ -625,30 +626,6 @@ static int platform_legacy_suspend(struct device *dev, pm_message_t mesg) ...@@ -625,30 +626,6 @@ static int platform_legacy_suspend(struct device *dev, pm_message_t mesg)
return ret; return ret;
} }
static int platform_legacy_suspend_late(struct device *dev, pm_message_t mesg)
{
struct platform_driver *pdrv = to_platform_driver(dev->driver);
struct platform_device *pdev = to_platform_device(dev);
int ret = 0;
if (dev->driver && pdrv->suspend_late)
ret = pdrv->suspend_late(pdev, mesg);
return ret;
}
static int platform_legacy_resume_early(struct device *dev)
{
struct platform_driver *pdrv = to_platform_driver(dev->driver);
struct platform_device *pdev = to_platform_device(dev);
int ret = 0;
if (dev->driver && pdrv->resume_early)
ret = pdrv->resume_early(pdev);
return ret;
}
static int platform_legacy_resume(struct device *dev) static int platform_legacy_resume(struct device *dev)
{ {
struct platform_driver *pdrv = to_platform_driver(dev->driver); struct platform_driver *pdrv = to_platform_driver(dev->driver);
...@@ -680,6 +657,13 @@ static void platform_pm_complete(struct device *dev) ...@@ -680,6 +657,13 @@ static void platform_pm_complete(struct device *dev)
drv->pm->complete(dev); drv->pm->complete(dev);
} }
#else /* !CONFIG_PM_SLEEP */
#define platform_pm_prepare NULL
#define platform_pm_complete NULL
#endif /* !CONFIG_PM_SLEEP */
#ifdef CONFIG_SUSPEND #ifdef CONFIG_SUSPEND
static int platform_pm_suspend(struct device *dev) static int platform_pm_suspend(struct device *dev)
...@@ -711,8 +695,6 @@ static int platform_pm_suspend_noirq(struct device *dev) ...@@ -711,8 +695,6 @@ static int platform_pm_suspend_noirq(struct device *dev)
if (drv->pm) { if (drv->pm) {
if (drv->pm->suspend_noirq) if (drv->pm->suspend_noirq)
ret = drv->pm->suspend_noirq(dev); ret = drv->pm->suspend_noirq(dev);
} else {
ret = platform_legacy_suspend_late(dev, PMSG_SUSPEND);
} }
return ret; return ret;
...@@ -747,8 +729,6 @@ static int platform_pm_resume_noirq(struct device *dev) ...@@ -747,8 +729,6 @@ static int platform_pm_resume_noirq(struct device *dev)
if (drv->pm) { if (drv->pm) {
if (drv->pm->resume_noirq) if (drv->pm->resume_noirq)
ret = drv->pm->resume_noirq(dev); ret = drv->pm->resume_noirq(dev);
} else {
ret = platform_legacy_resume_early(dev);
} }
return ret; return ret;
...@@ -794,8 +774,6 @@ static int platform_pm_freeze_noirq(struct device *dev) ...@@ -794,8 +774,6 @@ static int platform_pm_freeze_noirq(struct device *dev)
if (drv->pm) { if (drv->pm) {
if (drv->pm->freeze_noirq) if (drv->pm->freeze_noirq)
ret = drv->pm->freeze_noirq(dev); ret = drv->pm->freeze_noirq(dev);
} else {
ret = platform_legacy_suspend_late(dev, PMSG_FREEZE);
} }
return ret; return ret;
...@@ -830,8 +808,6 @@ static int platform_pm_thaw_noirq(struct device *dev) ...@@ -830,8 +808,6 @@ static int platform_pm_thaw_noirq(struct device *dev)
if (drv->pm) { if (drv->pm) {
if (drv->pm->thaw_noirq) if (drv->pm->thaw_noirq)
ret = drv->pm->thaw_noirq(dev); ret = drv->pm->thaw_noirq(dev);
} else {
ret = platform_legacy_resume_early(dev);
} }
return ret; return ret;
...@@ -866,8 +842,6 @@ static int platform_pm_poweroff_noirq(struct device *dev) ...@@ -866,8 +842,6 @@ static int platform_pm_poweroff_noirq(struct device *dev)
if (drv->pm) { if (drv->pm) {
if (drv->pm->poweroff_noirq) if (drv->pm->poweroff_noirq)
ret = drv->pm->poweroff_noirq(dev); ret = drv->pm->poweroff_noirq(dev);
} else {
ret = platform_legacy_suspend_late(dev, PMSG_HIBERNATE);
} }
return ret; return ret;
...@@ -902,8 +876,6 @@ static int platform_pm_restore_noirq(struct device *dev) ...@@ -902,8 +876,6 @@ static int platform_pm_restore_noirq(struct device *dev)
if (drv->pm) { if (drv->pm) {
if (drv->pm->restore_noirq) if (drv->pm->restore_noirq)
ret = drv->pm->restore_noirq(dev); ret = drv->pm->restore_noirq(dev);
} else {
ret = platform_legacy_resume_early(dev);
} }
return ret; return ret;
...@@ -922,6 +894,31 @@ static int platform_pm_restore_noirq(struct device *dev) ...@@ -922,6 +894,31 @@ static int platform_pm_restore_noirq(struct device *dev)
#endif /* !CONFIG_HIBERNATION */ #endif /* !CONFIG_HIBERNATION */
#ifdef CONFIG_PM_RUNTIME
int __weak platform_pm_runtime_suspend(struct device *dev)
{
return -ENOSYS;
};
int __weak platform_pm_runtime_resume(struct device *dev)
{
return -ENOSYS;
};
int __weak platform_pm_runtime_idle(struct device *dev)
{
return -ENOSYS;
};
#else /* !CONFIG_PM_RUNTIME */
#define platform_pm_runtime_suspend NULL
#define platform_pm_runtime_resume NULL
#define platform_pm_runtime_idle NULL
#endif /* !CONFIG_PM_RUNTIME */
static const struct dev_pm_ops platform_dev_pm_ops = { static const struct dev_pm_ops platform_dev_pm_ops = {
.prepare = platform_pm_prepare, .prepare = platform_pm_prepare,
.complete = platform_pm_complete, .complete = platform_pm_complete,
...@@ -937,22 +934,17 @@ static const struct dev_pm_ops platform_dev_pm_ops = { ...@@ -937,22 +934,17 @@ static const struct dev_pm_ops platform_dev_pm_ops = {
.thaw_noirq = platform_pm_thaw_noirq, .thaw_noirq = platform_pm_thaw_noirq,
.poweroff_noirq = platform_pm_poweroff_noirq, .poweroff_noirq = platform_pm_poweroff_noirq,
.restore_noirq = platform_pm_restore_noirq, .restore_noirq = platform_pm_restore_noirq,
.runtime_suspend = platform_pm_runtime_suspend,
.runtime_resume = platform_pm_runtime_resume,
.runtime_idle = platform_pm_runtime_idle,
}; };
#define PLATFORM_PM_OPS_PTR (&platform_dev_pm_ops)
#else /* !CONFIG_PM_SLEEP */
#define PLATFORM_PM_OPS_PTR NULL
#endif /* !CONFIG_PM_SLEEP */
struct bus_type platform_bus_type = { struct bus_type platform_bus_type = {
.name = "platform", .name = "platform",
.dev_attrs = platform_dev_attrs, .dev_attrs = platform_dev_attrs,
.match = platform_match, .match = platform_match,
.uevent = platform_uevent, .uevent = platform_uevent,
.pm = PLATFORM_PM_OPS_PTR, .pm = &platform_dev_pm_ops,
}; };
EXPORT_SYMBOL_GPL(platform_bus_type); EXPORT_SYMBOL_GPL(platform_bus_type);
......
obj-$(CONFIG_PM) += sysfs.o obj-$(CONFIG_PM) += sysfs.o
obj-$(CONFIG_PM_SLEEP) += main.o obj-$(CONFIG_PM_SLEEP) += main.o
obj-$(CONFIG_PM_RUNTIME) += runtime.o
obj-$(CONFIG_PM_TRACE_RTC) += trace.o obj-$(CONFIG_PM_TRACE_RTC) += trace.o
ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG
......
This diff is collapsed.
static inline void device_pm_init(struct device *dev) #ifdef CONFIG_PM_RUNTIME
{
dev->power.status = DPM_ON; extern void pm_runtime_init(struct device *dev);
} extern void pm_runtime_remove(struct device *dev);
#else /* !CONFIG_PM_RUNTIME */
static inline void pm_runtime_init(struct device *dev) {}
static inline void pm_runtime_remove(struct device *dev) {}
#endif /* !CONFIG_PM_RUNTIME */
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
...@@ -16,23 +23,33 @@ static inline struct device *to_device(struct list_head *entry) ...@@ -16,23 +23,33 @@ static inline struct device *to_device(struct list_head *entry)
return container_of(entry, struct device, power.entry); return container_of(entry, struct device, power.entry);
} }
extern void device_pm_init(struct device *dev);
extern void device_pm_add(struct device *); extern void device_pm_add(struct device *);
extern void device_pm_remove(struct device *); extern void device_pm_remove(struct device *);
extern void device_pm_move_before(struct device *, struct device *); extern void device_pm_move_before(struct device *, struct device *);
extern void device_pm_move_after(struct device *, struct device *); extern void device_pm_move_after(struct device *, struct device *);
extern void device_pm_move_last(struct device *); extern void device_pm_move_last(struct device *);
#else /* CONFIG_PM_SLEEP */ #else /* !CONFIG_PM_SLEEP */
static inline void device_pm_init(struct device *dev)
{
pm_runtime_init(dev);
}
static inline void device_pm_remove(struct device *dev)
{
pm_runtime_remove(dev);
}
static inline void device_pm_add(struct device *dev) {} static inline void device_pm_add(struct device *dev) {}
static inline void device_pm_remove(struct device *dev) {}
static inline void device_pm_move_before(struct device *deva, static inline void device_pm_move_before(struct device *deva,
struct device *devb) {} struct device *devb) {}
static inline void device_pm_move_after(struct device *deva, static inline void device_pm_move_after(struct device *deva,
struct device *devb) {} struct device *devb) {}
static inline void device_pm_move_last(struct device *dev) {} static inline void device_pm_move_last(struct device *dev) {}
#endif #endif /* !CONFIG_PM_SLEEP */
#ifdef CONFIG_PM #ifdef CONFIG_PM
......
This diff is collapsed.
...@@ -4151,7 +4151,7 @@ static void floppy_device_release(struct device *dev) ...@@ -4151,7 +4151,7 @@ static void floppy_device_release(struct device *dev)
{ {
} }
static int floppy_resume(struct platform_device *dev) static int floppy_resume(struct device *dev)
{ {
int fdc; int fdc;
...@@ -4162,10 +4162,15 @@ static int floppy_resume(struct platform_device *dev) ...@@ -4162,10 +4162,15 @@ static int floppy_resume(struct platform_device *dev)
return 0; return 0;
} }
static struct platform_driver floppy_driver = { static struct dev_pm_ops floppy_pm_ops = {
.resume = floppy_resume, .resume = floppy_resume,
.restore = floppy_resume,
};
static struct platform_driver floppy_driver = {
.driver = { .driver = {
.name = "floppy", .name = "floppy",
.pm = &floppy_pm_ops,
}, },
}; };
......
...@@ -1166,32 +1166,37 @@ static void at_dma_shutdown(struct platform_device *pdev) ...@@ -1166,32 +1166,37 @@ static void at_dma_shutdown(struct platform_device *pdev)
clk_disable(atdma->clk); clk_disable(atdma->clk);
} }
static int at_dma_suspend_late(struct platform_device *pdev, pm_message_t mesg) static int at_dma_suspend_noirq(struct device *dev)
{ {
struct at_dma *atdma = platform_get_drvdata(pdev); struct platform_device *pdev = to_platform_device(dev);
struct at_dma *atdma = platform_get_drvdata(pdev);
at_dma_off(platform_get_drvdata(pdev)); at_dma_off(platform_get_drvdata(pdev));
clk_disable(atdma->clk); clk_disable(atdma->clk);
return 0; return 0;
} }
static int at_dma_resume_early(struct platform_device *pdev) static int at_dma_resume_noirq(struct device *dev)
{ {
struct at_dma *atdma = platform_get_drvdata(pdev); struct platform_device *pdev = to_platform_device(dev);
struct at_dma *atdma = platform_get_drvdata(pdev);
clk_enable(atdma->clk); clk_enable(atdma->clk);
dma_writel(atdma, EN, AT_DMA_ENABLE); dma_writel(atdma, EN, AT_DMA_ENABLE);
return 0; return 0;
} }
static struct dev_pm_ops at_dma_dev_pm_ops = {
.suspend_noirq = at_dma_suspend_noirq,
.resume_noirq = at_dma_resume_noirq,
};
static struct platform_driver at_dma_driver = { static struct platform_driver at_dma_driver = {
.remove = __exit_p(at_dma_remove), .remove = __exit_p(at_dma_remove),
.shutdown = at_dma_shutdown, .shutdown = at_dma_shutdown,
.suspend_late = at_dma_suspend_late,
.resume_early = at_dma_resume_early,
.driver = { .driver = {
.name = "at_hdmac", .name = "at_hdmac",
.pm = &at_dma_dev_pm_ops,
}, },
}; };
......
...@@ -1399,8 +1399,9 @@ static void dw_shutdown(struct platform_device *pdev) ...@@ -1399,8 +1399,9 @@ static void dw_shutdown(struct platform_device *pdev)
clk_disable(dw->clk); clk_disable(dw->clk);
} }
static int dw_suspend_late(struct platform_device *pdev, pm_message_t mesg) static int dw_suspend_noirq(struct device *dev)
{ {
struct platform_device *pdev = to_platform_device(dev);
struct dw_dma *dw = platform_get_drvdata(pdev); struct dw_dma *dw = platform_get_drvdata(pdev);
dw_dma_off(platform_get_drvdata(pdev)); dw_dma_off(platform_get_drvdata(pdev));
...@@ -1408,23 +1409,27 @@ static int dw_suspend_late(struct platform_device *pdev, pm_message_t mesg) ...@@ -1408,23 +1409,27 @@ static int dw_suspend_late(struct platform_device *pdev, pm_message_t mesg)
return 0; return 0;
} }
static int dw_resume_early(struct platform_device *pdev) static int dw_resume_noirq(struct device *dev)
{ {
struct platform_device *pdev = to_platform_device(dev);
struct dw_dma *dw = platform_get_drvdata(pdev); struct dw_dma *dw = platform_get_drvdata(pdev);
clk_enable(dw->clk); clk_enable(dw->clk);
dma_writel(dw, CFG, DW_CFG_DMA_EN); dma_writel(dw, CFG, DW_CFG_DMA_EN);
return 0; return 0;
} }
static struct dev_pm_ops dw_dev_pm_ops = {
.suspend_noirq = dw_suspend_noirq,
.resume_noirq = dw_resume_noirq,
};
static struct platform_driver dw_driver = { static struct platform_driver dw_driver = {
.remove = __exit_p(dw_remove), .remove = __exit_p(dw_remove),
.shutdown = dw_shutdown, .shutdown = dw_shutdown,
.suspend_late = dw_suspend_late,
.resume_early = dw_resume_early,
.driver = { .driver = {
.name = "dw_dmac", .name = "dw_dmac",
.pm = &dw_dev_pm_ops,
}, },
}; };
......
...@@ -1291,17 +1291,18 @@ static void txx9dmac_shutdown(struct platform_device *pdev) ...@@ -1291,17 +1291,18 @@ static void txx9dmac_shutdown(struct platform_device *pdev)
txx9dmac_off(ddev); txx9dmac_off(ddev);
} }
static int txx9dmac_suspend_late(struct platform_device *pdev, static int txx9dmac_suspend_noirq(struct device *dev)
pm_message_t mesg)
{ {
struct platform_device *pdev = to_platform_device(dev);
struct txx9dmac_dev *ddev = platform_get_drvdata(pdev); struct txx9dmac_dev *ddev = platform_get_drvdata(pdev);
txx9dmac_off(ddev); txx9dmac_off(ddev);
return 0; return 0;
} }
static int txx9dmac_resume_early(struct platform_device *pdev) static int txx9dmac_resume_noirq(struct device *dev)
{ {
struct platform_device *pdev = to_platform_device(dev);
struct txx9dmac_dev *ddev = platform_get_drvdata(pdev); struct txx9dmac_dev *ddev = platform_get_drvdata(pdev);
struct txx9dmac_platform_data *pdata = pdev->dev.platform_data; struct txx9dmac_platform_data *pdata = pdev->dev.platform_data;
u32 mcr; u32 mcr;
...@@ -1314,6 +1315,11 @@ static int txx9dmac_resume_early(struct platform_device *pdev) ...@@ -1314,6 +1315,11 @@ static int txx9dmac_resume_early(struct platform_device *pdev)
} }
static struct dev_pm_ops txx9dmac_dev_pm_ops = {
.suspend_noirq = txx9dmac_suspend_noirq,
.resume_noirq = txx9dmac_resume_noirq,
};
static struct platform_driver txx9dmac_chan_driver = { static struct platform_driver txx9dmac_chan_driver = {
.remove = __exit_p(txx9dmac_chan_remove), .remove = __exit_p(txx9dmac_chan_remove),
.driver = { .driver = {
...@@ -1324,10 +1330,9 @@ static struct platform_driver txx9dmac_chan_driver = { ...@@ -1324,10 +1330,9 @@ static struct platform_driver txx9dmac_chan_driver = {
static struct platform_driver txx9dmac_driver = { static struct platform_driver txx9dmac_driver = {
.remove = __exit_p(txx9dmac_remove), .remove = __exit_p(txx9dmac_remove),
.shutdown = txx9dmac_shutdown, .shutdown = txx9dmac_shutdown,
.suspend_late = txx9dmac_suspend_late,
.resume_early = txx9dmac_resume_early,
.driver = { .driver = {
.name = "txx9dmac", .name = "txx9dmac",
.pm = &txx9dmac_dev_pm_ops,
}, },
}; };
......
...@@ -1134,35 +1134,44 @@ static int __exit i2c_pxa_remove(struct platform_device *dev) ...@@ -1134,35 +1134,44 @@ static int __exit i2c_pxa_remove(struct platform_device *dev)
} }
#ifdef CONFIG_PM #ifdef CONFIG_PM
static int i2c_pxa_suspend_late(struct platform_device *dev, pm_message_t state) static int i2c_pxa_suspend_noirq(struct device *dev)
{ {
struct pxa_i2c *i2c = platform_get_drvdata(dev); struct platform_device *pdev = to_platform_device(dev);
struct pxa_i2c *i2c = platform_get_drvdata(pdev);
clk_disable(i2c->clk); clk_disable(i2c->clk);
return 0; return 0;
} }
static int i2c_pxa_resume_early(struct platform_device *dev) static int i2c_pxa_resume_noirq(struct device *dev)
{ {
struct pxa_i2c *i2c = platform_get_drvdata(dev); struct platform_device *pdev = to_platform_device(dev);
struct pxa_i2c *i2c = platform_get_drvdata(pdev);
clk_enable(i2c->clk); clk_enable(i2c->clk);
i2c_pxa_reset(i2c); i2c_pxa_reset(i2c);
return 0; return 0;
} }
static struct dev_pm_ops i2c_pxa_dev_pm_ops = {
.suspend_noirq = i2c_pxa_suspend_noirq,
.resume_noirq = i2c_pxa_resume_noirq,
};
#define I2C_PXA_DEV_PM_OPS (&i2c_pxa_dev_pm_ops)
#else #else
#define i2c_pxa_suspend_late NULL #define I2C_PXA_DEV_PM_OPS NULL
#define i2c_pxa_resume_early NULL
#endif #endif
static struct platform_driver i2c_pxa_driver = { static struct platform_driver i2c_pxa_driver = {
.probe = i2c_pxa_probe, .probe = i2c_pxa_probe,
.remove = __exit_p(i2c_pxa_remove), .remove = __exit_p(i2c_pxa_remove),
.suspend_late = i2c_pxa_suspend_late,
.resume_early = i2c_pxa_resume_early,
.driver = { .driver = {
.name = "pxa2xx-i2c", .name = "pxa2xx-i2c",
.owner = THIS_MODULE, .owner = THIS_MODULE,
.pm = I2C_PXA_DEV_PM_OPS,
}, },
.id_table = i2c_pxa_id_table, .id_table = i2c_pxa_id_table,
}; };
......
...@@ -946,17 +946,20 @@ static int s3c24xx_i2c_remove(struct platform_device *pdev) ...@@ -946,17 +946,20 @@ static int s3c24xx_i2c_remove(struct platform_device *pdev)
} }
#ifdef CONFIG_PM #ifdef CONFIG_PM
static int s3c24xx_i2c_suspend_late(struct platform_device *dev, static int s3c24xx_i2c_suspend_noirq(struct device *dev)
pm_message_t msg)
{ {
struct s3c24xx_i2c *i2c = platform_get_drvdata(dev); struct platform_device *pdev = to_platform_device(dev);
struct s3c24xx_i2c *i2c = platform_get_drvdata(pdev);
i2c->suspended = 1; i2c->suspended = 1;
return 0; return 0;
} }
static int s3c24xx_i2c_resume(struct platform_device *dev) static int s3c24xx_i2c_resume(struct device *dev)
{ {
struct s3c24xx_i2c *i2c = platform_get_drvdata(dev); struct platform_device *pdev = to_platform_device(dev);
struct s3c24xx_i2c *i2c = platform_get_drvdata(pdev);
i2c->suspended = 0; i2c->suspended = 0;
s3c24xx_i2c_init(i2c); s3c24xx_i2c_init(i2c);
...@@ -964,9 +967,14 @@ static int s3c24xx_i2c_resume(struct platform_device *dev) ...@@ -964,9 +967,14 @@ static int s3c24xx_i2c_resume(struct platform_device *dev)
return 0; return 0;
} }
static struct dev_pm_ops s3c24xx_i2c_dev_pm_ops = {
.suspend_noirq = s3c24xx_i2c_suspend_noirq,
.resume = s3c24xx_i2c_resume,
};
#define S3C24XX_DEV_PM_OPS (&s3c24xx_i2c_dev_pm_ops)
#else #else
#define s3c24xx_i2c_suspend_late NULL #define S3C24XX_DEV_PM_OPS NULL
#define s3c24xx_i2c_resume NULL
#endif #endif
/* device driver for platform bus bits */ /* device driver for platform bus bits */
...@@ -985,12 +993,11 @@ MODULE_DEVICE_TABLE(platform, s3c24xx_driver_ids); ...@@ -985,12 +993,11 @@ MODULE_DEVICE_TABLE(platform, s3c24xx_driver_ids);
static struct platform_driver s3c24xx_i2c_driver = { static struct platform_driver s3c24xx_i2c_driver = {
.probe = s3c24xx_i2c_probe, .probe = s3c24xx_i2c_probe,
.remove = s3c24xx_i2c_remove, .remove = s3c24xx_i2c_remove,
.suspend_late = s3c24xx_i2c_suspend_late,
.resume = s3c24xx_i2c_resume,
.id_table = s3c24xx_driver_ids, .id_table = s3c24xx_driver_ids,
.driver = { .driver = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.name = "s3c-i2c", .name = "s3c-i2c",
.pm = S3C24XX_DEV_PM_OPS,
}, },
}; };
......
...@@ -53,7 +53,7 @@ MODULE_ALIAS("wmi:5FB7F034-2C63-45e9-BE91-3D44E2C707E4"); ...@@ -53,7 +53,7 @@ MODULE_ALIAS("wmi:5FB7F034-2C63-45e9-BE91-3D44E2C707E4");
static int __init hp_wmi_bios_setup(struct platform_device *device); static int __init hp_wmi_bios_setup(struct platform_device *device);
static int __exit hp_wmi_bios_remove(struct platform_device *device); static int __exit hp_wmi_bios_remove(struct platform_device *device);
static int hp_wmi_resume_handler(struct platform_device *device); static int hp_wmi_resume_handler(struct device *device);
struct bios_args { struct bios_args {
u32 signature; u32 signature;
...@@ -94,14 +94,19 @@ static struct rfkill *wifi_rfkill; ...@@ -94,14 +94,19 @@ static struct rfkill *wifi_rfkill;
static struct rfkill *bluetooth_rfkill; static struct rfkill *bluetooth_rfkill;
static struct rfkill *wwan_rfkill; static struct rfkill *wwan_rfkill;
static struct dev_pm_ops hp_wmi_pm_ops = {
.resume = hp_wmi_resume_handler,
.restore = hp_wmi_resume_handler,
};
static struct platform_driver hp_wmi_driver = { static struct platform_driver hp_wmi_driver = {
.driver = { .driver = {
.name = "hp-wmi", .name = "hp-wmi",
.owner = THIS_MODULE, .owner = THIS_MODULE,
.pm = &hp_wmi_pm_ops,
}, },
.probe = hp_wmi_bios_setup, .probe = hp_wmi_bios_setup,
.remove = hp_wmi_bios_remove, .remove = hp_wmi_bios_remove,
.resume = hp_wmi_resume_handler,
}; };
static int hp_wmi_perform_query(int query, int write, int value) static int hp_wmi_perform_query(int query, int write, int value)
...@@ -512,7 +517,7 @@ static int __exit hp_wmi_bios_remove(struct platform_device *device) ...@@ -512,7 +517,7 @@ static int __exit hp_wmi_bios_remove(struct platform_device *device)
return 0; return 0;
} }
static int hp_wmi_resume_handler(struct platform_device *device) static int hp_wmi_resume_handler(struct device *device)
{ {
/* /*
* Hardware state may have changed while suspended, so trigger * Hardware state may have changed while suspended, so trigger
......
...@@ -2167,8 +2167,9 @@ static int __devexit musb_remove(struct platform_device *pdev) ...@@ -2167,8 +2167,9 @@ static int __devexit musb_remove(struct platform_device *pdev)
#ifdef CONFIG_PM #ifdef CONFIG_PM
static int musb_suspend(struct platform_device *pdev, pm_message_t message) static int musb_suspend(struct device *dev)
{ {
struct platform_device *pdev = to_platform_device(dev);
unsigned long flags; unsigned long flags;
struct musb *musb = dev_to_musb(&pdev->dev); struct musb *musb = dev_to_musb(&pdev->dev);
...@@ -2195,8 +2196,9 @@ static int musb_suspend(struct platform_device *pdev, pm_message_t message) ...@@ -2195,8 +2196,9 @@ static int musb_suspend(struct platform_device *pdev, pm_message_t message)
return 0; return 0;
} }
static int musb_resume_early(struct platform_device *pdev) static int musb_resume_noirq(struct device *dev)
{ {
struct platform_device *pdev = to_platform_device(dev);
struct musb *musb = dev_to_musb(&pdev->dev); struct musb *musb = dev_to_musb(&pdev->dev);
if (!musb->clock) if (!musb->clock)
...@@ -2214,9 +2216,14 @@ static int musb_resume_early(struct platform_device *pdev) ...@@ -2214,9 +2216,14 @@ static int musb_resume_early(struct platform_device *pdev)
return 0; return 0;
} }
static struct dev_pm_ops musb_dev_pm_ops = {
.suspend = musb_suspend,
.resume_noirq = musb_resume_noirq,
};
#define MUSB_DEV_PM_OPS (&musb_dev_pm_ops)
#else #else
#define musb_suspend NULL #define MUSB_DEV_PM_OPS NULL
#define musb_resume_early NULL
#endif #endif
static struct platform_driver musb_driver = { static struct platform_driver musb_driver = {
...@@ -2224,11 +2231,10 @@ static struct platform_driver musb_driver = { ...@@ -2224,11 +2231,10 @@ static struct platform_driver musb_driver = {
.name = (char *)musb_driver_name, .name = (char *)musb_driver_name,
.bus = &platform_bus_type, .bus = &platform_bus_type,
.owner = THIS_MODULE, .owner = THIS_MODULE,
.pm = MUSB_DEV_PM_OPS,
}, },
.remove = __devexit_p(musb_remove), .remove = __devexit_p(musb_remove),
.shutdown = musb_shutdown, .shutdown = musb_shutdown,
.suspend = musb_suspend,
.resume_early = musb_resume_early,
}; };
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
......
...@@ -9,4 +9,7 @@ ...@@ -9,4 +9,7 @@
struct dev_archdata { struct dev_archdata {
}; };
struct pdev_archdata {
};
#endif /* _ASM_GENERIC_DEVICE_H */ #endif /* _ASM_GENERIC_DEVICE_H */
...@@ -22,6 +22,9 @@ struct platform_device { ...@@ -22,6 +22,9 @@ struct platform_device {
struct resource * resource; struct resource * resource;
struct platform_device_id *id_entry; struct platform_device_id *id_entry;
/* arch specific additions */
struct pdev_archdata archdata;
}; };
#define platform_get_device_id(pdev) ((pdev)->id_entry) #define platform_get_device_id(pdev) ((pdev)->id_entry)
...@@ -57,8 +60,6 @@ struct platform_driver { ...@@ -57,8 +60,6 @@ struct platform_driver {
int (*remove)(struct platform_device *); int (*remove)(struct platform_device *);
void (*shutdown)(struct platform_device *); void (*shutdown)(struct platform_device *);
int (*suspend)(struct platform_device *, pm_message_t state); int (*suspend)(struct platform_device *, pm_message_t state);
int (*suspend_late)(struct platform_device *, pm_message_t state);
int (*resume_early)(struct platform_device *);
int (*resume)(struct platform_device *); int (*resume)(struct platform_device *);
struct device_driver driver; struct device_driver driver;
struct platform_device_id *id_table; struct platform_device_id *id_table;
......
...@@ -22,6 +22,10 @@ ...@@ -22,6 +22,10 @@
#define _LINUX_PM_H #define _LINUX_PM_H
#include <linux/list.h> #include <linux/list.h>
#include <linux/workqueue.h>
#include <linux/spinlock.h>
#include <linux/wait.h>
#include <linux/timer.h>
/* /*
* Callbacks for platform drivers to implement. * Callbacks for platform drivers to implement.
...@@ -165,6 +169,28 @@ typedef struct pm_message { ...@@ -165,6 +169,28 @@ typedef struct pm_message {
* It is allowed to unregister devices while the above callbacks are being * It is allowed to unregister devices while the above callbacks are being
* executed. However, it is not allowed to unregister a device from within any * executed. However, it is not allowed to unregister a device from within any
* of its own callbacks. * of its own callbacks.
*
* There also are the following callbacks related to run-time power management
* of devices:
*
* @runtime_suspend: Prepare the device for a condition in which it won't be
* able to communicate with the CPU(s) and RAM due to power management.
* This need not mean that the device should be put into a low power state.
* For example, if the device is behind a link which is about to be turned
* off, the device may remain at full power. If the device does go to low
* power and if device_may_wakeup(dev) is true, remote wake-up (i.e., a
* hardware mechanism allowing the device to request a change of its power
* state, such as PCI PME) should be enabled for it.
*
* @runtime_resume: Put the device into the fully active state in response to a
* wake-up event generated by hardware or at the request of software. If
* necessary, put the device into the full power state and restore its
* registers, so that it is fully operational.
*
* @runtime_idle: Device appears to be inactive and it might be put into a low
* power state if all of the necessary conditions are satisfied. Check
* these conditions and handle the device as appropriate, possibly queueing
* a suspend request for it. The return value is ignored by the PM core.
*/ */
struct dev_pm_ops { struct dev_pm_ops {
...@@ -182,8 +208,25 @@ struct dev_pm_ops { ...@@ -182,8 +208,25 @@ struct dev_pm_ops {
int (*thaw_noirq)(struct device *dev); int (*thaw_noirq)(struct device *dev);
int (*poweroff_noirq)(struct device *dev); int (*poweroff_noirq)(struct device *dev);
int (*restore_noirq)(struct device *dev); int (*restore_noirq)(struct device *dev);
int (*runtime_suspend)(struct device *dev);
int (*runtime_resume)(struct device *dev);
int (*runtime_idle)(struct device *dev);
}; };
/*
* Use this if you want to use the same suspend and resume callbacks for suspend
* to RAM and hibernation.
*/
#define SIMPLE_DEV_PM_OPS(name, suspend_fn, resume_fn) \
struct dev_pm_ops name = { \
.suspend = suspend_fn, \
.resume = resume_fn, \
.freeze = suspend_fn, \
.thaw = resume_fn, \
.poweroff = suspend_fn, \
.restore = resume_fn, \
}
/** /**
* PM_EVENT_ messages * PM_EVENT_ messages
* *
...@@ -315,14 +358,80 @@ enum dpm_state { ...@@ -315,14 +358,80 @@ enum dpm_state {
DPM_OFF_IRQ, DPM_OFF_IRQ,
}; };
/**
* Device run-time power management status.
*
* These status labels are used internally by the PM core to indicate the
* current status of a device with respect to the PM core operations. They do
* not reflect the actual power state of the device or its status as seen by the
* driver.
*
* RPM_ACTIVE Device is fully operational. Indicates that the device
* bus type's ->runtime_resume() callback has completed
* successfully.
*
* RPM_SUSPENDED Device bus type's ->runtime_suspend() callback has
* completed successfully. The device is regarded as
* suspended.
*
* RPM_RESUMING Device bus type's ->runtime_resume() callback is being
* executed.
*
* RPM_SUSPENDING Device bus type's ->runtime_suspend() callback is being
* executed.
*/
enum rpm_status {
RPM_ACTIVE = 0,
RPM_RESUMING,
RPM_SUSPENDED,
RPM_SUSPENDING,
};
/**
* Device run-time power management request types.
*
* RPM_REQ_NONE Do nothing.
*
* RPM_REQ_IDLE Run the device bus type's ->runtime_idle() callback
*
* RPM_REQ_SUSPEND Run the device bus type's ->runtime_suspend() callback
*
* RPM_REQ_RESUME Run the device bus type's ->runtime_resume() callback
*/
enum rpm_request {
RPM_REQ_NONE = 0,
RPM_REQ_IDLE,
RPM_REQ_SUSPEND,
RPM_REQ_RESUME,
};
struct dev_pm_info { struct dev_pm_info {
pm_message_t power_state; pm_message_t power_state;
unsigned can_wakeup:1; unsigned int can_wakeup:1;
unsigned should_wakeup:1; unsigned int should_wakeup:1;
enum dpm_state status; /* Owned by the PM core */ enum dpm_state status; /* Owned by the PM core */
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
struct list_head entry; struct list_head entry;
#endif #endif
#ifdef CONFIG_PM_RUNTIME
struct timer_list suspend_timer;
unsigned long timer_expires;
struct work_struct work;
wait_queue_head_t wait_queue;
spinlock_t lock;
atomic_t usage_count;
atomic_t child_count;
unsigned int disable_depth:3;
unsigned int ignore_children:1;
unsigned int idle_notification:1;
unsigned int request_pending:1;
unsigned int deferred_resume:1;
enum rpm_request request;
enum rpm_status runtime_status;
int runtime_error;
#endif
}; };
/* /*
......
/*
* pm_runtime.h - Device run-time power management helper functions.
*
* Copyright (C) 2009 Rafael J. Wysocki <rjw@sisk.pl>
*
* This file is released under the GPLv2.
*/
#ifndef _LINUX_PM_RUNTIME_H
#define _LINUX_PM_RUNTIME_H
#include <linux/device.h>
#include <linux/pm.h>
#ifdef CONFIG_PM_RUNTIME
extern struct workqueue_struct *pm_wq;
extern int pm_runtime_idle(struct device *dev);
extern int pm_runtime_suspend(struct device *dev);
extern int pm_runtime_resume(struct device *dev);
extern int pm_request_idle(struct device *dev);
extern int pm_schedule_suspend(struct device *dev, unsigned int delay);
extern int pm_request_resume(struct device *dev);
extern int __pm_runtime_get(struct device *dev, bool sync);
extern int __pm_runtime_put(struct device *dev, bool sync);
extern int __pm_runtime_set_status(struct device *dev, unsigned int status);
extern int pm_runtime_barrier(struct device *dev);
extern void pm_runtime_enable(struct device *dev);
extern void __pm_runtime_disable(struct device *dev, bool check_resume);
static inline bool pm_children_suspended(struct device *dev)
{
return dev->power.ignore_children
|| !atomic_read(&dev->power.child_count);
}
static inline void pm_suspend_ignore_children(struct device *dev, bool enable)
{
dev->power.ignore_children = enable;
}
static inline void pm_runtime_get_noresume(struct device *dev)
{
atomic_inc(&dev->power.usage_count);
}
static inline void pm_runtime_put_noidle(struct device *dev)
{
atomic_add_unless(&dev->power.usage_count, -1, 0);
}
#else /* !CONFIG_PM_RUNTIME */
static inline int pm_runtime_idle(struct device *dev) { return -ENOSYS; }
static inline int pm_runtime_suspend(struct device *dev) { return -ENOSYS; }
static inline int pm_runtime_resume(struct device *dev) { return 0; }
static inline int pm_request_idle(struct device *dev) { return -ENOSYS; }
static inline int pm_schedule_suspend(struct device *dev, unsigned int delay)
{
return -ENOSYS;
}
static inline int pm_request_resume(struct device *dev) { return 0; }
static inline int __pm_runtime_get(struct device *dev, bool sync) { return 1; }
static inline int __pm_runtime_put(struct device *dev, bool sync) { return 0; }
static inline int __pm_runtime_set_status(struct device *dev,
unsigned int status) { return 0; }
static inline int pm_runtime_barrier(struct device *dev) { return 0; }
static inline void pm_runtime_enable(struct device *dev) {}
static inline void __pm_runtime_disable(struct device *dev, bool c) {}
static inline bool pm_children_suspended(struct device *dev) { return false; }
static inline void pm_suspend_ignore_children(struct device *dev, bool en) {}
static inline void pm_runtime_get_noresume(struct device *dev) {}
static inline void pm_runtime_put_noidle(struct device *dev) {}
#endif /* !CONFIG_PM_RUNTIME */
static inline int pm_runtime_get(struct device *dev)
{
return __pm_runtime_get(dev, false);
}
static inline int pm_runtime_get_sync(struct device *dev)
{
return __pm_runtime_get(dev, true);
}
static inline int pm_runtime_put(struct device *dev)
{
return __pm_runtime_put(dev, false);
}
static inline int pm_runtime_put_sync(struct device *dev)
{
return __pm_runtime_put(dev, true);
}
static inline int pm_runtime_set_active(struct device *dev)
{
return __pm_runtime_set_status(dev, RPM_ACTIVE);
}
static inline void pm_runtime_set_suspended(struct device *dev)
{
__pm_runtime_set_status(dev, RPM_SUSPENDED);
}
static inline void pm_runtime_disable(struct device *dev)
{
__pm_runtime_disable(dev, true);
}
#endif
...@@ -208,3 +208,17 @@ config APM_EMULATION ...@@ -208,3 +208,17 @@ config APM_EMULATION
random kernel OOPSes or reboots that don't seem to be related to random kernel OOPSes or reboots that don't seem to be related to
anything, try disabling/enabling this option (or disabling/enabling anything, try disabling/enabling this option (or disabling/enabling
APM in your BIOS). APM in your BIOS).
config PM_RUNTIME
bool "Run-time PM core functionality"
depends on PM
---help---
Enable functionality allowing I/O devices to be put into energy-saving
(low power) states at run time (or autosuspended) after a specified
period of inactivity and woken up in response to a hardware-generated
wake-up event or a driver's request.
Hardware support is generally required for this functionality to work
and the bus type drivers of the buses the devices are on are
responsible for the actual handling of the autosuspend requests and
wake-up events.
...@@ -298,8 +298,8 @@ int hibernation_snapshot(int platform_mode) ...@@ -298,8 +298,8 @@ int hibernation_snapshot(int platform_mode)
if (error) if (error)
return error; return error;
/* Free memory before shutting down devices. */ /* Preallocate image memory before shutting down devices. */
error = swsusp_shrink_memory(); error = hibernate_preallocate_memory();
if (error) if (error)
goto Close; goto Close;
...@@ -315,6 +315,10 @@ int hibernation_snapshot(int platform_mode) ...@@ -315,6 +315,10 @@ int hibernation_snapshot(int platform_mode)
/* Control returns here after successful restore */ /* Control returns here after successful restore */
Resume_devices: Resume_devices:
/* We may need to release the preallocated image pages here. */
if (error || !in_suspend)
swsusp_free();
dpm_resume_end(in_suspend ? dpm_resume_end(in_suspend ?
(error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE); (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE);
resume_console(); resume_console();
...@@ -460,11 +464,11 @@ int hibernation_platform_enter(void) ...@@ -460,11 +464,11 @@ int hibernation_platform_enter(void)
error = hibernation_ops->prepare(); error = hibernation_ops->prepare();
if (error) if (error)
goto Platofrm_finish; goto Platform_finish;
error = disable_nonboot_cpus(); error = disable_nonboot_cpus();
if (error) if (error)
goto Platofrm_finish; goto Platform_finish;
local_irq_disable(); local_irq_disable();
sysdev_suspend(PMSG_HIBERNATE); sysdev_suspend(PMSG_HIBERNATE);
...@@ -476,7 +480,7 @@ int hibernation_platform_enter(void) ...@@ -476,7 +480,7 @@ int hibernation_platform_enter(void)
* We don't need to reenable the nonboot CPUs or resume consoles, since * We don't need to reenable the nonboot CPUs or resume consoles, since
* the system is going to be halted anyway. * the system is going to be halted anyway.
*/ */
Platofrm_finish: Platform_finish:
hibernation_ops->finish(); hibernation_ops->finish();
dpm_suspend_noirq(PMSG_RESTORE); dpm_suspend_noirq(PMSG_RESTORE);
...@@ -578,7 +582,10 @@ int hibernate(void) ...@@ -578,7 +582,10 @@ int hibernate(void)
goto Thaw; goto Thaw;
error = hibernation_snapshot(hibernation_mode == HIBERNATION_PLATFORM); error = hibernation_snapshot(hibernation_mode == HIBERNATION_PLATFORM);
if (in_suspend && !error) { if (error)
goto Thaw;
if (in_suspend) {
unsigned int flags = 0; unsigned int flags = 0;
if (hibernation_mode == HIBERNATION_PLATFORM) if (hibernation_mode == HIBERNATION_PLATFORM)
...@@ -590,8 +597,8 @@ int hibernate(void) ...@@ -590,8 +597,8 @@ int hibernate(void)
power_down(); power_down();
} else { } else {
pr_debug("PM: Image restored successfully.\n"); pr_debug("PM: Image restored successfully.\n");
swsusp_free();
} }
Thaw: Thaw:
thaw_processes(); thaw_processes();
Finish: Finish:
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <linux/kobject.h> #include <linux/kobject.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/resume-trace.h> #include <linux/resume-trace.h>
#include <linux/workqueue.h>
#include "power.h" #include "power.h"
...@@ -217,8 +218,24 @@ static struct attribute_group attr_group = { ...@@ -217,8 +218,24 @@ static struct attribute_group attr_group = {
.attrs = g, .attrs = g,
}; };
#ifdef CONFIG_PM_RUNTIME
struct workqueue_struct *pm_wq;
static int __init pm_start_workqueue(void)
{
pm_wq = create_freezeable_workqueue("pm");
return pm_wq ? 0 : -ENOMEM;
}
#else
static inline int pm_start_workqueue(void) { return 0; }
#endif
static int __init pm_init(void) static int __init pm_init(void)
{ {
int error = pm_start_workqueue();
if (error)
return error;
power_kobj = kobject_create_and_add("power", NULL); power_kobj = kobject_create_and_add("power", NULL);
if (!power_kobj) if (!power_kobj)
return -ENOMEM; return -ENOMEM;
......
...@@ -74,7 +74,7 @@ extern asmlinkage int swsusp_arch_resume(void); ...@@ -74,7 +74,7 @@ extern asmlinkage int swsusp_arch_resume(void);
extern int create_basic_memory_bitmaps(void); extern int create_basic_memory_bitmaps(void);
extern void free_basic_memory_bitmaps(void); extern void free_basic_memory_bitmaps(void);
extern int swsusp_shrink_memory(void); extern int hibernate_preallocate_memory(void);
/** /**
* Auxiliary structure used for reading the snapshot image data and * Auxiliary structure used for reading the snapshot image data and
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment