[PATCH] ppc32: PowerMac PM rework

Benjamin Herrenschmidt benh at kernel.crashing.org
Sat May 28 12:15:19 EST 2005


Hi !

This new version of my PM rework fixes bits & pieces, most
significantly, improves suspend to disk by properly saving/restoring
MacIO ASIC state, and fixes issues with suspend to disk vs. AGP/DRI.

Also, the previous patch had the backward compatible ioctl backward, it
would suspend to disk instead of to RAM :)

Applies on top of current git plus:

http://gate.crashing.org/~benh/ppc32-pmac-cpufreq-upd.diff
http://gate.crashing.org/~benh/ppc32-pmac-pmu-irq-pri.diff
http://gate.crashing.org/~benh/ppc32-pmu-wakeup.diff

Please test and report any issue.

Index: linux-work/arch/ppc/platforms/Makefile
===================================================================
--- linux-work.orig/arch/ppc/platforms/Makefile	2005-05-02 10:48:08.000000000 +1000
+++ linux-work/arch/ppc/platforms/Makefile	2005-05-28 10:30:21.000000000 +1000
@@ -10,8 +10,9 @@
 obj-$(CONFIG_PCI)		+= apus_pci.o
 endif
 obj-$(CONFIG_PPC_PMAC)		+= pmac_pic.o pmac_setup.o pmac_time.o \
-					pmac_feature.o pmac_pci.o pmac_sleep.o \
-					pmac_low_i2c.o pmac_cache.o
+				   pmac_feature.o pmac_pci.o pmac_sleep.o \
+				   pmac_low_i2c.o pmac_cache.o pmac_pm.o
+
 obj-$(CONFIG_PPC_CHRP)		+= chrp_setup.o chrp_time.o chrp_pci.o \
 					chrp_pegasos_eth.o
 obj-$(CONFIG_PPC_PREP)		+= prep_pci.o prep_setup.o
Index: linux-work/arch/ppc/platforms/pmac_pm.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-work/arch/ppc/platforms/pmac_pm.c	2005-05-28 11:58:16.000000000 +1000
@@ -0,0 +1,802 @@
+/*
+ * PowerMac Power Management core
+ *
+ * Copyright (C) 2005 Benjamin Herrenschmidt, IBM Corp.
+ *
+ * Bits from drivers/macintosh/via-pmu.c
+ *
+ * Copyright (C) 1998 Paul Mackerras and Fabio Riccardi.
+ * Copyright (C) 2001-2002 Benjamin Herrenschmidt
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/pm.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/sysdev.h>
+#include <linux/suspend.h>
+#include <linux/adb.h>
+#include <linux/pmu.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/cpu.h>
+#include <linux/syscalls.h>
+#include <linux/reboot.h>
+#include <linux/timer.h>
+
+#include <asm/prom.h>
+#include <asm/machdep.h>
+#include <asm/irq.h>
+#include <asm/pmac_feature.h>
+#include <asm/mmu_context.h>
+#include <asm/cputable.h>
+#include <asm/time.h>
+#include <asm/sections.h>
+#include <asm/system.h>
+#include <asm/open_pic.h>
+
+#ifdef CONFIG_PM_DEBUG
+#define DBG(fmt...) printk(fmt)
+#else
+#define DBG(fmt...)
+#endif
+
+/* debugging */
+int __fake_sleep;
+
+/* lid wakeup control (fixme) */
+int pmac_option_lid_wakeup __pmacdata;
+EXPORT_SYMBOL_GPL(pmac_option_lid_wakeup);
+
+/* main callback for suspend to RAM */
+static int (*pmac_pm_low_suspend)(void) __pmacdata;
+
+/* assembly stuff */
+extern void low_sleep_handler(void);
+/* pmac_pic stuff */
+extern void pmacpic_suspend(void);
+extern void pmacpic_resume(void);
+
+
+/*************************************************************************
+ *
+ * Here is the "old style" PowerMac PM notifiers. They are still used by a
+ * couple of drivers that haven't yet been fitted in the device model.
+ * They will ultimately be deprecated.
+ *
+ *************************************************************************/
+
+static LIST_HEAD(sleep_notifiers);
+
+int __pmac pmu_register_sleep_notifier(struct pmu_sleep_notifier *n)
+{
+	struct list_head *list;
+	struct pmu_sleep_notifier *notifier;
+
+	for (list = sleep_notifiers.next; list != &sleep_notifiers;
+	     list = list->next) {
+		notifier = list_entry(list, struct pmu_sleep_notifier, list);
+		if (n->priority > notifier->priority)
+			break;
+	}
+	__list_add(&n->list, list->prev, list);
+	return 0;
+}
+EXPORT_SYMBOL(pmu_register_sleep_notifier);
+
+int __pmac pmu_unregister_sleep_notifier(struct pmu_sleep_notifier* n)
+{
+	if (n->list.next == 0)
+		return -ENOENT;
+	list_del(&n->list);
+	n->list.next = NULL;
+	return 0;
+}
+EXPORT_SYMBOL(pmu_unregister_sleep_notifier);
+
+/* Sleep is broadcast last-to-first */
+static int __pmac broadcast_sleep(int when, int fallback)
+{
+	int ret = PBOOK_SLEEP_OK;
+	struct list_head *list;
+	struct pmu_sleep_notifier *notifier;
+
+	for (list = sleep_notifiers.prev; list != &sleep_notifiers;
+	     list = list->prev) {
+		notifier = list_entry(list, struct pmu_sleep_notifier, list);
+		ret = notifier->notifier_call(notifier, when);
+		if (ret != PBOOK_SLEEP_OK) {
+			DBG("sleep %d rejected by %p (%p)\n",
+			    when, notifier, notifier->notifier_call);
+			for (; list != &sleep_notifiers; list = list->next) {
+				notifier = list_entry(list,
+					      struct pmu_sleep_notifier, list);
+				notifier->notifier_call(notifier, fallback);
+			}
+			return ret;
+		}
+	}
+	return ret;
+}
+
+/* Wake is broadcast first-to-last */
+static int __pmac broadcast_wake(void)
+{
+	int ret = PBOOK_SLEEP_OK;
+	struct list_head *list;
+	struct pmu_sleep_notifier *notifier;
+
+	for (list = sleep_notifiers.next; list != &sleep_notifiers;
+	     list = list->next) {
+		notifier = list_entry(list, struct pmu_sleep_notifier, list);
+		notifier->notifier_call(notifier, PBOOK_WAKE);
+	}
+	return ret;
+}
+
+/**************************************************************************
+ *
+ * Here, we have code to save/restore PCI config space. Most of that code
+ * should be removed once we are confident with the generic code, including
+ * with P2P bridges
+ *
+ **************************************************************************/
+
+static struct pci_save {
+	u16	command;
+	u16	cache_lat;
+	u16	intr;
+	u32	bars[6];
+	u32	rom_address;
+} *pbook_pci_saves __pmacdata;
+static int pbook_npci_saves __pmacdata;
+
+static void __pmac pbook_alloc_pci_save(void)
+{
+	int npci;
+	struct pci_dev *pd = NULL;
+
+	npci = 0;
+	while ((pd = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pd)) != NULL) {
+		++npci;
+	}
+	if (npci == 0)
+		return;
+	pbook_pci_saves = (struct pci_save *)
+		kmalloc(npci * sizeof(struct pci_save), GFP_KERNEL);
+	pbook_npci_saves = npci;
+}
+
+static void __pmac pbook_free_pci_save(void)
+{
+	if (pbook_pci_saves == NULL)
+		return;
+	kfree(pbook_pci_saves);
+	pbook_pci_saves = NULL;
+	pbook_npci_saves = 0;
+}
+
+static void __pmac pbook_pci_save(void)
+{
+	struct pci_save *ps = pbook_pci_saves;
+	struct pci_dev *pd = NULL;
+	int npci = pbook_npci_saves;
+	int i;
+
+	if (ps == NULL)
+		return;
+
+	while ((pd = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pd)) != NULL) {
+		if (npci-- == 0)
+			return;
+		switch (pd->hdr_type) {
+		case PCI_HEADER_TYPE_NORMAL:
+			pci_read_config_word(pd, PCI_COMMAND, &ps->command);
+			pci_read_config_word(pd, PCI_CACHE_LINE_SIZE,
+					     &ps->cache_lat);
+			pci_read_config_word(pd, PCI_INTERRUPT_LINE,
+					     &ps->intr);
+			pci_read_config_dword(pd, PCI_ROM_ADDRESS,
+					      &ps->rom_address);
+			for (i=0; i<6; i++)
+				pci_read_config_dword(pd,
+						      PCI_BASE_ADDRESS_0+i*4,
+						      &ps->bars[i]);
+			break;
+		case PCI_HEADER_TYPE_BRIDGE:
+			pci_read_config_word(pd, PCI_COMMAND, &ps->command);
+			pci_read_config_word(pd, PCI_CACHE_LINE_SIZE,
+					     &ps->cache_lat);
+			pci_read_config_dword(pd, PCI_ROM_ADDRESS1,
+					      &ps->rom_address);
+			pci_read_config_dword(pd, PCI_BASE_ADDRESS_0,
+					      &ps->bars[0]);
+			pci_read_config_dword(pd, PCI_BASE_ADDRESS_1,
+					      &ps->bars[1]);
+			break;
+		case PCI_HEADER_TYPE_CARDBUS:
+			pci_read_config_word(pd, PCI_COMMAND, &ps->command);
+			pci_read_config_word(pd, PCI_CACHE_LINE_SIZE,
+					     &ps->cache_lat);
+			pci_read_config_word(pd, PCI_INTERRUPT_LINE,
+					     &ps->intr);
+			pci_read_config_dword(pd, PCI_BASE_ADDRESS_0,
+					      &ps->bars[0]);
+			break;
+		}			
+		++ps;
+	}
+}
+
+/* For this to work, we must take care of a few things: If gmac was enabled
+ * during boot, it will be in the pci dev list. If it's disabled at this point
+ * (and it will probably be), then you can't access it's config space.
+ */
+static void __pmac pbook_pci_restore(void)
+{
+	u16 cmd;
+	struct pci_save *ps = pbook_pci_saves - 1;
+	struct pci_dev *pd = NULL;
+	int npci = pbook_npci_saves;
+	int i;
+
+	while ((pd = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pd)) != NULL) {
+		if (npci-- == 0)
+			return;
+		ps++;
+		if (ps->command == 0)
+			continue;
+		pci_read_config_word(pd, PCI_COMMAND, &cmd);
+		if ((ps->command & ~cmd) == 0)
+			continue;
+		switch (pd->hdr_type) {
+		case PCI_HEADER_TYPE_NORMAL:
+			for (i = 0; i < 6; ++i)
+				pci_write_config_dword(pd,
+						       PCI_BASE_ADDRESS_0+i*4,
+						       ps->bars[i]);
+			pci_write_config_dword(pd, PCI_ROM_ADDRESS,
+					       ps->rom_address);
+			pci_write_config_word(pd, PCI_CACHE_LINE_SIZE,
+					      ps->cache_lat);
+			pci_write_config_word(pd, PCI_INTERRUPT_LINE,
+					      ps->intr);
+			pci_write_config_word(pd, PCI_COMMAND, ps->command);
+			break;
+		case PCI_HEADER_TYPE_BRIDGE:
+			pci_write_config_dword(pd, PCI_BASE_ADDRESS_0,
+					       ps->bars[0]);
+			pci_write_config_dword(pd, PCI_BASE_ADDRESS_1,
+					       ps->bars[1]);
+			pci_write_config_dword(pd, PCI_ROM_ADDRESS,
+					       ps->rom_address);
+			pci_write_config_word(pd, PCI_CACHE_LINE_SIZE,
+					      ps->cache_lat);
+			pci_write_config_word(pd, PCI_COMMAND, ps->command);
+			break;
+		case PCI_HEADER_TYPE_CARDBUS:
+			pci_write_config_dword(pd, PCI_BASE_ADDRESS_0, 
+					       ps->bars[0]);
+			pci_write_config_word(pd, PCI_CACHE_LINE_SIZE,
+					      ps->cache_lat);
+			pci_write_config_word(pd, PCI_INTERRUPT_LINE,
+					      ps->intr);
+			pci_write_config_word(pd, PCI_COMMAND, ps->command);
+			break;
+		}
+	}
+}
+
+/*************************************************************************
+ *
+ * Here are the per-machine family low level sleep routines and the
+ * par-machine family initialization routines.
+ *
+ *************************************************************************/
+
+
+#define PB3400_MEM_CTRL		0xf8000000
+#define PB3400_MEM_CTRL_SLEEP	0x70
+
+static void __iomem *mem_ctrl_3400 __pmacdata;
+
+static int __pmac pmac_pm_sleep_3400(void)
+{
+	int i, x;
+	unsigned int hid0;
+	unsigned long p;
+	struct adb_request sleep_req;
+	unsigned int __iomem *mem_ctrl_sleep;
+
+	mem_ctrl_sleep = mem_ctrl_3400 + PB3400_MEM_CTRL_SLEEP;
+
+	/* Set the memory controller to keep the memory refreshed
+	   while we're asleep */
+	for (i = 0x403f; i >= 0x4000; --i) {
+		out_be32(mem_ctrl_sleep, i);
+		do {
+			x = (in_be32(mem_ctrl_sleep) >> 16) & 0x3ff;
+		} while (x == 0);
+		if (x >= 0x100)
+			break;
+	}
+
+	/* Ask the PMU to put us to sleep */
+	pmu_request(&sleep_req, NULL, 5, PMU_SLEEP, 'M', 'A', 'T', 'T');
+	while (!sleep_req.complete)
+		mb();
+
+	pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,1);
+
+	/* displacement-flush the L2 cache - necessary? */
+	for (p = KERNELBASE; p < KERNELBASE + 0x100000; p += 0x1000)
+		i = *(volatile int *)p;
+
+	/* Put the CPU into sleep mode */
+	asm volatile("mfspr %0,1008" : "=r" (hid0) :);
+	hid0 = (hid0 & ~(HID0_NAP | HID0_DOZE)) | HID0_SLEEP;
+	asm volatile("mtspr 1008,%0" : : "r" (hid0));
+	_nmask_and_or_msr(0, MSR_POW | MSR_EE);
+	udelay(10);
+
+	/* OK, we're awake again, start restoring things */
+	out_be32(mem_ctrl_sleep, 0x3f);
+	pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,0);
+	pbook_pci_restore();
+	pmu_unlock();
+
+	mdelay(10);
+
+	return 0;
+}
+
+static void __pmac pmac_pm_init_3400(void)
+{
+	/* first map in the memory controller registers */
+	mem_ctrl_3400 = ioremap(PB3400_MEM_CTRL, 0x100);
+	if (mem_ctrl_3400 == NULL) {
+		printk(KERN_ERR "pmac_pm_init_3400: ioremap failed\n");
+		return;
+	}
+
+	pmac_pm_low_suspend = pmac_pm_sleep_3400;
+}
+
+#define	GRACKLE_PM	(1<<7)
+#define GRACKLE_DOZE	(1<<5)
+#define	GRACKLE_NAP	(1<<4)
+#define	GRACKLE_SLEEP	(1<<3)
+
+static struct pci_dev *grackle __pmacdata;
+
+static int __pmac pmac_pm_sleep_grackle(void)
+{
+	unsigned long save_l2cr;
+	unsigned short pmcr1;
+	struct adb_request req;
+
+	/* 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);
+	pmu_request(&req, NULL, 2, PMU_POWER_CTRL,
+		    PMU_POW_OFF | PMU_POW_BACKLIGHT |
+		    PMU_POW_IRLED | PMU_POW_MEDIABAY);
+	pmu_wait_complete(&req);
+
+	/* For 750, save backside cache setting and disable it */
+	save_l2cr = _get_L2CR();	/* (returns -1 if not available) */
+
+	if (!__fake_sleep) {
+		/* Ask the PMU to put us to sleep */
+		pmu_request(&req, NULL, 5, PMU_SLEEP, 'M', 'A', 'T', 'T');
+		pmu_wait_complete(&req);
+	}
+
+	/* The VIA is supposed not to be restored correctly*/
+	pmu_save_via_state();
+
+	/* We shut down some HW */
+	pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,1);
+
+	pci_read_config_word(grackle, 0x70, &pmcr1);
+	/* Apparently, MacOS uses NAP mode for Grackle ??? */
+	pmcr1 &= ~(GRACKLE_DOZE|GRACKLE_SLEEP); 
+	pmcr1 |= GRACKLE_PM|GRACKLE_NAP;
+	pci_write_config_word(grackle, 0x70, pmcr1);
+
+	/* Call low-level ASM sleep handler */
+	if (__fake_sleep)
+		mdelay(5000);
+	else
+		low_sleep_handler();
+
+	/* We're awake again, stop grackle PM */
+	pci_read_config_word(grackle, 0x70, &pmcr1);
+	pmcr1 &= ~(GRACKLE_PM|GRACKLE_DOZE|GRACKLE_SLEEP|GRACKLE_NAP); 
+	pci_write_config_word(grackle, 0x70, pmcr1);
+
+	/* Make sure the PMU is idle */
+	pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,0);
+	pmu_restore_via_state();
+	
+	/* Restore L2 cache */
+	if (save_l2cr != 0xffffffff && (save_l2cr & L2CR_L2E) != 0)
+ 		_set_L2CR(save_l2cr);
+	
+	/* Power things up */
+	pmu_unlock();
+	pmu_request(&req, NULL, 2, PMU_POWER_CTRL0,
+			PMU_POW0_ON | PMU_POW0_HARD_DRIVE);
+	pmu_wait_complete(&req);
+	pmu_request(&req, NULL, 2, PMU_POWER_CTRL,
+		    PMU_POW_ON | PMU_POW_BACKLIGHT | PMU_POW_CHARGER |
+		    PMU_POW_IRLED | PMU_POW_MEDIABAY);
+	pmu_wait_complete(&req);
+
+	return 0;
+}
+
+static void __pmac pmac_pm_init_grackle(void)
+{
+	grackle = pci_find_slot(0, 0);
+	if (!grackle)
+		return;
+
+	pmac_pm_low_suspend = pmac_pm_sleep_grackle;
+}
+
+
+static int __pmac pmac_pm_sleep_core99(void)
+{
+	unsigned long save_l2cr;
+	unsigned long save_l3cr;
+	struct adb_request req;
+	
+	/* Tell PMU what events will wake us up */
+	pmu_request(&req, NULL, 4, PMU_POWER_EVENTS, PMU_PWR_CLR_WAKEUP_EVENTS,
+		0xff, 0xff);
+	pmu_wait_complete(&req);
+	pmu_request(&req, NULL, 4, PMU_POWER_EVENTS, PMU_PWR_SET_WAKEUP_EVENTS,
+		0, PMU_PWR_WAKEUP_KEY |
+		(pmac_option_lid_wakeup ? PMU_PWR_WAKEUP_LID_OPEN : 0));
+	pmu_wait_complete(&req);
+
+	/* Save the state of the L2 and L3 caches */
+	save_l3cr = _get_L3CR();	/* (returns -1 if not available) */
+	save_l2cr = _get_L2CR();	/* (returns -1 if not available) */
+
+	if (!__fake_sleep) {
+		/* Ask the PMU to put us to sleep */
+		pmu_request(&req, NULL, 5, PMU_SLEEP, 'M', 'A', 'T', 'T');
+		pmu_wait_complete(&req);
+	}
+
+	/* The VIA is supposed not to be restored correctly*/
+	pmu_save_via_state();
+
+	/* Shut down various ASICs. There's a chance that we can no longer
+	 * talk to the PMU after this, so I moved it to _after_ sending the
+	 * sleep command to it. Still need to be checked.
+	 */
+	pmac_call_feature(PMAC_FTR_SLEEP_STATE, NULL, 0, 1);
+
+	/* Call low-level ASM sleep handler */
+	if (__fake_sleep)
+		mdelay(5000);
+	else
+		low_sleep_handler();
+
+	/* Restore Apple core ASICs state */
+	pmac_call_feature(PMAC_FTR_SLEEP_STATE, NULL, 0, 0);
+
+	/* Restore VIA */
+	pmu_restore_via_state();
+
+	/* Restore video */
+	pmac_call_early_video_resume();
+
+	/* Restore L2 cache */
+	if (save_l2cr != 0xffffffff && (save_l2cr & L2CR_L2E) != 0)
+ 		_set_L2CR(save_l2cr);
+	/* Restore L3 cache */
+	if (save_l3cr != 0xffffffff && (save_l3cr & L3CR_L3E) != 0)
+ 		_set_L3CR(save_l3cr);
+	
+	/* Tell PMU we are ready */
+	pmu_unlock();
+	pmu_request(&req, NULL, 2, PMU_SYSTEM_READY, 2);
+	pmu_wait_complete(&req);
+
+	return 0;
+}
+
+static void __pmac pmac_pm_init_core99(void)
+{
+	pmac_pm_low_suspend = pmac_pm_sleep_core99;
+}
+
+
+/*************************************************************************
+ *
+ * Here are the callbacks interfacing with the common code.
+ *
+ *************************************************************************/
+
+static inline void wakeup_decrementer(void)
+{
+	/* No currently-supported powerbook has a 601,
+	 * so use get_tbl, not native
+	 */
+	last_jiffy_stamp(0) = tb_last_stamp = get_native_tbl();
+	set_dec(1);
+}
+
+static int __pmac pmac_pm_pre_freeze(suspend_state_t state)
+{
+	int ret;
+
+	DBG("%s(%d)\n", __FUNCTION__, state);
+
+	/* Check if suspend to RAM is possible */
+	if (state == PM_SUSPEND_MEM) {
+		if (pmac_pm_low_suspend == NULL)
+			return -EINVAL;
+		if (pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,-1) < 0)
+			return -EINVAL;
+		if (num_online_cpus() > 1 || cpu_is_offline(0))
+			return -EAGAIN;
+	}
+
+	DBG("Notify (1) old style drivers...\n");
+
+	/* Notify old-style device drivers & userland */
+	ret = broadcast_sleep(PBOOK_SLEEP_REQUEST, PBOOK_SLEEP_REJECT);
+	if (ret != PBOOK_SLEEP_OK) {
+		printk(KERN_ERR "Sleep rejected by drivers\n");
+		return -EBUSY;
+	}
+
+	/* 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
+	 */
+	DBG("Sync disks...\n");
+	sys_sync();
+
+	//	return (state == PM_SUSPEND_DISK);
+	return 1;
+}
+
+static int __pmac pmac_pm_prepare(suspend_state_t state)
+{
+	int ret;
+
+	DBG("%s(%d)\n", __FUNCTION__, state);
+
+	/* Sleep can fail now. May not be very robust but useful for
+	 * debugging
+	 */
+	DBG("Notify (2) old style drivers...\n");
+	ret = broadcast_sleep(PBOOK_SLEEP_NOW, PBOOK_WAKE);
+	if (ret != PBOOK_SLEEP_OK) {
+		printk(KERN_ERR "Driver sleep failed\n");
+		return -EBUSY;
+	}
+
+	/* Allocate room for PCI save */
+	DBG("Alloc PCI stuffs...\n");
+	pbook_alloc_pci_save();
+
+	return 0;
+}
+
+static int __pmac pmac_pm_prepare_irqs(suspend_state_t state)
+{
+	DBG("%s(%d)\n", __FUNCTION__, state);
+
+	/* That state only applies to suspend to RAM */
+	if (state != PM_SUSPEND_MEM)
+		return 0;
+
+	/* Stop interrupts on openpic */
+	if (pmu_get_model() == PMU_KEYLARGO_BASED)
+		openpic_set_priority(0xf);
+
+	/* Stop preemption */
+	preempt_disable();
+
+	/* Disable clock spreading on some machines */
+	pmac_tweak_clock_spreading(0);
+
+	/* 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 disable interrupts now and not in the generic code so
+	 * that we entre pmac_pm_finish_irqs() with interrupts still
+	 * off and can properly wakeup decrementer before enabling them.
+	 */
+	local_irq_disable();
+
+	return 0;
+}
+
+static void __pmac pmac_pm_pre_suspend(suspend_state_t state)
+{
+	DBG("%s\n", __FUNCTION__);
+
+	/* Save the state of PCI config space for some slots */
+	pbook_pci_save();
+
+	/* Suspend openpic */
+	if (pmu_get_model() == PMU_KEYLARGO_BASED)
+		openpic_suspend();
+	else
+		pmacpic_suspend();
+
+	/* 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 (cur_cpu_spec[0]->cpu_features & CPU_FTR_ALTIVEC)
+		enable_kernel_altivec();
+#endif /* CONFIG_ALTIVEC */
+
+	/* save ASIC state on suspend to disk */
+	if (state == PM_SUSPEND_DISK)
+		pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,2);
+}
+
+static void __pmac pmac_pmdisk_save_state(void)
+{
+	pmac_pm_pre_suspend(PM_SUSPEND_DISK);
+}
+
+static void __pmac pmac_pm_post_suspend(suspend_state_t state)
+{
+	DBG("%s\n", __FUNCTION__);
+
+	/* Restore ASIC state on suspend to disk */
+	if (state == PM_SUSPEND_DISK)
+		pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,0);
+
+	/* Restore the state of PCI config space for some slots */
+	pbook_pci_restore();
+
+	/* Resume openpic */
+	if (pmu_get_model() == PMU_KEYLARGO_BASED)
+		openpic_resume();
+	else
+		pmacpic_resume();
+
+	/* Restore userland MMU context */
+	set_context(current->active_mm->context, current->active_mm->pgd);
+}
+
+static void __pmac pmac_pmdisk_restore_state(void)
+{
+	pmac_pm_post_suspend(PM_SUSPEND_DISK);
+}
+
+static int __pmac pmac_pm_enter(suspend_state_t state)
+{
+	int rc = 0;
+
+	DBG("%s(%d)\n", __FUNCTION__, state);
+
+	if (state == PM_SUSPEND_MEM) {
+		pmac_pm_pre_suspend(state);
+		rc = pmac_pm_low_suspend();
+		pmac_pm_post_suspend(state);
+		
+	} else if (state == PM_SUSPEND_DISK) {
+		device_shutdown();
+		machine_restart(NULL);
+	} else
+		rc = -EINVAL;
+	return rc;
+}
+
+static void __pmac pmac_pm_finish_irqs(suspend_state_t state)
+{
+	DBG("%s(%d)\n", __FUNCTION__, state);
+
+	/* That state only applies to suspend to RAM */
+	if (state != PM_SUSPEND_MEM)
+		return;
+
+	/* Force a fetch from the PIC on the first DEC interrupt. */
+	ppc_force_interrupt = 1;
+
+	/* Restart jiffies & scheduling */
+	wakeup_decrementer();
+
+	/* Start interrupts on openpic */
+	if (pmu_get_model() == PMU_KEYLARGO_BASED)
+		openpic_set_priority(0);
+
+	/* Re-enable local CPU interrupts */
+	local_irq_enable();
+	mdelay(10);
+	preempt_enable();
+
+	/* Re-enable clock spreading on some machines */
+	pmac_tweak_clock_spreading(1);
+}
+
+static void __pmac pmac_pm_finish(suspend_state_t state)
+{
+	DBG("%s(%d)\n", __FUNCTION__, state);
+
+	/* Free PCI save block */
+	pbook_free_pci_save();
+
+}
+
+static void __pmac pmac_pm_post_freeze(suspend_state_t state)
+{
+	DBG("%s(%d)\n", __FUNCTION__, state);
+
+	/* Broadcase old style wakeup */
+	broadcast_wake();
+}
+
+static struct pm_ops pmac_pm_ops  __pmacdata = {
+	.pm_disk_mode	= PM_DISK_PLATFORM,
+	.pre_freeze	= pmac_pm_pre_freeze,
+	.prepare	= pmac_pm_prepare,
+	.prepare_irqs	= pmac_pm_prepare_irqs,
+	.enter		= pmac_pm_enter,
+	.finish_irqs	= pmac_pm_finish_irqs,
+	.finish		= pmac_pm_finish,
+	.post_freeze	= pmac_pm_post_freeze,
+};
+
+static int pmac_pm_init(void)
+{
+	if (_machine != _MACH_Pmac)
+		return 0;
+
+	switch (pmu_get_model()) {
+	case PMU_OHARE_BASED:
+		pmac_pm_init_3400();
+		break;
+	case PMU_HEATHROW_BASED:
+	case PMU_PADDINGTON_BASED:
+		pmac_pm_init_grackle();
+		break;
+	case PMU_KEYLARGO_BASED:
+		pmac_pm_init_core99();
+		break;
+	}
+
+#ifdef CONFIG_SOFTWARE_SUSPEND
+	ppc_md.save_processor_state = pmac_pmdisk_save_state;
+	ppc_md.restore_processor_state = pmac_pmdisk_restore_state;
+#endif
+
+	pm_set_ops(&pmac_pm_ops);
+
+	return 0;
+}
+
+late_initcall(pmac_pm_init);
Index: linux-work/arch/ppc/platforms/pmac_setup.c
===================================================================
--- linux-work.orig/arch/ppc/platforms/pmac_setup.c	2005-05-02 10:48:08.000000000 +1000
+++ linux-work/arch/ppc/platforms/pmac_setup.c	2005-05-28 10:30:21.000000000 +1000
@@ -423,68 +423,6 @@
 #endif
 }
 
-static int initializing = 1;
-/* TODO: Merge the suspend-to-ram with the common code !!!
- * currently, this is a stub implementation for suspend-to-disk
- * only
- */
-
-#ifdef CONFIG_SOFTWARE_SUSPEND
-
-static int pmac_pm_prepare(suspend_state_t state)
-{
-	printk(KERN_DEBUG "%s(%d)\n", __FUNCTION__, state);
-
-	return 0;
-}
-
-static int pmac_pm_enter(suspend_state_t state)
-{
-	printk(KERN_DEBUG "%s(%d)\n", __FUNCTION__, state);
-
-	/* 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 (cur_cpu_spec[0]->cpu_features & CPU_FTR_ALTIVEC)
-		enable_kernel_altivec();
-#endif /* CONFIG_ALTIVEC */
-
-	return 0;
-}
-
-static int pmac_pm_finish(suspend_state_t state)
-{
-	printk(KERN_DEBUG "%s(%d)\n", __FUNCTION__, state);
-
-	/* Restore userland MMU context */
-	set_context(current->active_mm->context, current->active_mm->pgd);
-
-	return 0;
-}
-
-static struct pm_ops pmac_pm_ops = {
-	.pm_disk_mode	= PM_DISK_SHUTDOWN,
-	.prepare	= pmac_pm_prepare,
-	.enter		= pmac_pm_enter,
-	.finish		= pmac_pm_finish,
-};
-
-#endif /* CONFIG_SOFTWARE_SUSPEND */
-
-static int pmac_late_init(void)
-{
-	initializing = 0;
-#ifdef CONFIG_SOFTWARE_SUSPEND
-	pm_set_ops(&pmac_pm_ops);
-#endif /* CONFIG_SOFTWARE_SUSPEND */
-	return 0;
-}
-
-late_initcall(pmac_late_init);
-
 /* can't be __init - can be called whenever a disk is first accessed */
 void __pmac
 note_bootable_part(dev_t dev, int part, int goodness)
@@ -492,7 +430,7 @@
 	static int found_boot = 0;
 	char *p;
 
-	if (!initializing)
+	if (system_state != SYSTEM_BOOTING)
 		return;
 	if ((goodness <= current_root_goodness) &&
 	    ROOT_DEV != DEFAULT_ROOT_DEVICE)
Index: linux-work/drivers/base/power/suspend.c
===================================================================
--- linux-work.orig/drivers/base/power/suspend.c	2005-05-26 13:27:08.000000000 +1000
+++ linux-work/drivers/base/power/suspend.c	2005-05-28 10:30:21.000000000 +1000
@@ -113,8 +113,19 @@
 		put_device(dev);
 	}
 	up(&dpm_list_sem);
-	if (error)
+	if (error) {
+		/* we failed... before resuming, bring back devices from
+		 * dpm_off_irq list back to main dpm_off list, we do want
+		 * to call resume() on them, in case they partially suspended
+		 * despite returning -EAGAIN
+		 */
+		while (!list_empty(&dpm_off_irq)) {
+			struct list_head * entry = dpm_off_irq.next;
+			list_del(entry);
+			list_add(entry, &dpm_off);
+		}
 		dpm_resume();
+	}
 	up(&dpm_sem);
 	return error;
 }
Index: linux-work/drivers/macintosh/via-pmu.c
===================================================================
--- linux-work.orig/drivers/macintosh/via-pmu.c	2005-05-28 10:30:17.000000000 +1000
+++ linux-work/drivers/macintosh/via-pmu.c	2005-05-28 10:30:21.000000000 +1000
@@ -14,10 +14,7 @@
  * THIS DRIVER IS BECOMING A TOTAL MESS !
  *  - Cleanup atomically disabling reply to PMU events after
  *    a sleep or a freq. switch
- *  - Move sleep code out of here to pmac_pm, merge into new
- *    common PM infrastructure
  *  - Move backlight code out as well
- *  - Save/Restore PCI space properly
  *
  */
 #include <stdarg.h>
@@ -45,8 +42,6 @@
 #include <linux/device.h>
 #include <linux/sysdev.h>
 #include <linux/suspend.h>
-#include <linux/syscalls.h>
-#include <linux/cpu.h>
 #include <asm/prom.h>
 #include <asm/machdep.h>
 #include <asm/io.h>
@@ -54,11 +49,11 @@
 #include <asm/system.h>
 #include <asm/sections.h>
 #include <asm/irq.h>
-#include <asm/pmac_feature.h>
 #include <asm/uaccess.h>
-#include <asm/mmu_context.h>
 #include <asm/cputable.h>
 #include <asm/time.h>
+#include <asm/pmac_feature.h>
+
 #ifdef CONFIG_PMAC_BACKLIGHT
 #include <asm/backlight.h>
 #endif
@@ -70,7 +65,6 @@
 /* Some compile options */
 #undef SUSPEND_USES_PMU
 #define DEBUG_SLEEP
-#undef HACKED_PCI_SAVE
 
 /* Misc minor number allocated for /dev/pmu */
 #define PMU_MINOR		154
@@ -155,12 +149,12 @@
 static u8 pmu_intr_mask;
 static int pmu_version;
 static int drop_interrupts;
-#ifdef CONFIG_PMAC_PBOOK
-static int option_lid_wakeup = 1;
-static int sleep_in_progress;
-#endif /* CONFIG_PMAC_PBOOK */
 static unsigned long async_req_locks;
 static unsigned int pmu_irq_stats[11];
+static int pmu_sys_suspended = 0;
+
+/* from pmac_pm ... */
+extern int pmac_option_lid_wakeup;
 
 static struct proc_dir_entry *proc_pmu_root;
 static struct proc_dir_entry *proc_pmu_info;
@@ -168,7 +162,6 @@
 static struct proc_dir_entry *proc_pmu_options;
 static int option_server_mode;
 
-#ifdef CONFIG_PMAC_PBOOK
 int pmu_battery_count;
 int pmu_cur_battery;
 unsigned int pmu_power_flags;
@@ -176,14 +169,11 @@
 static int query_batt_timer = BATTERY_POLLING_COUNT;
 static struct adb_request batt_req;
 static struct proc_dir_entry *proc_pmu_batt[PMU_MAX_BATTERIES];
-#endif /* CONFIG_PMAC_PBOOK */
 
 #if defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT)
 extern int disable_kernel_backlight;
 #endif /* defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT) */
 
-int __fake_sleep;
-int asleep;
 struct notifier_block *sleep_notifier_list;
 
 #ifdef CONFIG_ADB
@@ -210,11 +200,9 @@
 static int pmu_set_backlight_level(int level, void* data);
 static int pmu_set_backlight_enable(int on, int level, void* data);
 #endif /* CONFIG_PMAC_BACKLIGHT */
-#ifdef CONFIG_PMAC_PBOOK
 static void pmu_pass_intr(unsigned char *data, int len);
 static int proc_get_batt(char *page, char **start, off_t off,
 			int count, int *eof, void *data);
-#endif /* CONFIG_PMAC_PBOOK */
 static int proc_read_options(char *page, char **start, off_t off,
 			int count, int *eof, void *data);
 static int proc_write_options(struct file *file, const char __user *buffer,
@@ -232,10 +220,6 @@
 };
 #endif /* CONFIG_ADB */
 
-extern void low_sleep_handler(void);
-extern void enable_kernel_altivec(void);
-extern void enable_kernel_fp(void);
-
 #ifdef DEBUG_SLEEP
 int pmu_polled_request(struct adb_request *req);
 int pmu_wink(struct adb_request *req);
@@ -407,9 +391,7 @@
 
 	bright_req_1.complete = 1;
 	bright_req_2.complete = 1;
-#ifdef CONFIG_PMAC_PBOOK
 	batt_req.complete = 1;
-#endif
 
 #ifdef CONFIG_PPC32
 	if (pmu_kind == PMU_KEYLARGO_BASED)
@@ -468,7 +450,6 @@
 	register_backlight_controller(&pmu_backlight_controller, NULL, "pmu");
 #endif /* CONFIG_PMAC_BACKLIGHT */
 
-#ifdef CONFIG_PMAC_PBOOK
   	if (machine_is_compatible("AAPL,3400/2400") ||
   		machine_is_compatible("AAPL,3500")) {
 		int mb = pmac_call_feature(PMAC_FTR_GET_MB_INFO,
@@ -496,11 +477,9 @@
 				pmu_batteries[1].flags |= PMU_BATT_TYPE_SMART;
 		}
 	}
-#endif /* CONFIG_PMAC_PBOOK */
 	/* Create /proc/pmu */
 	proc_pmu_root = proc_mkdir("pmu", NULL);
 	if (proc_pmu_root) {
-#ifdef CONFIG_PMAC_PBOOK
 		int i;
 
 		for (i=0; i<pmu_battery_count; i++) {
@@ -509,7 +488,6 @@
 			proc_pmu_batt[i] = create_proc_read_entry(title, 0, proc_pmu_root,
 						proc_get_batt, (void *)i);
 		}
-#endif /* CONFIG_PMAC_PBOOK */
 
 		proc_pmu_info = create_proc_read_entry("info", 0, proc_pmu_root,
 					proc_get_info, NULL);
@@ -595,17 +573,6 @@
 	return pmu_kind;
 }
 
-#ifndef CONFIG_PPC64
-static inline void wakeup_decrementer(void)
-{
-	set_dec(tb_ticks_per_jiffy);
-	/* No currently-supported powerbook has a 601,
-	 * so use get_tbl, not native
-	 */
-	last_jiffy_stamp(0) = tb_last_stamp = get_tbl();
-}
-#endif
-
 static void pmu_set_server_mode(int server_mode)
 {
 	struct adb_request req;
@@ -629,7 +596,6 @@
 	pmu_wait_complete(&req);
 }
 
-#ifdef CONFIG_PMAC_PBOOK
 
 /* This new version of the code for 2400/3400/3500 powerbooks
  * is inspired from the implementation in gkrellm-pmu
@@ -803,6 +769,8 @@
 static void __pmac
 query_battery_state(void)
 {
+	if (pmu_sys_suspended)
+		return;
 	if (test_and_set_bit(0, &async_req_locks))
 		return;
 	if (pmu_kind == PMU_OHARE_BASED)
@@ -813,8 +781,6 @@
 			2, PMU_SMART_BATTERY_STATE, pmu_cur_battery+1);
 }
 
-#endif /* CONFIG_PMAC_PBOOK */
-
 static int __pmac
 proc_get_info(char *page, char **start, off_t off,
 		int count, int *eof, void *data)
@@ -823,11 +789,9 @@
 
 	p += sprintf(p, "PMU driver version     : %d\n", PMU_DRIVER_VERSION);
 	p += sprintf(p, "PMU firmware version   : %02x\n", pmu_version);
-#ifdef CONFIG_PMAC_PBOOK
 	p += sprintf(p, "AC Power               : %d\n",
 		((pmu_power_flags & PMU_PWR_AC_PRESENT) != 0));
 	p += sprintf(p, "Battery count          : %d\n", pmu_battery_count);
-#endif /* CONFIG_PMAC_PBOOK */
 
 	return p - page;
 }
@@ -859,7 +823,6 @@
 	return p - page;
 }
 
-#ifdef CONFIG_PMAC_PBOOK
 static int __pmac
 proc_get_batt(char *page, char **start, off_t off,
 		int count, int *eof, void *data)
@@ -883,7 +846,6 @@
 
 	return p - page;
 }
-#endif /* CONFIG_PMAC_PBOOK */
 
 static int __pmac
 proc_read_options(char *page, char **start, off_t off,
@@ -891,11 +853,9 @@
 {
 	char *p = page;
 
-#ifdef CONFIG_PMAC_PBOOK
 	if (pmu_kind == PMU_KEYLARGO_BASED &&
 	    pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,-1) >= 0)
-		p += sprintf(p, "lid_wakeup=%d\n", option_lid_wakeup);
-#endif /* CONFIG_PMAC_PBOOK */
+		p += sprintf(p, "lid_wakeup=%d\n", pmac_option_lid_wakeup);
 	if (pmu_kind == PMU_KEYLARGO_BASED)
 		p += sprintf(p, "server_mode=%d\n", option_server_mode);
 
@@ -932,12 +892,10 @@
 	*(val++) = 0;
 	while(*val == ' ')
 		val++;
-#ifdef CONFIG_PMAC_PBOOK
 	if (pmu_kind == PMU_KEYLARGO_BASED &&
 	    pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,-1) >= 0)
 		if (!strcmp(label, "lid_wakeup"))
-			option_lid_wakeup = ((*val) == '1');
-#endif /* CONFIG_PMAC_PBOOK */
+			pmac_option_lid_wakeup = ((*val) == '1');
 	if (pmu_kind == PMU_KEYLARGO_BASED && !strcmp(label, "server_mode")) {
 		int new_value;
 		new_value = ((*val) == '1');
@@ -1344,7 +1302,6 @@
 	unsigned char ints, pirq;
 	int i = 0;
 
-	asleep = 0;
 	if (drop_interrupts || len < 1) {
 		adb_int_pending = 0;
 		pmu_irq_stats[8]++;
@@ -1432,7 +1389,6 @@
 	}
 	/* Tick interrupt */
 	else if ((1 << pirq) & PMU_INT_TICK) {
-#ifdef CONFIG_PMAC_PBOOK
 		/* Environement or tick interrupt, query batteries */
 		if (pmu_battery_count) {
 			if ((--query_batt_timer) == 0) {
@@ -1447,7 +1403,6 @@
 		pmu_pass_intr(data, len);
 	} else {
 	       pmu_pass_intr(data, len);
-#endif /* CONFIG_PMAC_PBOOK */
 	}
 	goto next;
 }
@@ -1692,6 +1647,8 @@
 	
 	if (vias == NULL)
 		return -ENODEV;
+	if (pmu_sys_suspended)
+		return -EIO;
 
 	if (on) {
 		pmu_request(&req, NULL, 2, PMU_BACKLIGHT_BRIGHT,
@@ -1719,6 +1676,8 @@
 {
 	if (vias == NULL)
 		return -ENODEV;
+	if (pmu_sys_suspended)
+		return -EIO;
 
 	if (test_and_set_bit(1, &async_req_locks))
 		return -EAGAIN;
@@ -2062,201 +2021,9 @@
 	return -1;
 }
 
-#ifdef CONFIG_PMAC_PBOOK
-
-static LIST_HEAD(sleep_notifiers);
-
-int
-pmu_register_sleep_notifier(struct pmu_sleep_notifier *n)
-{
-	struct list_head *list;
-	struct pmu_sleep_notifier *notifier;
-
-	for (list = sleep_notifiers.next; list != &sleep_notifiers;
-	     list = list->next) {
-		notifier = list_entry(list, struct pmu_sleep_notifier, list);
-		if (n->priority > notifier->priority)
-			break;
-	}
-	__list_add(&n->list, list->prev, list);
-	return 0;
-}
-
-int
-pmu_unregister_sleep_notifier(struct pmu_sleep_notifier* n)
-{
-	if (n->list.next == 0)
-		return -ENOENT;
-	list_del(&n->list);
-	n->list.next = NULL;
-	return 0;
-}
-
-/* Sleep is broadcast last-to-first */
-static int __pmac
-broadcast_sleep(int when, int fallback)
-{
-	int ret = PBOOK_SLEEP_OK;
-	struct list_head *list;
-	struct pmu_sleep_notifier *notifier;
-
-	for (list = sleep_notifiers.prev; list != &sleep_notifiers;
-	     list = list->prev) {
-		notifier = list_entry(list, struct pmu_sleep_notifier, list);
-		ret = notifier->notifier_call(notifier, when);
-		if (ret != PBOOK_SLEEP_OK) {
-			printk(KERN_DEBUG "sleep %d rejected by %p (%p)\n",
-			       when, notifier, notifier->notifier_call);
-			for (; list != &sleep_notifiers; list = list->next) {
-				notifier = list_entry(list, struct pmu_sleep_notifier, list);
-				notifier->notifier_call(notifier, fallback);
-			}
-			return ret;
-		}
-	}
-	return ret;
-}
-
-/* Wake is broadcast first-to-last */
-static int __pmac
-broadcast_wake(void)
-{
-	int ret = PBOOK_SLEEP_OK;
-	struct list_head *list;
-	struct pmu_sleep_notifier *notifier;
-
-	for (list = sleep_notifiers.next; list != &sleep_notifiers;
-	     list = list->next) {
-		notifier = list_entry(list, struct pmu_sleep_notifier, list);
-		notifier->notifier_call(notifier, PBOOK_WAKE);
-	}
-	return ret;
-}
-
-/*
- * This struct is used to store config register values for
- * PCI devices which may get powered off when we sleep.
- */
-static struct pci_save {
-#ifndef HACKED_PCI_SAVE
-	u16	command;
-	u16	cache_lat;
-	u16	intr;
-	u32	rom_address;
-#else
-	u32	config[16];
-#endif	
-} *pbook_pci_saves;
-static int pbook_npci_saves;
-
-static void __pmac
-pbook_alloc_pci_save(void)
-{
-	int npci;
-	struct pci_dev *pd = NULL;
-
-	npci = 0;
-	while ((pd = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pd)) != NULL) {
-		++npci;
-	}
-	if (npci == 0)
-		return;
-	pbook_pci_saves = (struct pci_save *)
-		kmalloc(npci * sizeof(struct pci_save), GFP_KERNEL);
-	pbook_npci_saves = npci;
-}
-
-static void __pmac
-pbook_free_pci_save(void)
-{
-	if (pbook_pci_saves == NULL)
-		return;
-	kfree(pbook_pci_saves);
-	pbook_pci_saves = NULL;
-	pbook_npci_saves = 0;
-}
 
-static void __pmac
-pbook_pci_save(void)
-{
-	struct pci_save *ps = pbook_pci_saves;
-	struct pci_dev *pd = NULL;
-	int npci = pbook_npci_saves;
-	
-	if (ps == NULL)
-		return;
-
-	while ((pd = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pd)) != NULL) {
-		if (npci-- == 0)
-			return;
-#ifndef HACKED_PCI_SAVE
-		pci_read_config_word(pd, PCI_COMMAND, &ps->command);
-		pci_read_config_word(pd, PCI_CACHE_LINE_SIZE, &ps->cache_lat);
-		pci_read_config_word(pd, PCI_INTERRUPT_LINE, &ps->intr);
-		pci_read_config_dword(pd, PCI_ROM_ADDRESS, &ps->rom_address);
-#else
-		int i;
-		for (i=1;i<16;i++)
-			pci_read_config_dword(pd, i<<4, &ps->config[i]);
-#endif
-		++ps;
-	}
-}
-
-/* For this to work, we must take care of a few things: If gmac was enabled
- * during boot, it will be in the pci dev list. If it's disabled at this point
- * (and it will probably be), then you can't access it's config space.
- */
-static void __pmac
-pbook_pci_restore(void)
-{
-	u16 cmd;
-	struct pci_save *ps = pbook_pci_saves - 1;
-	struct pci_dev *pd = NULL;
-	int npci = pbook_npci_saves;
-	int j;
-
-	while ((pd = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pd)) != NULL) {
-#ifdef HACKED_PCI_SAVE
-		int i;
-		if (npci-- == 0)
-			return;
-		ps++;
-		for (i=2;i<16;i++)
-			pci_write_config_dword(pd, i<<4, ps->config[i]);
-		pci_write_config_dword(pd, 4, ps->config[1]);
-#else
-		if (npci-- == 0)
-			return;
-		ps++;
-		if (ps->command == 0)
-			continue;
-		pci_read_config_word(pd, PCI_COMMAND, &cmd);
-		if ((ps->command & ~cmd) == 0)
-			continue;
-		switch (pd->hdr_type) {
-		case PCI_HEADER_TYPE_NORMAL:
-			for (j = 0; j < 6; ++j)
-				pci_write_config_dword(pd,
-					PCI_BASE_ADDRESS_0 + j*4,
-					pd->resource[j].start);
-			pci_write_config_dword(pd, PCI_ROM_ADDRESS,
-				ps->rom_address);
-			pci_write_config_word(pd, PCI_CACHE_LINE_SIZE,
-				ps->cache_lat);
-			pci_write_config_word(pd, PCI_INTERRUPT_LINE,
-				ps->intr);
-			pci_write_config_word(pd, PCI_COMMAND, ps->command);
-			break;
-		}
-#endif	
-	}
-}
-
-#ifdef DEBUG_SLEEP
 /* N.B. This doesn't work on the 3400 */
-void  __pmac
-pmu_blink(int n)
+void  __pmac pmu_blink(int n)
 {
 	struct adb_request req;
 
@@ -2288,7 +2055,6 @@
 	}
 	mdelay(50);
 }
-#endif
 
 /*
  * Put the powerbook to sleep.
@@ -2296,8 +2062,7 @@
  
 static u32 save_via[8] __pmacdata;
 
-static void __pmac
-save_via_state(void)
+void __pmac pmu_save_via_state(void)
 {
 	save_via[0] = in_8(&via[ANH]);
 	save_via[1] = in_8(&via[DIRA]);
@@ -2308,8 +2073,7 @@
 	save_via[6] = in_8(&via[T1CL]);
 	save_via[7] = in_8(&via[T1CH]);
 }
-static void __pmac
-restore_via_state(void)
+void __pmac pmu_restore_via_state(void)
 {
 	out_8(&via[ANH], save_via[0]);
 	out_8(&via[DIRA], save_via[1]);
@@ -2324,390 +2088,6 @@
 	out_8(&via[IER], IER_SET | SR_INT | CB1_INT);
 }
 
-static int __pmac
-pmac_suspend_devices(void)
-{
-	int ret;
-
-	pm_prepare_console();
-	
-	/* Notify old-style device drivers & userland */
-	ret = broadcast_sleep(PBOOK_SLEEP_REQUEST, PBOOK_SLEEP_REJECT);
-	if (ret != PBOOK_SLEEP_OK) {
-		printk(KERN_ERR "Sleep rejected by drivers\n");
-		return -EBUSY;
-	}
-
-	/* 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();
-
-	/* Sleep can fail now. May not be very robust but useful for debugging */
-	ret = broadcast_sleep(PBOOK_SLEEP_NOW, PBOOK_WAKE);
-	if (ret != PBOOK_SLEEP_OK) {
-		printk(KERN_ERR "Driver sleep failed\n");
-		return -EBUSY;
-	}
-
-	/* 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;
-	}
-
-	/* Disable clock spreading on some machines */
-	pmac_tweak_clock_spreading(0);
-
-	/* 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 backlight requests */
-	while (!bright_req_1.complete || !bright_req_2.complete ||
-			!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
-pmac_wakeup_devices(void)
-{
-	mdelay(100);
-
-	/* 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, NULL);
-
-	/* Restart jiffies & scheduling */
-	wakeup_decrementer();
-
-	/* Re-enable local CPU interrupts */
-	local_irq_enable();
-	mdelay(10);
-	preempt_enable();
-
-	/* Re-enable clock spreading on some machines */
-	pmac_tweak_clock_spreading(1);
-
-	/* 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)
-#define	GRACKLE_SLEEP	(1<<3)
-
-int __pmac
-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);
-	pmu_request(&req, NULL, 2, PMU_POWER_CTRL,
-		PMU_POW_OFF|PMU_POW_BACKLIGHT|PMU_POW_IRLED|PMU_POW_MEDIABAY);
-	pmu_wait_complete(&req);
-
-	/* For 750, save backside cache setting and disable it */
-	save_l2cr = _get_L2CR();	/* (returns -1 if not available) */
-
-	if (!__fake_sleep) {
-		/* Ask the PMU to put us to sleep */
-		pmu_request(&req, NULL, 5, PMU_SLEEP, 'M', 'A', 'T', 'T');
-		pmu_wait_complete(&req);
-	}
-
-	/* The VIA is supposed not to be restored correctly*/
-	save_via_state();
-	/* We shut down some HW */
-	pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,1);
-
-	pci_read_config_word(grackle, 0x70, &pmcr1);
-	/* Apparently, MacOS uses NAP mode for Grackle ??? */
-	pmcr1 &= ~(GRACKLE_DOZE|GRACKLE_SLEEP); 
-	pmcr1 |= GRACKLE_PM|GRACKLE_NAP;
-	pci_write_config_word(grackle, 0x70, pmcr1);
-
-	/* Call low-level ASM sleep handler */
-	if (__fake_sleep)
-		mdelay(5000);
-	else
-		low_sleep_handler();
-
-	/* We're awake again, stop grackle PM */
-	pci_read_config_word(grackle, 0x70, &pmcr1);
-	pmcr1 &= ~(GRACKLE_PM|GRACKLE_DOZE|GRACKLE_SLEEP|GRACKLE_NAP); 
-	pci_write_config_word(grackle, 0x70, pmcr1);
-
-	/* Make sure the PMU is idle */
-	pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,0);
-	restore_via_state();
-	
-	/* Restore L2 cache */
-	if (save_l2cr != 0xffffffff && (save_l2cr & L2CR_L2E) != 0)
- 		_set_L2CR(save_l2cr);
-	
-	/* Restore userland MMU context */
-	set_context(current->active_mm->context, current->active_mm->pgd);
-
-	/* Power things up */
-	pmu_unlock();
-	pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, pmu_intr_mask);
-	pmu_wait_complete(&req);
-	pmu_request(&req, NULL, 2, PMU_POWER_CTRL0,
-			PMU_POW0_ON|PMU_POW0_HARD_DRIVE);
-	pmu_wait_complete(&req);
-	pmu_request(&req, NULL, 2, PMU_POWER_CTRL,
-			PMU_POW_ON|PMU_POW_BACKLIGHT|PMU_POW_CHARGER|PMU_POW_IRLED|PMU_POW_MEDIABAY);
-	pmu_wait_complete(&req);
-
-	pmac_wakeup_devices();
-
-	return 0;
-}
-
-static int __pmac
-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");
-		return -ENOSYS;
-	}
-
-	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);
-
-	/* Tell PMU what events will wake us up */
-	pmu_request(&req, NULL, 4, PMU_POWER_EVENTS, PMU_PWR_CLR_WAKEUP_EVENTS,
-		0xff, 0xff);
-	pmu_wait_complete(&req);
-	pmu_request(&req, NULL, 4, PMU_POWER_EVENTS, PMU_PWR_SET_WAKEUP_EVENTS,
-		0, PMU_PWR_WAKEUP_KEY |
-		(option_lid_wakeup ? PMU_PWR_WAKEUP_LID_OPEN : 0));
-	pmu_wait_complete(&req);
-
-	/* Save the state of the L2 and L3 caches */
-	save_l3cr = _get_L3CR();	/* (returns -1 if not available) */
-	save_l2cr = _get_L2CR();	/* (returns -1 if not available) */
-
-	if (!__fake_sleep) {
-		/* Ask the PMU to put us to sleep */
-		pmu_request(&req, NULL, 5, PMU_SLEEP, 'M', 'A', 'T', 'T');
-		pmu_wait_complete(&req);
-	}
-
-	/* The VIA is supposed not to be restored correctly*/
-	save_via_state();
-
-	/* Shut down various ASICs. There's a chance that we can no longer
-	 * talk to the PMU after this, so I moved it to _after_ sending the
-	 * sleep command to it. Still need to be checked.
-	 */
-	pmac_call_feature(PMAC_FTR_SLEEP_STATE, NULL, 0, 1);
-
-	/* Call low-level ASM sleep handler */
-	if (__fake_sleep)
-		mdelay(5000);
-	else
-		low_sleep_handler();
-
-	/* Restore Apple core ASICs state */
-	pmac_call_feature(PMAC_FTR_SLEEP_STATE, NULL, 0, 0);
-
-	/* Restore VIA */
-	restore_via_state();
-
-	/* Restore video */
-	pmac_call_early_video_resume();
-
-	/* Restore L2 cache */
-	if (save_l2cr != 0xffffffff && (save_l2cr & L2CR_L2E) != 0)
- 		_set_L2CR(save_l2cr);
-	/* Restore L3 cache */
-	if (save_l3cr != 0xffffffff && (save_l3cr & L3CR_L3E) != 0)
- 		_set_L3CR(save_l3cr);
-	
-	/* Restore userland MMU context */
-	set_context(current->active_mm->context, current->active_mm->pgd);
-
-	/* Tell PMU we are ready */
-	pmu_unlock();
-	pmu_request(&req, NULL, 2, PMU_SYSTEM_READY, 2);
-	pmu_wait_complete(&req);
-	pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, pmu_intr_mask);
-	pmu_wait_complete(&req);
-
-	pmac_wakeup_devices();
-
-	return 0;
-}
-
-#define PB3400_MEM_CTRL		0xf8000000
-#define PB3400_MEM_CTRL_SLEEP	0x70
-
-static int __pmac
-powerbook_sleep_3400(void)
-{
-	int ret, i, x;
-	unsigned int hid0;
-	unsigned long p;
-	struct adb_request sleep_req;
-	void __iomem *mem_ctrl;
-	unsigned int __iomem *mem_ctrl_sleep;
-
-	/* first map in the memory controller registers */
-	mem_ctrl = ioremap(PB3400_MEM_CTRL, 0x100);
-	if (mem_ctrl == NULL) {
-		printk("powerbook_sleep_3400: ioremap failed\n");
-		return -ENOMEM;
-	}
-	mem_ctrl_sleep = mem_ctrl + PB3400_MEM_CTRL_SLEEP;
-
-	/* 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();
-
-	/* Set the memory controller to keep the memory refreshed
-	   while we're asleep */
-	for (i = 0x403f; i >= 0x4000; --i) {
-		out_be32(mem_ctrl_sleep, i);
-		do {
-			x = (in_be32(mem_ctrl_sleep) >> 16) & 0x3ff;
-		} while (x == 0);
-		if (x >= 0x100)
-			break;
-	}
-
-	/* Ask the PMU to put us to sleep */
-	pmu_request(&sleep_req, NULL, 5, PMU_SLEEP, 'M', 'A', 'T', 'T');
-	while (!sleep_req.complete)
-		mb();
-
-	pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,1);
-
-	/* displacement-flush the L2 cache - necessary? */
-	for (p = KERNELBASE; p < KERNELBASE + 0x100000; p += 0x1000)
-		i = *(volatile int *)p;
-	asleep = 1;
-
-	/* Put the CPU into sleep mode */
-	asm volatile("mfspr %0,1008" : "=r" (hid0) :);
-	hid0 = (hid0 & ~(HID0_NAP | HID0_DOZE)) | HID0_SLEEP;
-	asm volatile("mtspr 1008,%0" : : "r" (hid0));
-	_nmask_and_or_msr(0, MSR_POW | MSR_EE);
-	udelay(10);
-
-	/* OK, we're awake again, start restoring things */
-	out_be32(mem_ctrl_sleep, 0x3f);
-	pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,0);
-	pbook_pci_restore();
-	pmu_unlock();
-
-	/* wait for the PMU interrupt sequence to complete */
-	while (asleep)
-		mb();
-
-	pmac_wakeup_devices();
-	pbook_free_pci_save();
-	iounmap(mem_ctrl);
-
-	return 0;
-}
 
 /*
  * Support for /dev/pmu device
@@ -2896,24 +2276,10 @@
 	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;
+		if (pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,-1) < 0)
+			error = pm_suspend(PM_SUSPEND_DISK);		
+		else
+			error = pm_suspend(PM_SUSPEND_MEM);		
 		return error;
 	case PMU_IOC_CAN_SLEEP:
 		if (pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,-1) < 0)
@@ -2926,8 +2292,6 @@
 	 * the fbdev
 	 */
 	case PMU_IOC_GET_BACKLIGHT:
-		if (sleep_in_progress)
-			return -EBUSY;
 		error = get_backlight_level();
 		if (error < 0)
 			return error;
@@ -2935,8 +2299,6 @@
 	case PMU_IOC_SET_BACKLIGHT:
 	{
 		__u32 value;
-		if (sleep_in_progress)
-			return -EBUSY;
 		error = get_user(value, argp);
 		if (!error)
 			error = set_backlight_level(value);
@@ -2983,7 +2345,6 @@
 	if (misc_register(&pmu_device) < 0)
 		printk(KERN_ERR "via-pmu: cannot register misc device.\n");
 }
-#endif /* CONFIG_PMAC_PBOOK */
 
 #ifdef DEBUG_SLEEP
 static inline void  __pmac
@@ -3065,17 +2426,29 @@
 
 #ifdef CONFIG_PM
 
-static int pmu_sys_suspended = 0;
-
 static int pmu_sys_suspend(struct sys_device *sysdev, pm_message_t state)
 {
-	if (state != PM_SUSPEND_DISK || pmu_sys_suspended)
+	struct adb_request req;
+
+	if (pmu_sys_suspended)
 		return 0;
 
+	/* Stop environment interrupts */
+	pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, 0);
+	pmu_wait_complete(&req);
+
 	/* Suspend PMU event interrupts */
 	pmu_suspend();
 
+	/* Mark driver suspended */
 	pmu_sys_suspended = 1;
+
+	/* Wait for completion of async backlight requests */
+	while (!bright_req_1.complete || !bright_req_2.complete ||
+			!batt_req.complete)
+		pmu_poll();
+	
+
 	return 0;
 }
 
@@ -3086,6 +2459,10 @@
 	if (!pmu_sys_suspended)
 		return 0;
 
+	/* Restart environment interrupts */ 
+	pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, pmu_intr_mask);
+	pmu_wait_complete(&req);
+
 	/* Tell PMU we are ready */
 	pmu_request(&req, NULL, 2, PMU_SYSTEM_READY, 2);
 	pmu_wait_complete(&req);
@@ -3093,6 +2470,7 @@
 	/* Resume PMU event interrupts */
 	pmu_resume();
 
+	/* Mark driver ready for async requests */
 	pmu_sys_suspended = 0;
 
 	return 0;
@@ -3151,12 +2529,8 @@
 EXPORT_SYMBOL(pmu_i2c_stdsub_write);
 EXPORT_SYMBOL(pmu_i2c_simple_read);
 EXPORT_SYMBOL(pmu_i2c_simple_write);
-#ifdef CONFIG_PMAC_PBOOK
-EXPORT_SYMBOL(pmu_register_sleep_notifier);
-EXPORT_SYMBOL(pmu_unregister_sleep_notifier);
 EXPORT_SYMBOL(pmu_enable_irled);
 EXPORT_SYMBOL(pmu_battery_count);
 EXPORT_SYMBOL(pmu_batteries);
 EXPORT_SYMBOL(pmu_power_flags);
-#endif /* CONFIG_PMAC_PBOOK */
 
Index: linux-work/include/asm-ppc/machdep.h
===================================================================
--- linux-work.orig/include/asm-ppc/machdep.h	2005-05-02 10:49:57.000000000 +1000
+++ linux-work/include/asm-ppc/machdep.h	2005-05-28 10:30:21.000000000 +1000
@@ -110,6 +110,12 @@
 	 */
 	long (*feature_call)(unsigned int feature, ...);
 
+#ifdef CONFIG_SOFTWARE_SUSPEND
+	int (*arch_prepare_suspend)(void);
+	void (*save_processor_state)(void);
+	void (*restore_processor_state)(void);
+#endif /* CONFIG_SOFTWARE_SUSPEND */
+
 #ifdef CONFIG_SMP
 	/* functions for dealing with other cpus */
 	struct smp_ops_t *smp_ops;
Index: linux-work/include/asm-ppc/suspend.h
===================================================================
--- linux-work.orig/include/asm-ppc/suspend.h	2005-05-02 10:49:59.000000000 +1000
+++ linux-work/include/asm-ppc/suspend.h	2005-05-28 10:30:21.000000000 +1000
@@ -1,12 +1,44 @@
+#ifndef __PPC_SUSPEND_H
+#define __PPC_SUSPEND_H
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <asm/machdep.h>
+
+
+#ifdef CONFIG_SOFTWARE_SUSPEND
 static inline int arch_prepare_suspend(void)
 {
+	if (ppc_md.arch_prepare_suspend)
+		return ppc_md.arch_prepare_suspend();
 	return 0;
 }
 
 static inline void save_processor_state(void)
 {
+	if (ppc_md.save_processor_state)
+		return ppc_md.save_processor_state();
 }
 
 static inline void restore_processor_state(void)
 {
+	if (ppc_md.restore_processor_state)
+		return ppc_md.restore_processor_state();
 }
+#else
+static inline int arch_prepare_suspend(void)
+{
+	return 0;
+}
+
+static inline void save_processor_state(void)
+{
+}
+
+static inline void restore_processor_state(void)
+{
+}
+#endif
+
+
+#endif /* __PPC_SUSPEND_H */
Index: linux-work/include/linux/pm.h
===================================================================
--- linux-work.orig/include/linux/pm.h	2005-05-02 10:50:24.000000000 +1000
+++ linux-work/include/linux/pm.h	2005-05-28 10:30:21.000000000 +1000
@@ -169,9 +169,38 @@
 
 struct pm_ops {
 	suspend_disk_method_t pm_disk_mode;
+	
+	/* Call before process freezing. If returns 0, then no freeze
+	 * should be done, if 1, freeze, negative -> error
+	 */
+	int (*pre_freeze)(suspend_state_t state);
+
+	/* called before devices are suspended */
 	int (*prepare)(suspend_state_t state);
+
+	/* called just before irqs are off and device second pass
+	 * and sysdevs are suspended. This function can on some archs
+	 * shut irqs off, in which case, they'll still be off when
+	 * finish_irqs() is called.
+	 */
+	int (*prepare_irqs)(suspend_state_t state);
+
+	/* called for entering the actual suspend state. Exits with
+	 * machine worken up and interrupts off
+	 */
 	int (*enter)(suspend_state_t state);
-	int (*finish)(suspend_state_t state);
+
+	/* called after sysdevs and "irq off" devices have been
+	 * worken up, irqs have just been restored to whatever state
+	 * prepare_irqs() left them in.
+	 */
+	void (*finish_irqs)(suspend_state_t state);
+
+	/* called after all devices are woken up, processes still frozen */
+	void (*finish)(suspend_state_t state);
+
+	/* called after unfreezing userland */
+	void (*post_freeze)(suspend_state_t state);
 };
 
 extern void pm_set_ops(struct pm_ops *);
Index: linux-work/include/linux/pmu.h
===================================================================
--- linux-work.orig/include/linux/pmu.h	2005-05-02 10:50:24.000000000 +1000
+++ linux-work/include/linux/pmu.h	2005-05-28 10:30:21.000000000 +1000
@@ -151,6 +151,9 @@
 extern void pmu_suspend(void);
 extern void pmu_resume(void);
 
+extern void pmu_save_via_state(void);
+extern void pmu_restore_via_state(void);
+
 extern void pmu_enable_irled(int on);
 
 extern void pmu_restart(void);
Index: linux-work/kernel/power/main.c
===================================================================
--- linux-work.orig/kernel/power/main.c	2005-05-26 13:27:08.000000000 +1000
+++ linux-work/kernel/power/main.c	2005-05-28 10:30:21.000000000 +1000
@@ -23,6 +23,7 @@
 
 struct pm_ops * pm_ops = NULL;
 suspend_disk_method_t pm_disk_mode = PM_DISK_SHUTDOWN;
+static int pm_process_frozen;
 
 /**
  *	pm_set_ops - Set the global power method table. 
@@ -49,32 +50,53 @@
 static int suspend_prepare(suspend_state_t state)
 {
 	int error = 0;
+	int freeze = 1;
 
 	if (!pm_ops || !pm_ops->enter)
 		return -EPERM;
 
 	pm_prepare_console();
 
-	if (freeze_processes()) {
+	if (pm_ops->pre_freeze)
+		freeze = pm_ops->pre_freeze(state);
+	if (freeze < 0)
+		goto Console;
+
+	if (freeze && freeze_processes()) {
 		error = -EAGAIN;
 		goto Thaw;
 	}
+	pm_process_frozen = freeze;
 
 	if (pm_ops->prepare) {
+		pr_debug("preparing arch...\n");
 		if ((error = pm_ops->prepare(state)))
 			goto Thaw;
 	}
 
+	pr_debug("suspending devices...\n");
 	if ((error = device_suspend(PMSG_SUSPEND))) {
 		printk(KERN_ERR "Some devices failed to suspend\n");
 		goto Finish;
 	}
+
+	if (pm_ops->prepare_irqs) {
+		pr_debug("preparing arch irqs...\n");
+		if ((error = pm_ops->prepare_irqs(state)))
+			goto Finish;
+	}
+
 	return 0;
  Finish:
 	if (pm_ops->finish)
 		pm_ops->finish(state);
  Thaw:
-	thaw_processes();
+	if (freeze)
+		thaw_processes();
+
+	if (pm_ops->post_freeze)
+		pm_ops->post_freeze(state);
+ Console:
 	pm_restore_console();
 	return error;
 }
@@ -109,10 +131,18 @@
 
 static void suspend_finish(suspend_state_t state)
 {
+	if (!pm_ops)
+		return;
+
+	if (pm_ops->finish_irqs)
+		pm_ops->finish_irqs(state);
 	device_resume();
-	if (pm_ops && pm_ops->finish)
+	if (pm_ops->finish)
 		pm_ops->finish(state);
-	thaw_processes();
+	if (pm_process_frozen)
+		thaw_processes();
+	if (pm_ops->post_freeze)
+		pm_ops->post_freeze(state);
 	pm_restore_console();
 }
 
Index: linux-work/arch/ppc/platforms/pmac_pic.c
===================================================================
--- linux-work.orig/arch/ppc/platforms/pmac_pic.c	2005-05-02 10:48:08.000000000 +1000
+++ linux-work/arch/ppc/platforms/pmac_pic.c	2005-05-28 10:30:21.000000000 +1000
@@ -619,7 +619,7 @@
 	return viaint;
 }
 
-static int pmacpic_suspend(struct sys_device *sysdev, u32 state)
+void __pmac pmacpic_suspend(void)
 {
 	int viaint = pmacpic_find_viaint();
 
@@ -636,11 +636,9 @@
 	/* make sure mask gets to controller before we return to caller */
 	mb();
         (void)in_le32(&pmac_irq_hw[0]->enable);
-
-        return 0;
 }
 
-static int pmacpic_resume(struct sys_device *sysdev)
+void __pmac pmacpic_resume(void)
 {
 	int i;
 
@@ -651,12 +649,11 @@
 	for (i = 0; i < max_real_irqs; ++i)
 		if (test_bit(i, sleep_save_mask))
 			pmac_unmask_irq(i);
-
-	return 0;
 }
 
 #endif /* CONFIG_PM */
 
+#if 0
 static struct sysdev_class pmacpic_sysclass = {
 	set_kset_name("pmac_pic"),
 };
@@ -686,4 +683,4 @@
 }
 
 subsys_initcall(init_pmacpic_sysfs);
-
+#endif
Index: linux-work/arch/ppc/syslib/open_pic.c
===================================================================
--- linux-work.orig/arch/ppc/syslib/open_pic.c	2005-05-28 10:30:17.000000000 +1000
+++ linux-work/arch/ppc/syslib/open_pic.c	2005-05-28 10:30:21.000000000 +1000
@@ -946,11 +946,7 @@
 	save_irq_src_vp[irq - open_pic_irq_offset] |= OPENPIC_MASK;
 }
 
-/* WARNING: Can be called directly by the cpufreq code with NULL parameter,
- * we need something better to deal with that... Maybe switch to S1 for
- * cpufreq changes
- */
-int openpic_suspend(struct sys_device *sysdev, u32 state)
+void openpic_suspend(void)
 {
 	int	i;
 	unsigned long flags;
@@ -959,11 +955,9 @@
 
 	if (openpic_suspend_count++ > 0) {
 		spin_unlock_irqrestore(&openpic_setup_lock, flags);
-		return 0;
+		return;
 	}
 
- 	openpic_set_priority(0xf);
-
 	open_pic.enable = openpic_cached_enable_irq;
 	open_pic.disable = openpic_cached_disable_irq;
 
@@ -973,6 +967,8 @@
 				   OPENPIC_CURRENT_TASK_PRIORITY_MASK, 0xf);
 	}
 
+ 	openpic_set_priority(0xf);
+
 	for (i=0; i<OPENPIC_NUM_IPI; i++)
 		save_ipi_vp[i] = openpic_read(&OpenPIC->Global.IPI_Vector_Priority(i));
 	for (i=0; i<NumSources; i++) {
@@ -983,15 +979,13 @@
 	}
 
 	spin_unlock_irqrestore(&openpic_setup_lock, flags);
-
-	return 0;
 }
 
 /* WARNING: Can be called directly by the cpufreq code with NULL parameter,
  * we need something better to deal with that... Maybe switch to S1 for
  * cpufreq changes
  */
-int openpic_resume(struct sys_device *sysdev)
+void openpic_resume(void)
 {
 	int		i;
 	unsigned long	flags;
@@ -1003,9 +997,11 @@
 
 	if ((--openpic_suspend_count) > 0) {
 		spin_unlock_irqrestore(&openpic_setup_lock, flags);
-		return 0;
+		return;
 	}
 
+ 	openpic_set_priority(0xf);
+
 	/* OpenPIC sometimes seem to need some time to be fully back up... */
 	do {
 		openpic_set_spurious(OPENPIC_VEC_SPURIOUS);
@@ -1028,22 +1024,19 @@
 		} while (openpic_readfield(&ISR[i]->Vector_Priority, vppmask)
 			 != (save_irq_src_vp[i] & vppmask));
 	}
-	for (i=0; i<NumProcessors; i++)
-		openpic_write(&OpenPIC->Processor[i].Current_Task_Priority,
-			      save_cpu_task_pri[i]);
-
 	open_pic.enable = openpic_enable_irq;
 	open_pic.disable = openpic_disable_irq;
 
- 	openpic_set_priority(0);
+	for (i=0; i<NumProcessors; i++)
+		openpic_write(&OpenPIC->Processor[i].Current_Task_Priority,
+			      save_cpu_task_pri[i]);
 
 	spin_unlock_irqrestore(&openpic_setup_lock, flags);
-
-	return 0;
 }
 
 #endif /* CONFIG_PM */
 
+#if 0
 static struct sysdev_class openpic_sysclass = {
 	set_kset_name("openpic"),
 };
@@ -1087,3 +1080,4 @@
 
 subsys_initcall(init_openpic_sysfs);
 
+#endif
Index: linux-work/include/asm-ppc/open_pic.h
===================================================================
--- linux-work.orig/include/asm-ppc/open_pic.h	2005-05-28 10:29:53.000000000 +1000
+++ linux-work/include/asm-ppc/open_pic.h	2005-05-28 10:30:21.000000000 +1000
@@ -64,6 +64,9 @@
 extern void openpic_set_priority(u_int pri);
 extern u_int openpic_get_priority(void);
 
+extern void openpic_suspend(void);
+extern void openpic_resume(void);
+
 extern inline int openpic_to_irq(int irq)
 {
 	/* IRQ 0 usually means 'disabled'.. don't mess with it
Index: linux-work/arch/ppc/kernel/time.c
===================================================================
--- linux-work.orig/arch/ppc/kernel/time.c	2005-05-02 10:48:08.000000000 +1000
+++ linux-work/arch/ppc/kernel/time.c	2005-05-28 10:30:21.000000000 +1000
@@ -86,6 +86,7 @@
 unsigned tb_to_us;
 unsigned tb_last_stamp;
 unsigned long tb_to_ns_scale;
+int ppc_force_interrupt;
 
 extern unsigned long wall_jiffies;
 
@@ -131,8 +132,11 @@
 	unsigned jiffy_stamp = last_jiffy_stamp(cpu);
 	extern void do_IRQ(struct pt_regs *);
 
-	if (atomic_read(&ppc_n_lost_interrupts) != 0)
+	if ((atomic_read(&ppc_n_lost_interrupts) != 0) ||
+	    ppc_force_interrupt) {
+		ppc_force_interrupt = 0;
 		do_IRQ(regs);
+	}
 
 	irq_enter();
 
Index: linux-work/arch/ppc/platforms/pmac_cpufreq.c
===================================================================
--- linux-work.orig/arch/ppc/platforms/pmac_cpufreq.c	2005-05-28 10:30:17.000000000 +1000
+++ linux-work/arch/ppc/platforms/pmac_cpufreq.c	2005-05-28 10:30:21.000000000 +1000
@@ -112,11 +112,11 @@
 
 static inline void wakeup_decrementer(void)
 {
-	set_dec(tb_ticks_per_jiffy);
 	/* No currently-supported powerbook has a 601,
 	 * so use get_tbl, not native
 	 */
 	last_jiffy_stamp(0) = tb_last_stamp = get_tbl();
+	set_dec(1);
 }
 
 #ifdef DEBUG_FREQ
@@ -340,6 +340,9 @@
 	/* Restore interrupts */
  	openpic_set_priority(pic_prio);
 
+	/* Force a fetch from the PIC on the first DEC interrupt. */
+	ppc_force_interrupt = 1;
+
 	/* Let interrupts flow again ... */
 	local_irq_restore(flags);
 
Index: linux-work/arch/ppc/platforms/pmac_feature.c
===================================================================
--- linux-work.orig/arch/ppc/platforms/pmac_feature.c	2005-05-03 13:51:57.000000000 +1000
+++ linux-work/arch/ppc/platforms/pmac_feature.c	2005-05-28 10:30:21.000000000 +1000
@@ -548,7 +548,7 @@
 }
 
 static void __pmac
-heathrow_sleep(struct macio_chip* macio, int secondary)
+heathrow_sleep(struct macio_chip* macio, int secondary, int turnoff)
 {
 	if (secondary) {
 		dbdma_save(macio, save_alt_dbdma);
@@ -559,17 +559,22 @@
 		save_fcr[0] = MACIO_IN32(0x38);
 		save_fcr[1] = MACIO_IN32(0x3c);
 		save_mbcr = MACIO_IN32(0x34);
-		/* Make sure sound is shut down */
-		MACIO_BIS(HEATHROW_FCR, HRW_SOUND_POWER_N);
-		MACIO_BIC(HEATHROW_FCR, HRW_SOUND_CLK_ENABLE);
-		/* This seems to be necessary as well or the fan
-		 * keeps coming up and battery drains fast */
-		MACIO_BIC(HEATHROW_FCR, HRW_IOBUS_ENABLE);
-		MACIO_BIC(HEATHROW_FCR, HRW_IDE0_RESET_N);
-		/* Make sure eth is down even if module or sleep
-		 * won't work properly */
-		MACIO_BIC(HEATHROW_FCR, HRW_BMAC_IO_ENABLE | HRW_BMAC_RESET);
+		if (turnoff) {
+			/* Make sure sound is shut down */
+			MACIO_BIS(HEATHROW_FCR, HRW_SOUND_POWER_N);
+			MACIO_BIC(HEATHROW_FCR, HRW_SOUND_CLK_ENABLE);
+			/* This seems to be necessary as well or the fan
+			 * keeps coming up and battery drains fast */
+			MACIO_BIC(HEATHROW_FCR, HRW_IOBUS_ENABLE);
+			MACIO_BIC(HEATHROW_FCR, HRW_IDE0_RESET_N);
+			/* Make sure eth is down even if module or sleep
+			 * won't work properly */
+			MACIO_BIC(HEATHROW_FCR,
+				  HRW_BMAC_IO_ENABLE | HRW_BMAC_RESET);
+		}
 	}
+	if (!turnoff)
+		return;
 	/* Make sure modem is shut down */
 	MACIO_OUT8(HRW_GPIO_MODEM_RESET,
 		MACIO_IN8(HRW_GPIO_MODEM_RESET) & ~1);
@@ -612,12 +617,16 @@
 		return -EPERM;
 	if (value == 1) {
 		if (macio_chips[1].type == macio_gatwick)
-			heathrow_sleep(&macio_chips[0], 1);
-		heathrow_sleep(&macio_chips[0], 0);
+			heathrow_sleep(&macio_chips[1], 1, 1);
+		heathrow_sleep(&macio_chips[0], 0, 1);
+	} else if (value == 2) {
+		if (macio_chips[1].type == macio_gatwick)
+			heathrow_sleep(&macio_chips[1], 1, 0);
+		heathrow_sleep(&macio_chips[0], 0, 0);
 	} else if (value == 0) {
 		heathrow_wakeup(&macio_chips[0], 0);
 		if (macio_chips[1].type == macio_gatwick)
-			heathrow_wakeup(&macio_chips[0], 1);
+			heathrow_wakeup(&macio_chips[1], 1);
 	}
 	return 0;
 }
@@ -1699,7 +1708,7 @@
 
 
 static int __pmac
-core99_sleep(void)
+core99_sleep(int turnoff)
 {
 	struct macio_chip* macio;
 	int i;
@@ -1709,26 +1718,28 @@
 	    macio->type != macio_intrepid)
 		return -ENODEV;
 
-	/* We power off the wireless slot in case it was not done
-	 * by the driver. We don't power it on automatically however
-	 */
-	if (macio->flags & MACIO_FLAG_AIRPORT_ON)
-		core99_airport_enable(macio->of_node, 0, 0);
+	if (turnoff) {
+		/* We power off the wireless slot in case it was not done
+		 * by the driver. We don't power it on automatically however
+		 */
+		if (macio->flags & MACIO_FLAG_AIRPORT_ON)
+			core99_airport_enable(macio->of_node, 0, 0);
 
-	/* We power off the FW cable. Should be done by the driver... */
-	if (macio->flags & MACIO_FLAG_FW_SUPPORTED) {
-		core99_firewire_enable(NULL, 0, 0);
-		core99_firewire_cable_power(NULL, 0, 0);
-	}
+		/* We power off the FW cable.Should be done by the driver... */
+		if (macio->flags & MACIO_FLAG_FW_SUPPORTED) {
+			core99_firewire_enable(NULL, 0, 0);
+			core99_firewire_cable_power(NULL, 0, 0);
+		}
 
-	/* We make sure int. modem is off (in case driver lost it) */
-	if (macio->type == macio_keylargo)
-		core99_modem_enable(macio->of_node, 0, 0);
-	else
-		pangea_modem_enable(macio->of_node, 0, 0);
+		/* We make sure int. modem is off (in case driver lost it) */
+		if (macio->type == macio_keylargo)
+			core99_modem_enable(macio->of_node, 0, 0);
+		else
+			pangea_modem_enable(macio->of_node, 0, 0);
 
-	/* We make sure the sound is off as well */
-	core99_sound_chip_enable(macio->of_node, 0, 0);
+		/* We make sure the sound is off as well */
+		core99_sound_chip_enable(macio->of_node, 0, 0);
+	}
 
 	/*
 	 * Save various bits of KeyLargo
@@ -1756,26 +1767,32 @@
 	/* Save state & config of DBDMA channels */
 	dbdma_save(macio, save_dbdma);
 
-	/*
-	 * Turn off as much as we can
-	 */
-	if (macio->type == macio_pangea)
-		pangea_shutdown(macio, 1);
-	else if (macio->type == macio_intrepid)
-		intrepid_shutdown(macio, 1);
-	else if (macio->type == macio_keylargo)
-		keylargo_shutdown(macio, 1);
+	if (turnoff) {
+		/*
+		 * Turn off as much as we can
+		 */
+		if (macio->type == macio_pangea)
+			pangea_shutdown(macio, 1);
+		else if (macio->type == macio_intrepid)
+			intrepid_shutdown(macio, 1);
+		else if (macio->type == macio_keylargo)
+			keylargo_shutdown(macio, 1);
+	}
 
 	/*
-	 * Put the host bridge to sleep
+	 * Save host bridge state and put to sleep
 	 */
 
 	save_unin_clock_ctl = UN_IN(UNI_N_CLOCK_CNTL);
-	/* Note: do not switch GMAC off, driver does it when necessary, WOL must keep it
-	 * enabled !
+
+	if (!turnoff)
+		return 0;
+
+	/* Note: do not switch GMAC off, driver does it when necessary,
+	 * WOL must keep it  enabled !
 	 */
 	UN_OUT(UNI_N_CLOCK_CNTL, save_unin_clock_ctl &
-	       ~(/*UNI_N_CLOCK_CNTL_GMAC|*/UNI_N_CLOCK_CNTL_FW/*|UNI_N_CLOCK_CNTL_PCI*/));
+	       ~(UNI_N_CLOCK_CNTL_FW));
 	udelay(100);
 	UN_OUT(UNI_N_HWINIT_STATE, UNI_N_HWINIT_STATE_SLEEPING);
 	UN_OUT(UNI_N_POWER_MGT, UNI_N_POWER_MGT_SLEEP);
@@ -1876,7 +1893,9 @@
 		return -EPERM;
 
 	if (value == 1)
-		return core99_sleep();
+		return core99_sleep(1);
+	else if (value == 2)
+		return core99_sleep(0);
 	else if (value == 0)
 		return core99_wake_up();
 	return 0;
Index: linux-work/include/asm-ppc/pmac_feature.h
===================================================================
--- linux-work.orig/include/asm-ppc/pmac_feature.h	2005-05-03 13:51:57.000000000 +1000
+++ linux-work/include/asm-ppc/pmac_feature.h	2005-05-28 10:30:21.000000000 +1000
@@ -245,6 +245,7 @@
  * set the sleep state of the motherboard.
  *
  * Pass -1 as value to query for sleep capability
+ * Pass 2 to save state & not sleep
  * Pass 1 to set IOs to sleep
  * Pass 0 to set IOs to wake
  */
Index: linux-work/include/asm-ppc/irq.h
===================================================================
--- linux-work.orig/include/asm-ppc/irq.h	2005-05-02 10:49:57.000000000 +1000
+++ linux-work/include/asm-ppc/irq.h	2005-05-28 10:30:21.000000000 +1000
@@ -391,6 +391,7 @@
 extern unsigned long ppc_cached_irq_mask[NR_MASK_WORDS];
 extern unsigned long ppc_lost_interrupts[NR_MASK_WORDS];
 extern atomic_t ppc_n_lost_interrupts;
+extern int ppc_force_interrupt;
 
 struct irqaction;
 struct pt_regs;
Index: linux-work/drivers/ide/ide-io.c
===================================================================
--- linux-work.orig/drivers/ide/ide-io.c	2005-05-02 10:48:09.000000000 +1000
+++ linux-work/drivers/ide/ide-io.c	2005-05-28 10:30:21.000000000 +1000
@@ -150,7 +150,7 @@
 
 	switch (rq->pm->pm_step) {
 	case ide_pm_flush_cache:	/* Suspend step 1 (flush cache) complete */
-		if (rq->pm->pm_state == 4)
+		if (rq->pm->pm_state == PM_SUSPEND_DISK)
 			rq->pm->pm_step = ide_pm_state_completed;
 		else
 			rq->pm->pm_step = idedisk_pm_standby;
Index: linux-work/drivers/video/aty/aty128fb.c
===================================================================
--- linux-work.orig/drivers/video/aty/aty128fb.c	2005-05-02 10:48:53.000000000 +1000
+++ linux-work/drivers/video/aty/aty128fb.c	2005-05-28 10:30:21.000000000 +1000
@@ -2337,21 +2337,15 @@
 	 * can properly take care of D3 ? Also, with swsusp, we
 	 * know we'll be rebooted, ...
 	 */
-#ifdef CONFIG_PPC_PMAC
-	/* HACK ALERT ! Once I find a proper way to say to each driver
-	 * individually what will happen with it's PCI slot, I'll change
-	 * that. On laptops, the AGP slot is just unclocked, so D2 is
-	 * expected, while on desktops, the card is powered off
-	 */
-	if (state >= 3)
-		state = 2;
-#endif /* CONFIG_PPC_PMAC */
 	 
-	if (state != 2 || state == pdev->dev.power.power_state)
+	if (pdev->dev.power.power_state)
 		return 0;
 
 	printk(KERN_DEBUG "aty128fb: suspending...\n");
 	
+	if (state == PM_SUSPEND_DISK)
+		goto skip;
+
 	acquire_console_sem();
 
 	fb_set_suspend(info, 1);
@@ -2381,12 +2375,11 @@
 	 * used dummy fb ops, 2.5 need proper support for this at the
 	 * fbdev level
 	 */
-	if (state == 2)
-		aty128_set_suspend(par, 1);
+	aty128_set_suspend(par, 1);
 
 	release_console_sem();
-
-	pdev->dev.power.power_state = state;
+ skip:
+	pdev->dev.power.power_state = 1;
 
 	return 0;
 }
@@ -2400,8 +2393,7 @@
 		return 0;
 
 	/* Wakeup chip */
-	if (pdev->dev.power.power_state == 2)
-		aty128_set_suspend(par, 0);
+	aty128_set_suspend(par, 0);
 	par->asleep = 0;
 
 	/* Restore display & engine */
Index: linux-work/drivers/char/agp/uninorth-agp.c
===================================================================
--- linux-work.orig/drivers/char/agp/uninorth-agp.c	2005-05-02 10:48:09.000000000 +1000
+++ linux-work/drivers/char/agp/uninorth-agp.c	2005-05-28 11:37:38.000000000 +1000
@@ -347,6 +347,8 @@
 	struct agp_bridge_data *bridge;
 	u32 command;
 
+	uninorth_configure();
+
 	bridge = agp_find_bridge(pdev);
 	if (bridge == NULL)
 		return -ENODEV;
Index: linux-work/drivers/video/aty/radeon_base.c
===================================================================
--- linux-work.orig/drivers/video/aty/radeon_base.c	2005-05-28 11:25:03.000000000 +1000
+++ linux-work/drivers/video/aty/radeon_base.c	2005-05-28 11:31:14.000000000 +1000
@@ -2036,7 +2036,7 @@
  */
 #ifdef CONFIG_PPC_OF
 #undef SET_MC_FB_FROM_APERTURE
-static void fixup_memory_mappings(struct radeonfb_info *rinfo)
+void radeon_fixup_memory_mappings(struct radeonfb_info *rinfo)
 {
 	u32 save_crtc_gen_cntl, save_crtc2_gen_cntl = 0;
 	u32 save_crtc_ext_cntl;
@@ -2360,7 +2360,7 @@
 	 * to cause lockups when enabling the engine. We reconfigure
 	 * the card internal memory mappings properly
 	 */
-	fixup_memory_mappings(rinfo);
+	radeon_fixup_memory_mappings(rinfo);
 #endif /* CONFIG_PPC_OF */
 
 	/* Get VRAM size and type */
Index: linux-work/drivers/video/aty/radeon_pm.c
===================================================================
--- linux-work.orig/drivers/video/aty/radeon_pm.c	2005-05-28 11:25:03.000000000 +1000
+++ linux-work/drivers/video/aty/radeon_pm.c	2005-05-28 11:26:41.000000000 +1000
@@ -2659,8 +2659,10 @@
 			radeon_set_suspend(rinfo, 0);
 
 		rinfo->asleep = 0;
-	} else
+	} else {
+		radeon_fixup_memory_mappings(rinfo);
 		radeon_engine_idle();
+	}
 
 	/* Restore display & engine */
 	radeon_write_mode (rinfo, &rinfo->state, 1);
Index: linux-work/drivers/video/aty/radeonfb.h
===================================================================
--- linux-work.orig/drivers/video/aty/radeonfb.h	2005-05-02 10:48:53.000000000 +1000
+++ linux-work/drivers/video/aty/radeonfb.h	2005-05-28 11:25:54.000000000 +1000
@@ -618,6 +618,7 @@
 extern void radeonfb_engine_reset(struct radeonfb_info *rinfo);
 
 /* Other functions */
+extern void radeon_fixup_memory_mappings(struct radeonfb_info *rinfo);
 extern int radeon_screen_blank(struct radeonfb_info *rinfo, int blank, int mode_switch);
 extern void radeon_write_mode (struct radeonfb_info *rinfo, struct radeon_regs *mode,
 			       int reg_only);






More information about the Linuxppc-dev mailing list