From: Johannes Berg <johannes@sipsolutions.net>
To: linuxppc-dev@ozlabs.org
Subject: [PATCH 4/5] powermac: proper sleep management
Date: Mon, 19 Mar 2007 11:53:56 +0100 [thread overview]
Message-ID: <20070319105359.744830000@sipsolutions.net> (raw)
In-Reply-To: 20070319105352.771599000@sipsolutions.net
After having removed the power management ops from powermac completely, this
patch adds them back for PMU based machines, directly in the PMU driver.
This finally allows suspending via /sys/power/state on powerbooks.
The patch also replaces the PMU ioctl with a simple call to
pm_suspend(PM_SUSPEND_MEM) and puts the sleep-related PMU ioctls onto the
feature-removal schedule.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
Could use some testing on older powerbooks just to see if they get problems
with the slight reordering of the suspend/resume sequence. I doubt it though.
And before someone asks:
Yes, it is safe to remove the backlight ioctl restrictions
because the generic layer actually freezes processes before STR.
This updated version removes the sys_sync() call that can't be done with
processes frozen.
---
Documentation/feature-removal-schedule.txt | 10
drivers/macintosh/via-pmu.c | 307 +++++++++++------------------
2 files changed, 137 insertions(+), 180 deletions(-)
--- linux-2.6.orig/drivers/macintosh/via-pmu.c 2007-03-19 11:47:40.232413925 +0100
+++ linux-2.6/drivers/macintosh/via-pmu.c 2007-03-19 11:53:10.332413925 +0100
@@ -155,9 +155,6 @@ static int drop_interrupts;
#if defined(CONFIG_PM) && defined(CONFIG_PPC32)
static int option_lid_wakeup = 1;
#endif /* CONFIG_PM && CONFIG_PPC32 */
-#if (defined(CONFIG_PM)&&defined(CONFIG_PPC32))||defined(CONFIG_PMAC_BACKLIGHT_LEGACY)
-static int sleep_in_progress;
-#endif
static unsigned long async_req_locks;
static unsigned int pmu_irq_stats[11];
@@ -1991,132 +1988,6 @@ restore_via_state(void)
extern void pmu_backlight_set_sleep(int sleep);
-static int
-pmac_suspend_devices(void)
-{
- int ret;
-
- pm_prepare_console();
-
- /* Notify old-style device drivers */
- broadcast_sleep(PBOOK_SLEEP_REQUEST);
-
- /* Sync the disks. */
- /* XXX It would be nice to have some way to ensure that
- * nobody is dirtying any new buffers while we wait. That
- * could be achieved using the refrigerator for processes
- * that swsusp uses
- */
- sys_sync();
-
- broadcast_sleep(PBOOK_SLEEP_NOW);
-
- /* Send suspend call to devices, hold the device core's dpm_sem */
- ret = device_suspend(PMSG_SUSPEND);
- if (ret) {
- broadcast_wake();
- printk(KERN_ERR "Driver sleep failed\n");
- return -EBUSY;
- }
-
-#ifdef CONFIG_PMAC_BACKLIGHT
- /* Tell backlight code not to muck around with the chip anymore */
- pmu_backlight_set_sleep(1);
-#endif
-
- /* Call platform functions marked "on sleep" */
- pmac_pfunc_i2c_suspend();
- pmac_pfunc_base_suspend();
-
- /* Stop preemption */
- preempt_disable();
-
- /* Make sure the decrementer won't interrupt us */
- asm volatile("mtdec %0" : : "r" (0x7fffffff));
- /* Make sure any pending DEC interrupt occurring while we did
- * the above didn't re-enable the DEC */
- mb();
- asm volatile("mtdec %0" : : "r" (0x7fffffff));
-
- /* We can now disable MSR_EE. This code of course works properly only
- * on UP machines... For SMP, if we ever implement sleep, we'll have to
- * stop the "other" CPUs way before we do all that stuff.
- */
- local_irq_disable();
-
- /* Broadcast power down irq
- * This isn't that useful in most cases (only directly wired devices can
- * use this but still... This will take care of sysdev's as well, so
- * we exit from here with local irqs disabled and PIC off.
- */
- ret = device_power_down(PMSG_SUSPEND);
- if (ret) {
- wakeup_decrementer();
- local_irq_enable();
- preempt_enable();
- device_resume();
- broadcast_wake();
- printk(KERN_ERR "Driver powerdown failed\n");
- return -EBUSY;
- }
-
- /* Wait for completion of async requests */
- while (!batt_req.complete)
- pmu_poll();
-
- /* Giveup the lazy FPU & vec so we don't have to back them
- * up from the low level code
- */
- enable_kernel_fp();
-
-#ifdef CONFIG_ALTIVEC
- if (cpu_has_feature(CPU_FTR_ALTIVEC))
- enable_kernel_altivec();
-#endif /* CONFIG_ALTIVEC */
-
- return 0;
-}
-
-static int
-pmac_wakeup_devices(void)
-{
- mdelay(100);
-
-#ifdef CONFIG_PMAC_BACKLIGHT
- /* Tell backlight code it can use the chip again */
- pmu_backlight_set_sleep(0);
-#endif
-
- /* Power back up system devices (including the PIC) */
- device_power_up();
-
- /* Force a poll of ADB interrupts */
- adb_int_pending = 1;
- via_pmu_interrupt(0, NULL);
-
- /* Restart jiffies & scheduling */
- wakeup_decrementer();
-
- /* Re-enable local CPU interrupts */
- local_irq_enable();
- mdelay(10);
- preempt_enable();
-
- /* Call platform functions marked "on wake" */
- pmac_pfunc_base_resume();
- pmac_pfunc_i2c_resume();
-
- /* Resume devices */
- device_resume();
-
- /* Notify old style drivers */
- broadcast_wake();
-
- pm_restore_console();
-
- return 0;
-}
-
#define GRACKLE_PM (1<<7)
#define GRACKLE_DOZE (1<<5)
#define GRACKLE_NAP (1<<4)
@@ -2127,19 +1998,12 @@ static int powerbook_sleep_grackle(void)
unsigned long save_l2cr;
unsigned short pmcr1;
struct adb_request req;
- int ret;
struct pci_dev *grackle;
grackle = pci_find_slot(0, 0);
if (!grackle)
return -ENODEV;
- ret = pmac_suspend_devices();
- if (ret) {
- printk(KERN_ERR "Sleep rejected by devices\n");
- return ret;
- }
-
/* Turn off various things. Darwin does some retry tests here... */
pmu_request(&req, NULL, 2, PMU_POWER_CTRL0, PMU_POW0_OFF|PMU_POW0_HARD_DRIVE);
pmu_wait_complete(&req);
@@ -2200,8 +2064,6 @@ static int powerbook_sleep_grackle(void)
PMU_POW_ON|PMU_POW_BACKLIGHT|PMU_POW_CHARGER|PMU_POW_IRLED|PMU_POW_MEDIABAY);
pmu_wait_complete(&req);
- pmac_wakeup_devices();
-
return 0;
}
@@ -2211,7 +2073,6 @@ powerbook_sleep_Core99(void)
unsigned long save_l2cr;
unsigned long save_l3cr;
struct adb_request req;
- int ret;
if (pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,-1) < 0) {
printk(KERN_ERR "Sleep mode not supported on this machine\n");
@@ -2221,12 +2082,6 @@ powerbook_sleep_Core99(void)
if (num_online_cpus() > 1 || cpu_is_offline(0))
return -EAGAIN;
- ret = pmac_suspend_devices();
- if (ret) {
- printk(KERN_ERR "Sleep rejected by devices\n");
- return ret;
- }
-
/* Stop environment and ADB interrupts */
pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, 0);
pmu_wait_complete(&req);
@@ -2297,8 +2152,6 @@ powerbook_sleep_Core99(void)
/* Restore LPJ, cpufreq will adjust the cpu frequency */
loops_per_jiffy /= 2;
- pmac_wakeup_devices();
-
return 0;
}
@@ -2308,7 +2161,7 @@ powerbook_sleep_Core99(void)
static int
powerbook_sleep_3400(void)
{
- int ret, i, x;
+ int i, x;
unsigned int hid0;
unsigned long p;
struct adb_request sleep_req;
@@ -2326,13 +2179,6 @@ powerbook_sleep_3400(void)
/* Allocate room for PCI save */
pbook_alloc_pci_save();
- ret = pmac_suspend_devices();
- if (ret) {
- pbook_free_pci_save();
- printk(KERN_ERR "Sleep rejected by devices\n");
- return ret;
- }
-
/* Save the state of PCI config space for some slots */
pbook_pci_save();
@@ -2376,7 +2222,6 @@ powerbook_sleep_3400(void)
while (asleep)
mb();
- pmac_wakeup_devices();
pbook_free_pci_save();
iounmap(mem_ctrl);
@@ -2558,6 +2403,124 @@ pmu_release(struct inode *inode, struct
return 0;
}
+#if defined(CONFIG_PM) && defined(CONFIG_PPC32)
+static int powerbook_prepare_sleep(suspend_state_t state)
+{
+ /* Notify old-style device drivers */
+ broadcast_sleep(PBOOK_SLEEP_REQUEST);
+ broadcast_sleep(PBOOK_SLEEP_NOW);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+ /* Tell backlight code not to muck around with the chip anymore */
+ pmu_backlight_set_sleep(1);
+#endif
+
+ /* Call platform functions marked "on sleep" */
+ pmac_pfunc_i2c_suspend();
+ pmac_pfunc_base_suspend();
+
+ preempt_disable();
+
+ return 0;
+}
+
+static int powerbook_sleep(suspend_state_t state)
+{
+ int error = 0;
+
+ asm volatile("mtdec %0" : : "r" (0x7fffffff));
+ /* Make sure any pending DEC interrupt occurring while we did
+ * the above didn't re-enable the DEC */
+ mb();
+ asm volatile("mtdec %0" : : "r" (0x7fffffff));
+
+ /* Wait for completion of async requests */
+ while (!batt_req.complete)
+ pmu_poll();
+
+ /* Giveup the lazy FPU & vec so we don't have to back them
+ * up from the low level code
+ */
+ enable_kernel_fp();
+
+#ifdef CONFIG_ALTIVEC
+ if (cpu_has_feature(CPU_FTR_ALTIVEC))
+ enable_kernel_altivec();
+#endif /* CONFIG_ALTIVEC */
+
+ switch (pmu_kind) {
+ case PMU_OHARE_BASED:
+ error = powerbook_sleep_3400();
+ break;
+ case PMU_HEATHROW_BASED:
+ case PMU_PADDINGTON_BASED:
+ error = powerbook_sleep_grackle();
+ break;
+ case PMU_KEYLARGO_BASED:
+ error = powerbook_sleep_Core99();
+ break;
+ default:
+ return -ENOSYS;
+ }
+
+ if (error)
+ return error;
+
+ mdelay(100);
+
+ /* Force a poll of ADB interrupts */
+ adb_int_pending = 1;
+ via_pmu_interrupt(0, NULL);
+
+ /* Restart jiffies & scheduling */
+ wakeup_decrementer();
+
+ return 0;
+}
+
+static int powerbook_finish_sleep(suspend_state_t state)
+{
+#ifdef CONFIG_PMAC_BACKLIGHT
+ /* Tell backlight code it can use the chip again */
+ pmu_backlight_set_sleep(0);
+#endif
+
+ preempt_enable();
+
+ /* Call platform functions marked "on wake" */
+ pmac_pfunc_base_resume();
+ pmac_pfunc_i2c_resume();
+
+ /* Notify old style drivers */
+ broadcast_wake();
+
+ return 0;
+}
+
+static int pmu_sleep_valid(suspend_state_t state)
+{
+ return state == PM_SUSPEND_MEM
+ && (pmac_call_feature(PMAC_FTR_SLEEP_STATE, NULL, 0, -1) >= 0);
+}
+
+static struct pm_ops pmu_pm_ops = {
+ .pm_disk_mode = PM_DISK_PLATFORM,
+ .prepare = powerbook_prepare_sleep,
+ .finish = powerbook_finish_sleep,
+ .enter = powerbook_sleep,
+ .valid = pmu_sleep_valid,
+};
+
+static int register_pmu_pm_ops(void)
+{
+ pm_set_ops(&pmu_pm_ops);
+
+ return 0;
+}
+
+device_initcall(register_pmu_pm_ops);
+#endif
+
static int
pmu_ioctl(struct inode * inode, struct file *filp,
u_int cmd, u_long arg)
@@ -2567,29 +2530,19 @@ pmu_ioctl(struct inode * inode, struct f
switch (cmd) {
#if defined(CONFIG_PM) && defined(CONFIG_PPC32)
+ /* just provided for compatibility */
case PMU_IOC_SLEEP:
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
- if (sleep_in_progress)
- return -EBUSY;
- sleep_in_progress = 1;
- switch (pmu_kind) {
- case PMU_OHARE_BASED:
- error = powerbook_sleep_3400();
- break;
- case PMU_HEATHROW_BASED:
- case PMU_PADDINGTON_BASED:
- error = powerbook_sleep_grackle();
- break;
- case PMU_KEYLARGO_BASED:
- error = powerbook_sleep_Core99();
- break;
- default:
- error = -ENOSYS;
- }
- sleep_in_progress = 0;
+ printk(KERN_INFO "via-pmu: the PMU_IOC_SLEEP ioctl is deprecated.\n");
+ printk(KERN_INFO "via-pmu: use \"echo mem > /sys/power/state\" instead!\n");
+ printk(KERN_INFO "via-pmu: this ioctl will be removed soon.\n");
+ error = pm_suspend(PM_SUSPEND_MEM);
break;
case PMU_IOC_CAN_SLEEP:
+ printk(KERN_INFO "via-pmu: the PMU_IOC_CAN_SLEEP ioctl is deprecated.\n");
+ printk(KERN_INFO "via-pmu: use \"grep mem /sys/power/state\" instead!\n");
+ printk(KERN_INFO "via-pmu: this ioctl will be removed soon.\n");
if (pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,-1) < 0)
return put_user(0, argp);
else
@@ -2602,9 +2555,6 @@ pmu_ioctl(struct inode * inode, struct f
{
int brightness;
- if (sleep_in_progress)
- return -EBUSY;
-
brightness = pmac_backlight_get_legacy_brightness();
if (brightness < 0)
return brightness;
@@ -2616,9 +2566,6 @@ pmu_ioctl(struct inode * inode, struct f
{
int brightness;
- if (sleep_in_progress)
- return -EBUSY;
-
error = get_user(brightness, argp);
if (error)
return error;
--- linux-2.6.orig/Documentation/feature-removal-schedule.txt 2007-03-19 11:47:24.672413925 +0100
+++ linux-2.6/Documentation/feature-removal-schedule.txt 2007-03-19 11:47:41.162413925 +0100
@@ -324,3 +324,13 @@ Why: the i8xx_tco watchdog driver has be
Who: Wim Van Sebroeck <wim@iguana.be>
---------------------------
+
+What: /dev/pmu suspend/can-suspend ioctls
+When: 2.6.24
+Files: drivers/macintosh/via-pmu.c
+Why: powermac supports proper generic pm_ops now and can suspend with
+ "echo mem > /sys/power/state" instead of the ioctl, checking if
+ it can suspend can be done by reading /sys/power/state.
+Who: Johannes Berg <johannes@sipsolutions.net>
+
+---------------------------
--
next prev parent reply other threads:[~2007-03-19 10:59 UTC|newest]
Thread overview: 32+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-03-19 10:53 [PATCH 0/5] powermac suspend fixes Johannes Berg
2007-03-19 10:53 ` [PATCH 1/5] powerpc: generic time suspend/resume code Johannes Berg
2007-03-19 14:47 ` Benjamin Herrenschmidt
2007-03-19 21:51 ` Guennadi Liakhovetski
2007-03-19 22:11 ` Johannes Berg
2007-03-19 23:21 ` Guennadi Liakhovetski
2007-03-21 20:47 ` David Brownell
2007-03-21 22:48 ` Guennadi Liakhovetski
2007-05-02 5:02 ` Michael Ellerman
2007-05-02 8:25 ` Johannes Berg
2007-05-02 11:06 ` Michael Ellerman
2007-05-02 14:04 ` Johannes Berg
2007-03-19 10:53 ` [PATCH 2/5] powerpc: fix suspend states again Johannes Berg
2007-03-19 14:48 ` Benjamin Herrenschmidt
2007-03-19 15:22 ` Johannes Berg
2007-03-19 15:32 ` Benjamin Herrenschmidt
2007-03-19 15:45 ` Johannes Berg
2007-03-19 15:54 ` Johannes Berg
2007-03-19 16:22 ` Johannes Berg
2007-03-19 16:39 ` Benjamin Herrenschmidt
2007-03-19 16:06 ` Benjamin Herrenschmidt
2007-03-19 10:53 ` [PATCH 3/5] powermac: disallow pmu sleep notifiers from aborting sleep Johannes Berg
2007-03-19 14:49 ` Benjamin Herrenschmidt
2007-03-19 10:53 ` Johannes Berg [this message]
2007-03-19 14:50 ` [PATCH 4/5] powermac: proper sleep management Benjamin Herrenschmidt
2007-03-19 15:16 ` Johannes Berg
2007-03-19 23:44 ` Johannes Berg
2007-03-20 0:11 ` [PATCH 4/5 v2] " Johannes Berg
2007-03-20 0:48 ` Johannes Berg
2007-03-20 2:19 ` Johannes Berg
2007-03-19 10:53 ` [PATCH 5/5] remove dead code in via-pmu68k Johannes Berg
2007-03-19 19:17 ` Brad Boyer
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20070319105359.744830000@sipsolutions.net \
--to=johannes@sipsolutions.net \
--cc=linuxppc-dev@ozlabs.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).