* [RFC 0/6] suspend on G5
@ 2007-03-21 10:40 Johannes Berg
2007-03-21 10:40 ` [RFC 1/6] powermac: support G5 CPU hotplug Johannes Berg
` (5 more replies)
0 siblings, 6 replies; 7+ messages in thread
From: Johannes Berg @ 2007-03-21 10:40 UTC (permalink / raw)
To: linuxppc-dev
Hi,
This is a repost of my suspend for G5 patches. It's RFC instead of PATCH
because it relies on some patches that Rafael Wysocki did to remove the
pageflags that are used for suspend, so it can't be applied as-is without
having those patches too. They can be found with the patch titles
* swsusp: Use inline functions for changing page flags
* swsusp: Do not use page flags
* mm: Remove unused page flags
In addition to that patch, you'll need my patch
* swsusp: introduce register_nosave_region_late
which I posted to linux-pm in one of the
"swsusp: Do not use page flags (was: Re: Remove page flags for software suspend)"
threads.
All these patches should also be somewhere on
http://johannes.sipsolutions.net/patches/, the first three named
rafael{1,2,3}.patch.
johannes
^ permalink raw reply [flat|nested] 7+ messages in thread
* [RFC 1/6] powermac: support G5 CPU hotplug
2007-03-21 10:40 [RFC 0/6] suspend on G5 Johannes Berg
@ 2007-03-21 10:40 ` Johannes Berg
2007-03-21 10:40 ` [RFC 2/6] powerpc: MPIC sys_device & suspend/resume Johannes Berg
` (4 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Johannes Berg @ 2007-03-21 10:40 UTC (permalink / raw)
To: linuxppc-dev
This patch allows "hotplugging" of CPUs on G5 machines. CPUs that are
disabled are put into an idle loop with the decrementer frequency set
to minimum. To wake them up again we kick them just like when bringing
them up. To stop those CPUs from messing with any global state we stop
them from entering the timer interrupt.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
arch/powerpc/kernel/idle_power4.S | 14 +++++++++---
arch/powerpc/platforms/powermac/setup.c | 35 +++++++++++++++++++++++++++++++-
arch/powerpc/platforms/powermac/smp.c | 12 +++++++++-
include/asm-powerpc/machdep.h | 2 +
4 files changed, 56 insertions(+), 7 deletions(-)
--- linux-2.6.orig/arch/powerpc/platforms/powermac/smp.c 2007-03-21 11:18:47.542243895 +0100
+++ linux-2.6/arch/powerpc/platforms/powermac/smp.c 2007-03-21 11:23:27.332243895 +0100
@@ -897,7 +897,7 @@ void smp_core99_cpu_die(unsigned int cpu
cpu_dead[cpu] = 0;
}
-#endif
+#endif /* CONFIG_HOTPLUG_CPU && CONFIG_PP32 */
/* Core99 Macs (dual G4s and G5s) */
struct smp_ops_t core99_smp_ops = {
@@ -907,8 +907,16 @@ struct smp_ops_t core99_smp_ops = {
.setup_cpu = smp_core99_setup_cpu,
.give_timebase = smp_core99_give_timebase,
.take_timebase = smp_core99_take_timebase,
-#if defined(CONFIG_HOTPLUG_CPU) && defined(CONFIG_PPC32)
+#if defined(CONFIG_HOTPLUG_CPU)
+# if defined(CONFIG_PPC32)
.cpu_disable = smp_core99_cpu_disable,
.cpu_die = smp_core99_cpu_die,
+# endif
+# if defined(CONFIG_PPC64)
+ .cpu_disable = generic_cpu_disable,
+ .cpu_die = generic_cpu_die,
+ /* intentionally do *NOT* assign cpu_enable,
+ * the generic code will use kick_cpu then! */
+# endif
#endif
};
--- linux-2.6.orig/arch/powerpc/platforms/powermac/setup.c 2007-03-21 11:18:47.612243895 +0100
+++ linux-2.6/arch/powerpc/platforms/powermac/setup.c 2007-03-21 11:28:28.542243895 +0100
@@ -425,6 +425,9 @@ static int initializing = 1;
static int pmac_late_init(void)
{
initializing = 0;
+ /* this is udbg (which is __init) and we can later use it during
+ * cpu hotplug (in smp_core99_kick_cpu) */
+ ppc_md.progress = NULL;
return 0;
}
@@ -651,6 +654,36 @@ static int pmac_pci_probe_mode(struct pc
return PCI_PROBE_NORMAL;
return PCI_PROBE_DEVTREE;
}
+
+#ifdef CONFIG_HOTPLUG_CPU
+/* access per cpu vars from generic smp.c */
+DECLARE_PER_CPU(int, cpu_state);
+
+static void pmac_cpu_die(void)
+{
+ /* turn off as much as possible, we'll be
+ * kicked out as this will only be invoked
+ * on core99 platforms for now ... */
+
+ printk(KERN_INFO "CPU#%d offline\n", smp_processor_id());
+ __get_cpu_var(cpu_state) = CPU_DEAD;
+ smp_wmb();
+
+ /* during the path that leads here preemption is disabled,
+ * reenable it now so that when coming up preempt count is
+ * zero correctly */
+ preempt_enable();
+
+ while (1) {
+ /* let's not take timer interrupts too often ... */
+ set_dec(0x7fffffff);
+ printk("CPU %d dead\n", smp_processor_id());
+
+ power4_idle_irqs_softdisabled();
+ }
+}
+#endif
+
#endif
define_machine(powermac) {
@@ -689,6 +722,6 @@ define_machine(powermac) {
.phys_mem_access_prot = pci_phys_mem_access_prot,
#endif
#if defined(CONFIG_HOTPLUG_CPU) && defined(CONFIG_PPC64)
- .cpu_die = generic_mach_cpu_die,
+ .cpu_die = pmac_cpu_die,
#endif
};
--- linux-2.6.orig/arch/powerpc/kernel/idle_power4.S 2007-03-21 11:18:47.662243895 +0100
+++ linux-2.6/arch/powerpc/kernel/idle_power4.S 2007-03-21 11:23:27.342243895 +0100
@@ -19,7 +19,12 @@
.text
+_GLOBAL(power4_idle_irqs_softdisabled)
+ li r6,0
+ b 0f
_GLOBAL(power4_idle)
+ li r6,1
+0:
BEGIN_FTR_SECTION
blr
END_FTR_SECTION_IFCLR(CPU_FTR_CAN_NAP)
@@ -35,8 +40,8 @@ END_FTR_SECTION_IFCLR(CPU_FTR_CAN_NAP)
rotldi r0,r0,16
mtmsrd r0,1 /* hard-disable interrupts */
li r0,1
- stb r0,PACASOFTIRQEN(r13) /* we'll hard-enable shortly */
- stb r0,PACAHARDIRQEN(r13)
+ stb r0,PACAHARDIRQEN(r13) /* we'll hard-enable shortly */
+ stb r6,PACASOFTIRQEN(r13) /* set softirqs enabled bit */
BEGIN_FTR_SECTION
DSSALL
sync
@@ -51,5 +56,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
isync
mtmsrd r7
isync
- b 1b
-
+ cmpdi 0,r6,0
+ bne+ 1b /* return for softirq-disabled case */
+ blr
--- linux-2.6.orig/include/asm-powerpc/machdep.h 2007-03-21 11:18:47.682243895 +0100
+++ linux-2.6/include/asm-powerpc/machdep.h 2007-03-21 11:27:55.412243895 +0100
@@ -252,6 +252,8 @@ struct machdep_calls {
extern void power4_idle(void);
extern void ppc6xx_idle(void);
+/* this one is for CPU hotplug (e.g. powermac) */
+extern void power4_idle_irqs_softdisabled(void);
/*
* ppc_md contains a copy of the machine description structure for the
--
^ permalink raw reply [flat|nested] 7+ messages in thread
* [RFC 2/6] powerpc: MPIC sys_device & suspend/resume
2007-03-21 10:40 [RFC 0/6] suspend on G5 Johannes Berg
2007-03-21 10:40 ` [RFC 1/6] powermac: support G5 CPU hotplug Johannes Berg
@ 2007-03-21 10:40 ` Johannes Berg
2007-03-21 10:40 ` [RFC 3/6] powerpc: dart iommu suspend Johannes Berg
` (3 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Johannes Berg @ 2007-03-21 10:40 UTC (permalink / raw)
To: linuxppc-dev
This adds mpic to the system devices and implements suspend
and resume for them. This is necessary to get interrupts for
modules back to where they were before a suspend to disk.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
Without this patch, i2sbus (built as a module) for example
doesn't work properly across a suspend-to-disk/resume cycle,
with this patch it works fine.
I'm not entirely sure if there should be some wait logic
after I restore the MPIC registers, it works as-is for me.
Over the previous version of this patch this changes that
it also restores the HT interrupts if necessary, making my
quad G5 actually work.
---
arch/powerpc/sysdev/mpic.c | 96 ++++++++++++++++++++++++++++++++++++++++++++-
include/asm-powerpc/mpic.h | 15 +++++++
2 files changed, 110 insertions(+), 1 deletion(-)
--- linux-2.6-git.orig/arch/powerpc/sysdev/mpic.c 2007-03-21 09:22:31.755847391 +0100
+++ linux-2.6-git/arch/powerpc/sysdev/mpic.c 2007-03-21 09:23:03.129847391 +0100
@@ -354,6 +354,12 @@ static void mpic_startup_ht_interrupt(st
tmp |= 0x22;
writel(tmp, fixup->base + 4);
spin_unlock_irqrestore(&mpic->fixup_lock, flags);
+
+#ifdef CONFIG_PM
+ /* use the lowest bit inverted to the actual HW,
+ * set if this fixup was enabled, clear otherwise */
+ mpic->save_data[source].fixup_data = tmp | 1;
+#endif
}
static void mpic_shutdown_ht_interrupt(struct mpic *mpic, unsigned int source,
@@ -375,6 +381,12 @@ static void mpic_shutdown_ht_interrupt(s
tmp |= 1;
writel(tmp, fixup->base + 4);
spin_unlock_irqrestore(&mpic->fixup_lock, flags);
+
+#ifdef CONFIG_PM
+ /* use the lowest bit inverted to the actual HW,
+ * set if this fixup was enabled, clear otherwise */
+ mpic->save_data[source].fixup_data = tmp & ~1;
+#endif
}
static void __init mpic_scan_ht_pic(struct mpic *mpic, u8 __iomem *devbase,
@@ -1143,7 +1155,7 @@ void __init mpic_init(struct mpic *mpic)
/* Do the HT PIC fixups on U3 broken mpic */
DBG("MPIC flags: %x\n", mpic->flags);
if ((mpic->flags & MPIC_BROKEN_U3) && (mpic->flags & MPIC_PRIMARY))
- mpic_scan_ht_pics(mpic);
+ mpic_scan_ht_pics(mpic);
for (i = 0; i < mpic->num_sources; i++) {
/* start with vector = source number, and masked */
@@ -1167,6 +1179,12 @@ void __init mpic_init(struct mpic *mpic)
/* Set current processor priority to 0 */
mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), 0);
+
+#ifdef CONFIG_PM
+ /* allocate memory to save mpic state */
+ mpic->save_data = alloc_bootmem(mpic->num_sources * sizeof(struct mpic_irq_save));
+ BUG_ON(mpic->save_data == NULL);
+#endif
}
void __init mpic_set_clk_ratio(struct mpic *mpic, u32 clock_ratio)
@@ -1417,3 +1435,79 @@ void __devinit smp_mpic_setup_cpu(int cp
mpic_setup_this_cpu();
}
#endif /* CONFIG_SMP */
+
+#ifdef CONFIG_PM
+static int mpic_suspend(struct sys_device *dev, pm_message_t state)
+{
+ struct mpic *mpic = container_of(dev, struct mpic, sysdev);
+ int i;
+
+ for (i = 0; i < mpic->num_sources; i++) {
+ mpic->save_data[i].vecprio =
+ mpic_irq_read(i, MPIC_INFO(IRQ_VECTOR_PRI));
+ mpic->save_data[i].dest =
+ mpic_irq_read(i, MPIC_INFO(IRQ_DESTINATION));
+ }
+
+ return 0;
+}
+
+static int mpic_resume(struct sys_device *dev)
+{
+ struct mpic *mpic = container_of(dev, struct mpic, sysdev);
+ int i;
+
+ for (i = 0; i < mpic->num_sources; i++) {
+ mpic_irq_write(i, MPIC_INFO(IRQ_VECTOR_PRI),
+ mpic->save_data[i].vecprio);
+ mpic_irq_write(i, MPIC_INFO(IRQ_DESTINATION),
+ mpic->save_data[i].dest);
+
+#ifdef CONFIG_MPIC_BROKEN_U3
+ {
+ struct mpic_irq_fixup *fixup = &mpic->fixups[i];
+
+ if (fixup->base) {
+ /* we use the lowest bit in an inverted meaning */
+ if ((mpic->save_data[i].fixup_data & 1) == 0)
+ continue;
+
+ /* Enable and configure */
+ writeb(0x10 + 2 * fixup->index, fixup->base + 2);
+
+ writel(mpic->save_data[i].fixup_data & ~1,
+ fixup->base + 4);
+ }
+ }
+#endif
+ } /* end for loop */
+
+ return 0;
+}
+#endif
+
+static struct sysdev_class mpic_sysclass = {
+#ifdef CONFIG_PM
+ .resume = mpic_resume,
+ .suspend = mpic_suspend,
+#endif
+ set_kset_name("mpic"),
+};
+
+static int mpic_init_sys(void)
+{
+ struct mpic *mpic = mpics;
+ int error, id = 0;
+
+ error = sysdev_class_register(&mpic_sysclass);
+
+ while (mpic && !error) {
+ mpic->sysdev.cls = &mpic_sysclass;
+ mpic->sysdev.id = id++;
+ error = sysdev_register(&mpic->sysdev);
+ mpic = mpic->next;
+ }
+ return error;
+}
+
+device_initcall(mpic_init_sys);
--- linux-2.6-git.orig/include/asm-powerpc/mpic.h 2007-03-21 09:22:31.795847391 +0100
+++ linux-2.6-git/include/asm-powerpc/mpic.h 2007-03-21 09:23:03.131847391 +0100
@@ -3,6 +3,7 @@
#ifdef __KERNEL__
#include <linux/irq.h>
+#include <linux/sysdev.h>
#include <asm/dcr.h>
/*
@@ -228,6 +229,14 @@ struct mpic_reg_bank {
#endif /* CONFIG_PPC_DCR */
};
+struct mpic_irq_save {
+ u32 vecprio,
+ dest;
+#ifdef CONFIG_MPIC_BROKEN_U3
+ u32 fixup_data;
+#endif
+};
+
/* The instance data of a given MPIC */
struct mpic
{
@@ -294,6 +303,12 @@ struct mpic
/* link */
struct mpic *next;
+
+ struct sys_device sysdev;
+
+#ifdef CONFIG_PM
+ struct mpic_irq_save *save_data;
+#endif
};
/*
--
^ permalink raw reply [flat|nested] 7+ messages in thread
* [RFC 3/6] powerpc: dart iommu suspend
2007-03-21 10:40 [RFC 0/6] suspend on G5 Johannes Berg
2007-03-21 10:40 ` [RFC 1/6] powermac: support G5 CPU hotplug Johannes Berg
2007-03-21 10:40 ` [RFC 2/6] powerpc: MPIC sys_device & suspend/resume Johannes Berg
@ 2007-03-21 10:40 ` Johannes Berg
2007-03-21 10:40 ` [RFC 4/6] powerpc: mark pages that dont exist as nosave Johannes Berg
` (2 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Johannes Berg @ 2007-03-21 10:40 UTC (permalink / raw)
To: linuxppc-dev
This implements save and restore hooks for IOMMUs and implements
it the dart iommu.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
arch/powerpc/sysdev/dart_iommu.c | 46 +++++++++++++++++++++++++++++++++++++++
include/asm-powerpc/iommu.h | 14 +++++++++++
include/asm-powerpc/machdep.h | 5 ++++
3 files changed, 65 insertions(+)
--- linux-2.6-git.orig/arch/powerpc/sysdev/dart_iommu.c 2007-03-21 09:22:31.555847391 +0100
+++ linux-2.6-git/arch/powerpc/sysdev/dart_iommu.c 2007-03-21 09:23:03.801847391 +0100
@@ -36,6 +36,7 @@
#include <linux/pci.h>
#include <linux/dma-mapping.h>
#include <linux/vmalloc.h>
+#include <linux/suspend.h>
#include <asm/io.h>
#include <asm/prom.h>
#include <asm/iommu.h>
@@ -54,6 +55,9 @@ static unsigned long dart_tablesize;
/* Virtual base address of the DART table */
static u32 *dart_vbase;
+#ifdef CONFIG_PM
+static u32 *dart_copy;
+#endif
/* Mapped base address for the dart */
static unsigned int __iomem *dart;
@@ -346,6 +350,48 @@ void iommu_init_early_dart(void)
pci_dma_ops = &dma_direct_ops;
}
+#ifdef CONFIG_PM
+static void iommu_dart_save(void)
+{
+ memcpy(dart_copy, dart_vbase, 2*1024*1024);
+}
+
+static void iommu_dart_restore(void)
+{
+ memcpy(dart_vbase, dart_copy, 2*1024*1024);
+ dart_tlb_invalidate_all();
+}
+
+static int __init iommu_init_late_dart(void)
+{
+ unsigned long tbasepfn;
+ struct page *p;
+
+ /* if no dart table exists then we won't need to save it
+ * and the area has also not been reserved */
+ if (!dart_tablebase)
+ return 0;
+
+ tbasepfn = __pa(dart_tablebase) >> PAGE_SHIFT;
+ register_nosave_region_late(tbasepfn,
+ tbasepfn + ((1<<24) >> PAGE_SHIFT));
+
+ /* For suspend we need to copy the dart contents because
+ * it is not part of the regular mapping (see above) and
+ * thus not saved automatically. The memory for this copy
+ * must be allocated early because we need 2 MB. */
+ p = alloc_pages(GFP_KERNEL, 21 - PAGE_SHIFT);
+ BUG_ON(!p);
+ dart_copy = page_address(p);
+
+ ppc_md.iommu_save = iommu_dart_save;
+ ppc_md.iommu_restore = iommu_dart_restore;
+
+ return 0;
+}
+
+late_initcall(iommu_init_late_dart);
+#endif
void __init alloc_dart_table(void)
{
--- linux-2.6-git.orig/include/asm-powerpc/iommu.h 2007-03-21 09:22:31.584847391 +0100
+++ linux-2.6-git/include/asm-powerpc/iommu.h 2007-03-21 09:23:03.803847391 +0100
@@ -26,6 +26,7 @@
#include <linux/spinlock.h>
#include <linux/device.h>
#include <linux/dma-mapping.h>
+#include <asm/machdep.h>
#include <asm/types.h>
#include <asm/bitops.h>
@@ -109,6 +110,19 @@ static inline void pci_iommu_init(void)
#endif
extern void alloc_dart_table(void);
+#if defined(CONFIG_PPC64) && defined(CONFIG_PM)
+static inline void iommu_save(void)
+{
+ if (ppc_md.iommu_save)
+ ppc_md.iommu_save();
+}
+
+static inline void iommu_restore(void)
+{
+ if (ppc_md.iommu_restore)
+ ppc_md.iommu_restore();
+}
+#endif
#endif /* __KERNEL__ */
#endif /* _ASM_IOMMU_H */
--- linux-2.6-git.orig/include/asm-powerpc/machdep.h 2007-03-21 09:23:02.283847391 +0100
+++ linux-2.6-git/include/asm-powerpc/machdep.h 2007-03-21 09:23:03.805847391 +0100
@@ -91,6 +91,11 @@ struct machdep_calls {
void __iomem * (*ioremap)(phys_addr_t addr, unsigned long size,
unsigned long flags);
void (*iounmap)(volatile void __iomem *token);
+
+#ifdef CONFIG_PM
+ void (*iommu_save)(void);
+ void (*iommu_restore)(void);
+#endif
#endif /* CONFIG_PPC64 */
int (*probe)(void);
--
^ permalink raw reply [flat|nested] 7+ messages in thread
* [RFC 4/6] powerpc: mark pages that dont exist as nosave
2007-03-21 10:40 [RFC 0/6] suspend on G5 Johannes Berg
` (2 preceding siblings ...)
2007-03-21 10:40 ` [RFC 3/6] powerpc: dart iommu suspend Johannes Berg
@ 2007-03-21 10:40 ` Johannes Berg
2007-03-21 10:40 ` [RFC 5/6] powermac: fix G5-cpufreq for cpu on/offline Johannes Berg
2007-03-21 10:40 ` [RFC 6/6] powermac: suspend to disk on G5 Johannes Berg
5 siblings, 0 replies; 7+ messages in thread
From: Johannes Berg @ 2007-03-21 10:40 UTC (permalink / raw)
To: linuxppc-dev
On some powerpc architectures (notably 64-bit powermac) there is a memory
hole, for example on powermacs between 2G and 4G. Since we use the flat
memory model regardless, these pages must be marked as nosave (for suspend
to disk.)
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
Tested on powerbook and G5 powermac.
---
arch/powerpc/mm/mem.c | 25 +++++++++++++++++++++++++
1 file changed, 25 insertions(+)
--- linux-2.6-git.orig/arch/powerpc/mm/mem.c 2007-03-21 11:05:32.853447142 +0100
+++ linux-2.6-git/arch/powerpc/mm/mem.c 2007-03-21 11:06:08.338447142 +0100
@@ -31,6 +31,7 @@
#include <linux/highmem.h>
#include <linux/initrd.h>
#include <linux/pagemap.h>
+#include <linux/suspend.h>
#include <asm/pgalloc.h>
#include <asm/prom.h>
@@ -280,6 +281,28 @@ void __init do_init_bootmem(void)
init_bootmem_done = 1;
}
+/* mark pages that don't exist as nosave */
+static int __init mark_nonram_nosave(void)
+{
+ unsigned long lmb_next_region_start_pfn,
+ lmb_region_max_pfn;
+ int i;
+
+ for (i = 0; i < lmb.memory.cnt - 1; i++) {
+ lmb_region_max_pfn =
+ (lmb.memory.region[i].base >> PAGE_SHIFT) +
+ (lmb.memory.region[i].size >> PAGE_SHIFT);
+ lmb_next_region_start_pfn =
+ lmb.memory.region[i+1].base >> PAGE_SHIFT;
+
+ if (lmb_region_max_pfn < lmb_next_region_start_pfn)
+ register_nosave_region(lmb_region_max_pfn,
+ lmb_next_region_start_pfn);
+ }
+
+ return 0;
+}
+
/*
* paging_init() sets up the page tables - in fact we've already done this.
*/
@@ -311,6 +334,8 @@ void __init paging_init(void)
max_zone_pfns[ZONE_DMA] = top_of_ram >> PAGE_SHIFT;
#endif
free_area_init_nodes(max_zone_pfns);
+
+ mark_nonram_nosave();
}
#endif /* ! CONFIG_NEED_MULTIPLE_NODES */
--
^ permalink raw reply [flat|nested] 7+ messages in thread
* [RFC 5/6] powermac: fix G5-cpufreq for cpu on/offline
2007-03-21 10:40 [RFC 0/6] suspend on G5 Johannes Berg
` (3 preceding siblings ...)
2007-03-21 10:40 ` [RFC 4/6] powerpc: mark pages that dont exist as nosave Johannes Berg
@ 2007-03-21 10:40 ` Johannes Berg
2007-03-21 10:40 ` [RFC 6/6] powermac: suspend to disk on G5 Johannes Berg
5 siblings, 0 replies; 7+ messages in thread
From: Johannes Berg @ 2007-03-21 10:40 UTC (permalink / raw)
To: linuxppc-dev
The original code here is wrong, it applies "previous" knowledge.
The way the cpufreq core is designed is that the policy for the
secondary CPU that comes online says that it must in fact not
use this policy but use the same as the other CPUs that are
listed, which in fact is CPU#0.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
arch/powerpc/platforms/powermac/cpufreq_64.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
--- linux-2.6-git.orig/arch/powerpc/platforms/powermac/cpufreq_64.c 2007-03-21 09:22:30.845847391 +0100
+++ linux-2.6-git/arch/powerpc/platforms/powermac/cpufreq_64.c 2007-03-21 09:23:06.156847391 +0100
@@ -357,13 +357,13 @@ static unsigned int g5_cpufreq_get_speed
static int g5_cpufreq_cpu_init(struct cpufreq_policy *policy)
{
- if (policy->cpu != 0)
- return -ENODEV;
-
policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
policy->cur = g5_cpu_freqs[g5_query_freq()].frequency;
- policy->cpus = cpu_possible_map;
+ /* secondary CPUs are tied to the primary one by the
+ * cpufreq core if in the secondary policy we tell it that
+ * it actually must be one policy together with all others. */
+ policy->cpus = cpu_online_map;
cpufreq_frequency_table_get_attr(g5_cpu_freqs, policy->cpu);
return cpufreq_frequency_table_cpuinfo(policy,
--
^ permalink raw reply [flat|nested] 7+ messages in thread
* [RFC 6/6] powermac: suspend to disk on G5
2007-03-21 10:40 [RFC 0/6] suspend on G5 Johannes Berg
` (4 preceding siblings ...)
2007-03-21 10:40 ` [RFC 5/6] powermac: fix G5-cpufreq for cpu on/offline Johannes Berg
@ 2007-03-21 10:40 ` Johannes Berg
5 siblings, 0 replies; 7+ messages in thread
From: Johannes Berg @ 2007-03-21 10:40 UTC (permalink / raw)
To: linuxppc-dev
Powermac G5 suspend to disk implementation. The code is platform
agnostic but only tested on powermac, no other 64-bit powerpc
machines.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
WARNING: nvidiafb breaks suspend. I don't know why yet, but if it is
compiled and you try to suspend from X it all just freezes. The nvidiafb
suspend code looks a bit fishy but I shall have to understand first what
it's trying to achieve.
Other than that I'm really happy with this, it's good to finally be able to
hibernate the machine instead of keeping it up or shutting it down.
Tested on my powermac, this time with forced preemption enabled, of course
only together with all the other patches.
---
arch/powerpc/Kconfig | 5
arch/powerpc/kernel/Makefile | 1
arch/powerpc/kernel/asm-offsets.c | 4
arch/powerpc/kernel/idle.c | 5
arch/powerpc/kernel/swsusp.c | 9 +
arch/powerpc/kernel/swsusp_64.c | 24 +++
arch/powerpc/kernel/swsusp_asm64.S | 228 +++++++++++++++++++++++++++++++++++++
include/linux/suspend.h | 2
kernel/power/Kconfig | 4
9 files changed, 276 insertions(+), 6 deletions(-)
--- linux-2.6-git.orig/arch/powerpc/kernel/Makefile 2007-03-21 09:22:46.341847391 +0100
+++ linux-2.6-git/arch/powerpc/kernel/Makefile 2007-03-21 09:23:04.549847391 +0100
@@ -38,6 +38,7 @@ obj-$(CONFIG_6xx) += idle_6xx.o l2cr_6x
obj-$(CONFIG_TAU) += tau_6xx.o
obj-$(CONFIG_SOFTWARE_SUSPEND) += swsusp.o
obj32-$(CONFIG_SOFTWARE_SUSPEND) += swsusp_32.o
+obj64-$(CONFIG_SOFTWARE_SUSPEND) += swsusp_64.o swsusp_asm64.o
obj32-$(CONFIG_MODULES) += module_32.o
ifeq ($(CONFIG_PPC_MERGE),y)
--- linux-2.6-git.orig/kernel/power/Kconfig 2007-03-21 09:22:58.001847391 +0100
+++ linux-2.6-git/kernel/power/Kconfig 2007-03-21 09:23:04.551847391 +0100
@@ -91,7 +91,7 @@ config PM_SYSFS_DEPRECATED
config SOFTWARE_SUSPEND
bool "Software Suspend"
- depends on PM && SWAP && ((X86 && (!SMP || SUSPEND_SMP)) || ((FRV || PPC32) && !SMP))
+ depends on PM && SWAP && (((X86 || PPC64_SWSUSP) && (!SMP || SUSPEND_SMP)) || ((FRV || PPC32) && !SMP))
---help---
Enable the suspend to disk (STD) functionality.
@@ -146,7 +146,7 @@ config PM_STD_PARTITION
config SUSPEND_SMP
bool
- depends on HOTPLUG_CPU && X86 && PM
+ depends on HOTPLUG_CPU && (X86 || PPC64) && PM
default y
config APM_EMULATION
--- linux-2.6-git.orig/include/linux/suspend.h 2007-03-21 09:23:01.569847391 +0100
+++ linux-2.6-git/include/linux/suspend.h 2007-03-21 09:23:04.552847391 +0100
@@ -1,7 +1,7 @@
#ifndef _LINUX_SWSUSP_H
#define _LINUX_SWSUSP_H
-#if defined(CONFIG_X86) || defined(CONFIG_FRV) || defined(CONFIG_PPC32)
+#if defined(CONFIG_X86) || defined(CONFIG_FRV) || defined(CONFIG_PPC32) || defined(CONFIG_PPC64)
#include <asm/suspend.h>
#endif
#include <linux/swap.h>
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6-git/arch/powerpc/kernel/swsusp_64.c 2007-03-21 09:23:04.554847391 +0100
@@ -0,0 +1,24 @@
+/*
+ * PowerPC 64-bit swsusp implementation
+ *
+ * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+ *
+ * GPLv2
+ */
+
+#include <asm/system.h>
+#include <asm/iommu.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+
+void do_after_copyback(void)
+{
+ iommu_restore();
+ touch_softlockup_watchdog();
+ mb();
+}
+
+void _iommu_save(void)
+{
+ iommu_save();
+}
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6-git/arch/powerpc/kernel/swsusp_asm64.S 2007-03-21 09:23:04.558847391 +0100
@@ -0,0 +1,228 @@
+/*
+ * PowerPC 64-bit swsusp implementation
+ *
+ * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+ *
+ * GPLv2
+ */
+
+#include <linux/threads.h>
+#include <asm/processor.h>
+#include <asm/page.h>
+#include <asm/cputable.h>
+#include <asm/thread_info.h>
+#include <asm/ppc_asm.h>
+#include <asm/asm-offsets.h>
+
+/*
+ * Structure for storing CPU registers on the save area.
+ */
+#define SL_r1 0x00 /* stack pointer */
+#define SL_PC 0x08
+#define SL_MSR 0x10
+#define SL_SDR1 0x18
+#define SL_XER 0x20
+#define SL_TB 0x40
+#define SL_r2 0x48
+#define SL_CR 0x50
+#define SL_LR 0x58
+#define SL_r12 0x60
+#define SL_r13 0x68
+#define SL_r14 0x70
+#define SL_r15 0x78
+#define SL_r16 0x80
+#define SL_r17 0x88
+#define SL_r18 0x90
+#define SL_r19 0x98
+#define SL_r20 0xa0
+#define SL_r21 0xa8
+#define SL_r22 0xb0
+#define SL_r23 0xb8
+#define SL_r24 0xc0
+#define SL_r25 0xc8
+#define SL_r26 0xd0
+#define SL_r27 0xd8
+#define SL_r28 0xe0
+#define SL_r29 0xe8
+#define SL_r30 0xf0
+#define SL_r31 0xf8
+#define SL_SIZE SL_r31+8
+
+/* these macros rely on the save area being
+ * pointed to by r11 */
+#define SAVE_SPECIAL(special) \
+ mf##special r0 ;\
+ std r0, SL_##special(r11)
+#define RESTORE_SPECIAL(special) \
+ ld r0, SL_##special(r11) ;\
+ mt##special r0
+#define SAVE_REGISTER(reg) \
+ std reg, SL_##reg(r11)
+#define RESTORE_REGISTER(reg) \
+ ld reg, SL_##reg(r11)
+
+/* space for storing cpu state */
+ .section .data
+ .align 5
+swsusp_save_area:
+ .space SL_SIZE
+
+ .section ".toc","aw"
+swsusp_save_area_ptr:
+ .tc swsusp_save_area[TC],swsusp_save_area
+restore_pblist_ptr:
+ .tc restore_pblist[TC],restore_pblist
+
+ .section .text
+ .align 5
+_GLOBAL(swsusp_arch_suspend)
+ ld r11,swsusp_save_area_ptr@toc(r2)
+ SAVE_SPECIAL(LR)
+ SAVE_REGISTER(r1)
+ SAVE_SPECIAL(CR)
+ SAVE_SPECIAL(TB)
+ SAVE_REGISTER(r2)
+ SAVE_REGISTER(r12)
+ SAVE_REGISTER(r13)
+ SAVE_REGISTER(r14)
+ SAVE_REGISTER(r15)
+ SAVE_REGISTER(r16)
+ SAVE_REGISTER(r17)
+ SAVE_REGISTER(r18)
+ SAVE_REGISTER(r19)
+ SAVE_REGISTER(r20)
+ SAVE_REGISTER(r21)
+ SAVE_REGISTER(r22)
+ SAVE_REGISTER(r23)
+ SAVE_REGISTER(r24)
+ SAVE_REGISTER(r25)
+ SAVE_REGISTER(r26)
+ SAVE_REGISTER(r27)
+ SAVE_REGISTER(r28)
+ SAVE_REGISTER(r29)
+ SAVE_REGISTER(r30)
+ SAVE_REGISTER(r31)
+ SAVE_SPECIAL(MSR)
+ SAVE_SPECIAL(SDR1)
+ SAVE_SPECIAL(XER)
+
+ /* we push the stack up 128 bytes but don't store the
+ * stack pointer on the stack like a real stackframe */
+ addi r1,r1,-128
+
+ bl _iommu_save
+ bl swsusp_save
+
+ /* restore LR */
+ ld r11,swsusp_save_area_ptr@toc(r2)
+ RESTORE_SPECIAL(LR)
+ addi r1,r1,128
+
+ blr
+
+/* Resume code */
+_GLOBAL(swsusp_arch_resume)
+ /* Stop pending alitvec streams and memory accesses */
+BEGIN_FTR_SECTION
+ DSSALL
+END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
+ sync
+
+ ld r12,restore_pblist_ptr@toc(r2)
+ ld r12,0(r12)
+
+ cmpdi r12,0
+ beq- nothing_to_copy
+ li r15,512
+copyloop:
+ ld r13,pbe_address(r12)
+ ld r14,pbe_orig_address(r12)
+
+ mtctr r15
+ li r10,0
+copy_page_loop:
+ ldx r0,r10,r13
+ stdx r0,r10,r14
+ addi r10,r10,8
+ bdnz copy_page_loop
+
+ ld r12,pbe_next(r12)
+ cmpdi r12,0
+ bne+ copyloop
+nothing_to_copy:
+
+ /* flush caches */
+ lis r3, 0x10
+ mtctr r3
+ li r3, 0
+ ori r3, r3, CONFIG_KERNEL_START>>48
+ li r0, 48
+ sld r3, r3, r0
+ li r0, 0
+1:
+ dcbf r0,r3
+ addi r3,r3,0x20
+ bdnz 1b
+
+ sync
+
+ tlbia
+
+ ld r11,swsusp_save_area_ptr@toc(r2)
+
+ RESTORE_SPECIAL(CR)
+
+ /* restore timebase */
+ /* load saved tb */
+ ld r1, SL_TB(r11)
+ /* get upper 32 bits of it */
+ srdi r2, r1, 32
+ /* clear tb lower to avoid wrap */
+ li r0, 0
+ mttbl r0
+ /* set tb upper */
+ mttbu r2
+ /* set tb lower */
+ mttbl r1
+
+ /* restore registers */
+ RESTORE_REGISTER(r1)
+ RESTORE_REGISTER(r2)
+ RESTORE_REGISTER(r12)
+ RESTORE_REGISTER(r13)
+ RESTORE_REGISTER(r14)
+ RESTORE_REGISTER(r15)
+ RESTORE_REGISTER(r16)
+ RESTORE_REGISTER(r17)
+ RESTORE_REGISTER(r18)
+ RESTORE_REGISTER(r19)
+ RESTORE_REGISTER(r20)
+ RESTORE_REGISTER(r21)
+ RESTORE_REGISTER(r22)
+ RESTORE_REGISTER(r23)
+ RESTORE_REGISTER(r24)
+ RESTORE_REGISTER(r25)
+ RESTORE_REGISTER(r26)
+ RESTORE_REGISTER(r27)
+ RESTORE_REGISTER(r28)
+ RESTORE_REGISTER(r29)
+ RESTORE_REGISTER(r30)
+ RESTORE_REGISTER(r31)
+ /* can't use RESTORE_SPECIAL(MSR) */
+ ld r0, SL_MSR(r11)
+ mtmsrd r0, 0
+ RESTORE_SPECIAL(SDR1)
+ RESTORE_SPECIAL(XER)
+
+ sync
+
+ addi r1,r1,-128
+ bl slb_flush_and_rebolt
+ bl do_after_copyback
+ addi r1,r1,128
+
+ ld r11,swsusp_save_area_ptr@toc(r2)
+ RESTORE_SPECIAL(LR)
+
+ li r3, 0
+ blr
--- linux-2.6-git.orig/arch/powerpc/kernel/asm-offsets.c 2007-03-21 09:22:31.207847391 +0100
+++ linux-2.6-git/arch/powerpc/kernel/asm-offsets.c 2007-03-21 09:23:04.560847391 +0100
@@ -21,12 +21,12 @@
#include <linux/types.h>
#include <linux/mman.h>
#include <linux/mm.h>
+#include <linux/suspend.h>
#ifdef CONFIG_PPC64
#include <linux/time.h>
#include <linux/hardirq.h>
#else
#include <linux/ptrace.h>
-#include <linux/suspend.h>
#endif
#include <asm/io.h>
@@ -257,11 +257,11 @@ int main(void)
DEFINE(CPU_SPEC_SETUP, offsetof(struct cpu_spec, cpu_setup));
DEFINE(CPU_SPEC_RESTORE, offsetof(struct cpu_spec, cpu_restore));
-#ifndef CONFIG_PPC64
DEFINE(pbe_address, offsetof(struct pbe, address));
DEFINE(pbe_orig_address, offsetof(struct pbe, orig_address));
DEFINE(pbe_next, offsetof(struct pbe, next));
+#ifndef CONFIG_PPC64
DEFINE(TASK_SIZE, TASK_SIZE);
DEFINE(NUM_USER_SEGMENTS, TASK_SIZE>>28);
#endif /* ! CONFIG_PPC64 */
--- linux-2.6-git.orig/arch/powerpc/kernel/idle.c 2007-03-21 09:22:31.235847391 +0100
+++ linux-2.6-git/arch/powerpc/kernel/idle.c 2007-03-21 09:23:04.561847391 +0100
@@ -33,8 +33,11 @@
#include <asm/smp.h>
#ifdef CONFIG_HOTPLUG_CPU
+/* this is used for software suspend, and that shuts down
+ * CPUs even while the system is still booting... */
#define cpu_should_die() (cpu_is_offline(smp_processor_id()) && \
- system_state == SYSTEM_RUNNING)
+ (system_state == SYSTEM_RUNNING \
+ || system_state == SYSTEM_BOOTING))
#else
#define cpu_should_die() 0
#endif
--- linux-2.6-git.orig/arch/powerpc/kernel/swsusp.c 2007-03-21 09:22:46.343847391 +0100
+++ linux-2.6-git/arch/powerpc/kernel/swsusp.c 2007-03-21 09:23:04.563847391 +0100
@@ -32,6 +32,11 @@ void save_processor_state(void)
#ifdef CONFIG_SPE
enable_kernel_spe();
#endif
+
+#ifdef CONFIG_PPC64
+ hard_irq_disable();
+#endif
+
}
void restore_processor_state(void)
@@ -39,4 +44,8 @@ void restore_processor_state(void)
#ifdef CONFIG_PPC32
set_context(current->active_mm->context.id, current->active_mm->pgd);
#endif
+
+#ifdef CONFIG_PPC64
+ hard_irq_enable();
+#endif
}
--- linux-2.6-git.orig/arch/powerpc/Kconfig 2007-03-21 09:22:50.184847391 +0100
+++ linux-2.6-git/arch/powerpc/Kconfig 2007-03-21 09:23:04.565847391 +0100
@@ -126,6 +126,11 @@ config DEFAULT_UIMAGE
Used to allow a board to specify it wants a uImage built by default
default n
+config PPC64_SWSUSP
+ bool
+ depends on PPC64 && (PPC_PMAC64 || EXPERIMENTAL)
+ default y
+
menu "Processor support"
choice
prompt "Processor Type"
--
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2007-03-21 12:12 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-03-21 10:40 [RFC 0/6] suspend on G5 Johannes Berg
2007-03-21 10:40 ` [RFC 1/6] powermac: support G5 CPU hotplug Johannes Berg
2007-03-21 10:40 ` [RFC 2/6] powerpc: MPIC sys_device & suspend/resume Johannes Berg
2007-03-21 10:40 ` [RFC 3/6] powerpc: dart iommu suspend Johannes Berg
2007-03-21 10:40 ` [RFC 4/6] powerpc: mark pages that dont exist as nosave Johannes Berg
2007-03-21 10:40 ` [RFC 5/6] powermac: fix G5-cpufreq for cpu on/offline Johannes Berg
2007-03-21 10:40 ` [RFC 6/6] powermac: suspend to disk on G5 Johannes Berg
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).