ppc32: PowerMac PM rework
Subsystems (8)
PATCH 1/1 ppc32: PowerMac PM rework
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.
arch/ppc/platforms/Makefile +3 -2
@@ -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
arch/ppc/platforms/pmac_pm.c new file +802 -0
802 lines not on this page · raw message
arch/ppc/platforms/pmac_setup.c +1 -63
76 lines not on this page · raw message
drivers/base/power/suspend.c +12 -1
@@ -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; }
drivers/macintosh/via-pmu.c +41 -667
986 lines not on this page · raw message
include/asm-ppc/machdep.h +6 -0
@@ -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;
include/asm-ppc/suspend.h +32 -0
@@ -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 */
include/linux/pm.h +30 -1
@@ -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 *);
include/linux/pmu.h +3 -0
@@ -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 );
kernel/power/main.c +34 -4
@@ -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 (); }
arch/ppc/platforms/pmac_pic.c +4 -7
@@ -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
arch/ppc/syslib/open_pic.c +13 -19
@@ -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
include/asm-ppc/open_pic.h +3 -0
@@ -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
arch/ppc/kernel/time.c +5 -1
@@ -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 ();
arch/ppc/platforms/pmac_cpufreq.c +4 -1
@@ -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);
arch/ppc/platforms/pmac_feature.c +65 -46
167 lines not on this page · raw message
include/asm-ppc/pmac_feature.h +1 -0
@@ -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 */
include/asm-ppc/irq.h +1 -0
@@ -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 ;
drivers/ide/ide-io.c +1 -1
@@ -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;
drivers/video/aty/aty128fb.c +8 -16
@@ -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 */
drivers/char/agp/uninorth-agp.c +2 -0
@@ -347,6 +347,8 @@struct agp_bridge_data *bridge;u32 command; +uninorth_configure (); + bridge =agp_find_bridge (pdev);if (bridge ==NULL )return -ENODEV ;
drivers/video/aty/radeon_base.c +2 -2
@@ -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 */
drivers/video/aty/radeon_pm.c +3 -1
@@ -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 );
drivers/video/aty/radeonfb.h +1 -0
@@ -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);
Quoted 1 line · Benjamin Herrenschmidt
Please test and report any issue.
With this patch my iBook G3 no longer wakes up by opening the lid. I have to touch the keyboard to wake it up.
Andreas.
Signature · 4 lines
Andreas Schwab, SuSE Labs, [email protected] SuSE Linux Products GmbH, Maxfeldstraße 5, 90409 Nürnberg, Germany Key fingerprint = 58CA 54C7 6D53 942B 1756 01D3 44D5 214B 8276 4ED5 "And now for something completely different."
Quoted 6 lines · Andreas Schwab
Quoted 1 line · Benjamin Herrenschmidt
Please test and report any issue.
With this patch my iBook G3 no longer wakes up by opening the lid. I have to touch the keyboard to wake it up.
Yup, that's a minor issue, the lid wakeup option lost it's default value :) Will be fixed in the next version of the patch.
Ben.