Package: kernel-source-2.6.10 Severity: wishlist Tags: patch
Good day, Guido Guenther maintains some patches against 2.6 that I found very usefull : software suspend : >From debian-ppc : | On Wed, Feb 23, 2005 at 11:54:20AM +1100, Benjamin Herrenschmidt wrote: | > > I also gather that suspend-to-disk is available - | > > http://article.gmane.org/gmane.linux.debian.ports.powerpc/25379 | > | > I don't think suspend to disk is very reliable tho ... | Works here without problems for several days now, patch is at | http://honk.physik.uni-konstanz.de/~agx/linux-ppc/kernel/2.6.11-rc4-agx0.diff | Cheers, | -- Guido Again From debian-ppc on 04 december 2004 : | The patch contains some other small goodies such as a selectable HZ | value (default is 1000, 100 saves some battery) and some alsa and | cpufreq fixes. | Please note that this patch still conflicts with suspend to ram, so you | won't be able to use both. | Cheers, | -- Guido patch is at : http://honk.physik.uni-konstanz.de/~agx/linux-ppc/kernel/ and attached to this bug report. Regards. -- System Information: Debian Release: 3.1 APT prefers unstable APT policy: (500, 'unstable') Architecture: powerpc (ppc) Kernel: Linux 2.6.9-rfb-swsusp Locale: [EMAIL PROTECTED], [EMAIL PROTECTED] (charmap=ISO-8859-15)
diff -u -Naur linux-2.6.10.orig/arch/ppc/Kconfig linux-2.6.10/arch/ppc/Kconfig --- linux-2.6.10.orig/arch/ppc/Kconfig 2004-12-24 22:35:40.000000000 +0100 +++ linux-2.6.10/arch/ppc/Kconfig 2005-01-04 14:21:32.583281000 +0100 @@ -966,6 +966,15 @@ source "drivers/zorro/Kconfig" +source kernel/power/Kconfig + +config PPC_HZ + int "Clock Tick Rate" + default 1000 + help + Select the kernel clock tick rate in interrupts per second. + Slower processors should choose 100; everything else 1000. + endmenu menu "Bus options" diff -u -Naur linux-2.6.10.orig/arch/ppc/kernel/Makefile linux-2.6.10/arch/ppc/kernel/Makefile --- linux-2.6.10.orig/arch/ppc/kernel/Makefile 2004-12-24 22:35:28.000000000 +0100 +++ linux-2.6.10/arch/ppc/kernel/Makefile 2005-01-04 14:21:32.583281000 +0100 @@ -16,6 +16,7 @@ semaphore.o syscalls.o setup.o \ cputable.o ppc_htab.o obj-$(CONFIG_6xx) += l2cr.o cpu_setup_6xx.o +obj-$(CONFIG_SOFTWARE_SUSPEND) += swsusp.o obj-$(CONFIG_POWER4) += cpu_setup_power4.o obj-$(CONFIG_MODULES) += module.o ppc_ksyms.o obj-$(CONFIG_NOT_COHERENT_CACHE) += dma-mapping.o diff -u -Naur linux-2.6.10.orig/arch/ppc/kernel/signal.c linux-2.6.10/arch/ppc/kernel/signal.c --- linux-2.6.10.orig/arch/ppc/kernel/signal.c 2004-12-24 22:35:39.000000000 +0100 +++ linux-2.6.10/arch/ppc/kernel/signal.c 2005-01-04 14:21:32.583281000 +0100 @@ -28,6 +28,7 @@ #include <linux/elf.h> #include <linux/tty.h> #include <linux/binfmts.h> +#include <linux/suspend.h> #include <asm/ucontext.h> #include <asm/uaccess.h> #include <asm/pgtable.h> @@ -614,6 +615,14 @@ unsigned long frame, newsp; int signr, ret; + if (current->flags & PF_FREEZE) { + refrigerator(PF_FREEZE); + signr = 0; + ret = regs->gpr[3]; + if (!signal_pending(current)) + goto no_signal; + } + if (!oldset) oldset = ¤t->blocked; @@ -636,6 +645,7 @@ regs->gpr[3] = EINTR; /* note that the cr0.SO bit is already set */ } else { +no_signal: regs->nip -= 4; /* Back up & retry system call */ regs->result = 0; regs->trap = 0; diff -u -Naur linux-2.6.10.orig/arch/ppc/kernel/swsusp.S linux-2.6.10/arch/ppc/kernel/swsusp.S --- linux-2.6.10.orig/arch/ppc/kernel/swsusp.S 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.10/arch/ppc/kernel/swsusp.S 2005-01-04 14:21:32.583281000 +0100 @@ -0,0 +1,356 @@ +#include <linux/config.h> +#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/offsets.h> + + +/* + * Structure for storing CPU registers on the save area. + */ +#define SL_SP 0 +#define SL_PC 4 +#define SL_MSR 8 +#define SL_SDR1 0xc +#define SL_SPRG0 0x10 /* 4 sprg's */ +#define SL_DBAT0 0x20 +#define SL_IBAT0 0x28 +#define SL_DBAT1 0x30 +#define SL_IBAT1 0x38 +#define SL_DBAT2 0x40 +#define SL_IBAT2 0x48 +#define SL_DBAT3 0x50 +#define SL_IBAT3 0x58 +#define SL_TB 0x60 +#define SL_R2 0x68 +#define SL_CR 0x6c +#define SL_LR 0x70 +#define SL_R12 0x74 /* r12 to r31 */ +#define SL_SIZE (SL_R12 + 80) + + .section .data + .align 5 + +_GLOBAL(swsusp_save_area) + .space SL_SIZE + + + .section .text + .align 5 + +_GLOBAL(swsusp_arch_suspend) + + lis r11,[EMAIL PROTECTED] + ori r11,r11,[EMAIL PROTECTED] + + mflr r0 + stw r0,SL_LR(r11) + mfcr r0 + stw r0,SL_CR(r11) + stw r1,SL_SP(r11) + stw r2,SL_R2(r11) + stmw r12,SL_R12(r11) + + /* Save MSR & SDR1 */ + mfmsr r4 + stw r4,SL_MSR(r11) + mfsdr1 r4 + stw r4,SL_SDR1(r11) + + /* Get a stable timebase and save it */ +1: mftbu r4 + stw r4,SL_TB(r11) + mftb r5 + stw r5,SL_TB+4(r11) + mftbu r3 + cmpw r3,r4 + bne 1b + + /* Save SPRGs */ + mfsprg r4,0 + stw r4,SL_SPRG0(r11) + mfsprg r4,1 + stw r4,SL_SPRG0+4(r11) + mfsprg r4,2 + stw r4,SL_SPRG0+8(r11) + mfsprg r4,3 + stw r4,SL_SPRG0+12(r11) + + /* Save BATs */ + mfdbatu r4,0 + stw r4,SL_DBAT0(r11) + mfdbatl r4,0 + stw r4,SL_DBAT0+4(r11) + mfdbatu r4,1 + stw r4,SL_DBAT1(r11) + mfdbatl r4,1 + stw r4,SL_DBAT1+4(r11) + mfdbatu r4,2 + stw r4,SL_DBAT2(r11) + mfdbatl r4,2 + stw r4,SL_DBAT2+4(r11) + mfdbatu r4,3 + stw r4,SL_DBAT3(r11) + mfdbatl r4,3 + stw r4,SL_DBAT3+4(r11) + mfibatu r4,0 + stw r4,SL_IBAT0(r11) + mfibatl r4,0 + stw r4,SL_IBAT0+4(r11) + mfibatu r4,1 + stw r4,SL_IBAT1(r11) + mfibatl r4,1 + stw r4,SL_IBAT1+4(r11) + mfibatu r4,2 + stw r4,SL_IBAT2(r11) + mfibatl r4,2 + stw r4,SL_IBAT2+4(r11) + mfibatu r4,3 + stw r4,SL_IBAT3(r11) + mfibatl r4,3 + stw r4,SL_IBAT3+4(r11) + +#if 0 + /* Backup various CPU config stuffs */ + bl __save_cpu_setup +#endif + /* Call the low level suspend stuff (we should probably have made + * a stackframe... + */ + bl swsusp_save + + /* Restore LR from the save area */ + lis r11,[EMAIL PROTECTED] + ori r11,r11,[EMAIL PROTECTED] + lwz r0,SL_LR(r11) + mtlr r0 + + 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 + + /* Disable MSR:DR to make sure we don't take a TLB or + * hash miss during the copy, as our hash table will + * for a while be unuseable. For .text, we assume we are + * covered by a BAT. This works only for non-G5 at this + * point. G5 will need a better approach, possibly using + * a small temporary hash table filled with large mappings, + * disabling the MMU completely isn't a good option for + * performance reasons. + * (Note that 750's may have the same performance issue as + * the G5 in this case, we should investigate using moving + * BATs for these CPUs) + */ + mfmsr r0 + sync + rlwinm r0,r0,0,28,26 /* clear MSR_DR */ + mtmsr r0 + sync + isync + + /* Load ptr the list of pages to copy in r3 */ + lis r11,(pagedir_nosave - KERNELBASE)@h + ori r11,r11,[EMAIL PROTECTED] + lwz r10,0(r11) + tophys(r3,r10) + + /* Load the count of pages to copy in r4 */ + lis r11,(nr_copy_pages - KERNELBASE)@h + ori r11,r11,[EMAIL PROTECTED] + lwz r4,0(r11) + + + /* Copy the pages. This is a very basic implementation, to + * be replaced by something more cache efficient */ +1: + li r0,256 + mtctr r0 + lwz r11,0(r3) /* source */ + tophys(r5,r11) + lwz r10,4(r3) /* destination */ + tophys(r6,r10) +2: + lwz r8,0(r5) + lwz r9,4(r5) + lwz r10,8(r5) + lwz r11,12(r5) + addi r5,r5,16 + stw r8,0(r6) + stw r9,4(r6) + stw r10,8(r6) + stw r11,12(r6) + addi r6,r6,16 + bdnz 2b + addi r3,r3,16 + subi r4,r4,1 + cmpwi 0,r4,0 + bne 1b + + /* Do a very simple cache flush/inval of the L1 to ensure + * coherency of the icache + */ + lis r3,0x0002 + mtctr r3 + li r3, 0 +1: + lwz r0,0(r3) + addi r3,r3,0x0020 + bdnz 1b + isync + sync + + /* Now flush those cache lines */ + lis r3,0x0002 + mtctr r3 + li r3, 0 +1: + dcbf 0,r3 + addi r3,r3,0x0020 + bdnz 1b + sync + + /* Ok, we are now running with the kernel data of the old + * kernel fully restored. We can get to the save area + * easily now. As for the rest of the code, it assumes the + * loader kernel and the booted one are exactly identical + */ + lis r11,[EMAIL PROTECTED] + ori r11,r11,[EMAIL PROTECTED] + tophys(r11,r11) + +#if 0 + /* Restore various CPU config stuffs */ + bl __restore_cpu_setup +#endif + /* Restore the BATs, and SDR1. Then we can turn on the MMU. + * This is a bit hairy as we are running out of those BATs, + * but first, our code is probably in the icache, and we are + * writing the same value to the BAT, so that should be fine, + * though a better solution will have to be found long-term + */ + lwz r4,SL_SDR1(r11) + mtsdr1 r4 + lwz r4,SL_SPRG0(r11) + mtsprg 0,r4 + lwz r4,SL_SPRG0+4(r11) + mtsprg 1,r4 + lwz r4,SL_SPRG0+8(r11) + mtsprg 2,r4 + lwz r4,SL_SPRG0+12(r11) + mtsprg 3,r4 + +#if 0 + lwz r4,SL_DBAT0(r11) + mtdbatu 0,r4 + lwz r4,SL_DBAT0+4(r11) + mtdbatl 0,r4 + lwz r4,SL_DBAT1(r11) + mtdbatu 1,r4 + lwz r4,SL_DBAT1+4(r11) + mtdbatl 1,r4 + lwz r4,SL_DBAT2(r11) + mtdbatu 2,r4 + lwz r4,SL_DBAT2+4(r11) + mtdbatl 2,r4 + lwz r4,SL_DBAT3(r11) + mtdbatu 3,r4 + lwz r4,SL_DBAT3+4(r11) + mtdbatl 3,r4 + lwz r4,SL_IBAT0(r11) + mtibatu 0,r4 + lwz r4,SL_IBAT0+4(r11) + mtibatl 0,r4 + lwz r4,SL_IBAT1(r11) + mtibatu 1,r4 + lwz r4,SL_IBAT1+4(r11) + mtibatl 1,r4 + lwz r4,SL_IBAT2(r11) + mtibatu 2,r4 + lwz r4,SL_IBAT2+4(r11) + mtibatl 2,r4 + lwz r4,SL_IBAT3(r11) + mtibatu 3,r4 + lwz r4,SL_IBAT3+4(r11) + mtibatl 3,r4 +#endif + +BEGIN_FTR_SECTION + li r4,0 + mtspr SPRN_DBAT4U,r4 + mtspr SPRN_DBAT4L,r4 + mtspr SPRN_DBAT5U,r4 + mtspr SPRN_DBAT5L,r4 + mtspr SPRN_DBAT6U,r4 + mtspr SPRN_DBAT6L,r4 + mtspr SPRN_DBAT7U,r4 + mtspr SPRN_DBAT7L,r4 + mtspr SPRN_IBAT4U,r4 + mtspr SPRN_IBAT4L,r4 + mtspr SPRN_IBAT5U,r4 + mtspr SPRN_IBAT5L,r4 + mtspr SPRN_IBAT6U,r4 + mtspr SPRN_IBAT6L,r4 + mtspr SPRN_IBAT7U,r4 + mtspr SPRN_IBAT7L,r4 +END_FTR_SECTION_IFSET(CPU_FTR_HAS_HIGH_BATS) + + /* Flush all TLBs */ + lis r4,0x1000 +1: addic. r4,r4,-0x1000 + tlbie r4 + blt 1b + sync + + /* restore the MSR and turn on the MMU */ + lwz r3,SL_MSR(r11) + bl turn_on_mmu + tovirt(r11,r11) + + /* Restore TB */ + li r3,0 + mttbl r3 + lwz r3,SL_TB(r11) + lwz r4,SL_TB+4(r11) + mttbu r3 + mttbl r4 + + /* Kick decrementer */ + li r0,1 + mtdec r0 + + /* Restore the callee-saved registers and return */ + lwz r0,SL_CR(r11) + mtcr r0 + lwz r2,SL_R2(r11) + lmw r12,SL_R12(r11) + lwz r1,SL_SP(r11) + lwz r0,SL_LR(r11) + mtlr r0 + + // XXX Note: we don't really need to call swsusp_resume + + li r3,0 + blr + +/* FIXME:This construct is actually not useful since we don't shut + * down the instruction MMU, we could just flip back MSR-DR on. + */ +turn_on_mmu: + mflr r4 + mtsrr0 r4 + mtsrr1 r3 + sync + isync + rfi + diff -u -Naur linux-2.6.10.orig/arch/ppc/kernel/vmlinux.lds.S linux-2.6.10/arch/ppc/kernel/vmlinux.lds.S --- linux-2.6.10.orig/arch/ppc/kernel/vmlinux.lds.S 2004-12-24 22:35:50.000000000 +0100 +++ linux-2.6.10/arch/ppc/kernel/vmlinux.lds.S 2005-01-04 14:21:32.593281000 +0100 @@ -74,6 +74,12 @@ CONSTRUCTORS } + . = ALIGN(4096); + __nosave_begin = .; + .data_nosave : { *(.data.nosave) } + . = ALIGN(4096); + __nosave_end = .; + . = ALIGN(32); .data.cacheline_aligned : { *(.data.cacheline_aligned) } diff -u -Naur linux-2.6.10.orig/arch/ppc/platforms/pmac_cpufreq.c linux-2.6.10/arch/ppc/platforms/pmac_cpufreq.c --- linux-2.6.10.orig/arch/ppc/platforms/pmac_cpufreq.c 2004-12-24 22:34:58.000000000 +0100 +++ linux-2.6.10/arch/ppc/platforms/pmac_cpufreq.c 2005-01-04 14:21:32.593281000 +0100 @@ -36,6 +36,7 @@ #include <asm/system.h> #include <asm/open_pic.h> +#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "pmac-cpufreq", msg) /* WARNING !!! This will cause calibrate_delay() to be called, * but this is an __init function ! So you MUST go edit * init/main.c to make it non-init before enabling DEBUG_FREQ @@ -118,14 +119,12 @@ */ static int __pmac cpu_750fx_cpu_speed(int low_speed) { -#ifdef DEBUG_FREQ - printk(KERN_DEBUG "HID1, before: %x\n", mfspr(SPRN_HID1)); -#endif + dprintk("HID1, before: %x\n", mfspr(SPRN_HID1)); #ifdef CONFIG_6xx low_choose_750fx_pll(low_speed); #endif + dprintk("HID1, after: %x\n", mfspr(SPRN_HID1)); #ifdef DEBUG_FREQ - printk(KERN_DEBUG "HID1, after: %x\n", mfspr(SPRN_HID1)); debug_calc_bogomips(); #endif @@ -202,9 +201,7 @@ preempt_disable(); -#ifdef DEBUG_FREQ - printk(KERN_DEBUG "HID1, before: %x\n", mfspr(SPRN_HID1)); -#endif + dprintk("HID1, before: %x\n", mfspr(SPRN_HID1)); /* Disable all interrupt sources on openpic */ openpic_set_priority(0xf); @@ -262,9 +259,7 @@ /* Restore userland MMU context */ set_context(current->active_mm->context, current->active_mm->pgd); -#ifdef DEBUG_FREQ - printk(KERN_DEBUG "HID1, after: %x\n", mfspr(SPRN_HID1)); -#endif + dprintk("HID1, after: %x\n", mfspr(SPRN_HID1)); /* Restore low level PMU operations */ pmu_unlock(); @@ -354,14 +349,40 @@ return 0x50 + (*reg); } +static struct freq_attr* pmac_cpufreq_attr[] = { + &cpufreq_freq_attr_scaling_available_freqs, + NULL, +}; + static struct cpufreq_driver pmac_cpufreq_driver = { .verify = pmac_cpufreq_verify, .target = pmac_cpufreq_target, .init = pmac_cpufreq_cpu_init, .name = "powermac", .owner = THIS_MODULE, + .attr = pmac_cpufreq_attr, }; +static unsigned int __pmac pmac_cpufreq_get_pmu(unsigned int cpu) +{ + if (cpu) + return -ENODEV; + /* FIXME: we need to get the frequency properly */ + return cur_freq; +} + + +static unsigned int __pmac pmac_cpufreq_get_gpios(unsigned int cpu) +{ + struct device_node *freq_gpio_np = of_find_node_by_name(NULL, + "frequency-gpio"); + int rc; + + frequency_gpio = read_gpio(freq_gpio_np); + rc = pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, frequency_gpio, 0); + return (rc & 0x01) ? hi_freq : low_freq; +} + static int __pmac pmac_cpufreq_init_MacRISC3(struct device_node *cpunode) { @@ -371,6 +392,7 @@ "frequency-gpio"); struct device_node *slew_done_gpio_np = of_find_node_by_name(NULL, "slewing-done"); + struct cpufreq_driver *driver = &pmac_cpufreq_driver; u32 *value; /* @@ -395,6 +417,7 @@ int lenp, rc; u32 *freqs, *ratio; + dprintk("Using GIO"); freqs = (u32 *)get_property(cpunode, "bus-frequencies", &lenp); lenp /= sizeof(u32); if (freqs == NULL || lenp != 2) { @@ -423,14 +446,15 @@ low_freq = (low_freq * (*ratio)) / 2000; hi_freq = (hi_freq * (*ratio)) / 2000; - /* Now we get the frequencies, we read the GPIO to see what is out current + /* Now we get the frequencies, we read the GPIO to see what is our current * speed */ rc = pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, frequency_gpio, 0); cur_freq = (rc & 0x01) ? hi_freq : low_freq; set_speed_proc = gpios_set_cpu_speed; - return 1; + driver->get = pmac_cpufreq_get_gpios; + return 0; } /* If we use the PMU, look for the min & max frequencies in the @@ -450,22 +474,31 @@ return 1; hi_freq = (*value) / 1000; set_speed_proc = pmu_set_cpu_speed; + dprintk("Using PMU"); + driver->get = pmac_cpufreq_get_pmu; return 0; } +static unsigned int __pmac pmac_cpufreq_get_7447A(unsigned int cpu) +{ + if (mfspr(HID1) & HID1_DFS) + return low_freq; + else + return hi_freq; +} + static int __pmac pmac_cpufreq_init_7447A(struct device_node *cpunode) { struct device_node *volt_gpio_np; u32 *reg; + struct cpufreq_driver *driver = &pmac_cpufreq_driver; /* OF only reports the high frequency */ hi_freq = cur_freq; low_freq = cur_freq/2; - if (mfspr(HID1) & HID1_DFS) - cur_freq = low_freq; - else - cur_freq = hi_freq; + driver->get = pmac_cpufreq_get_7447A; + cur_freq = driver->get(0); volt_gpio_np = of_find_node_by_name(NULL, "cpu-vcore-select"); if (!volt_gpio_np){ diff -u -Naur linux-2.6.10.orig/arch/ppc/platforms/pmac_setup.c linux-2.6.10/arch/ppc/platforms/pmac_setup.c --- linux-2.6.10.orig/arch/ppc/platforms/pmac_setup.c 2004-12-24 22:35:01.000000000 +0100 +++ linux-2.6.10/arch/ppc/platforms/pmac_setup.c 2005-01-04 14:21:32.593281000 +0100 @@ -52,6 +52,7 @@ #include <linux/seq_file.h> #include <linux/root_dev.h> #include <linux/bitops.h> +#include <linux/suspend.h> #include <asm/reg.h> #include <asm/sections.h> @@ -70,6 +71,8 @@ #include <asm/pmac_feature.h> #include <asm/time.h> #include <asm/of_device.h> +#include <asm/mmu_context.h> + #include "pmac_pic.h" #include "mem_pieces.h" @@ -421,10 +424,62 @@ } 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; } diff -u -Naur linux-2.6.10.orig/drivers/ide/ppc/pmac.c linux-2.6.10/drivers/ide/ppc/pmac.c --- linux-2.6.10.orig/drivers/ide/ppc/pmac.c 2004-12-24 22:33:59.000000000 +0100 +++ linux-2.6.10/drivers/ide/ppc/pmac.c 2005-01-04 14:21:32.000000000 +0100 @@ -32,6 +32,7 @@ #include <linux/notifier.h> #include <linux/reboot.h> #include <linux/pci.h> +#include <linux/pm.h> #include <linux/adb.h> #include <linux/pmu.h> #include <linux/scatterlist.h> @@ -1360,7 +1361,7 @@ ide_hwif_t *hwif = (ide_hwif_t *)dev_get_drvdata(&mdev->ofdev.dev); int rc = 0; - if (state != mdev->ofdev.dev.power.power_state && state >= 2) { + if (state != mdev->ofdev.dev.power.power_state && state == PM_SUSPEND_MEM) { rc = pmac_ide_do_suspend(hwif); if (rc == 0) mdev->ofdev.dev.power.power_state = state; @@ -1468,7 +1469,7 @@ ide_hwif_t *hwif = (ide_hwif_t *)pci_get_drvdata(pdev); int rc = 0; - if (state != pdev->dev.power.power_state && state >= 2) { + if (state != pdev->dev.power.power_state && state == PM_SUSPEND_MEM ) { rc = pmac_ide_do_suspend(hwif); if (rc == 0) pdev->dev.power.power_state = state; diff -u -Naur linux-2.6.10.orig/drivers/macintosh/Kconfig linux-2.6.10/drivers/macintosh/Kconfig --- linux-2.6.10.orig/drivers/macintosh/Kconfig 2004-12-24 22:34:32.000000000 +0100 +++ linux-2.6.10/drivers/macintosh/Kconfig 2005-01-04 14:21:32.000000000 +0100 @@ -80,7 +80,7 @@ config PMAC_PBOOK bool "Power management support for PowerBooks" - depends on ADB_PMU + depends on PM && ADB_PMU ---help--- This provides support for putting a PowerBook to sleep; it also enables media bay support. Power management works on the @@ -97,11 +97,6 @@ have it autoloaded. The act of removing the module shuts down the sound hardware for more power savings. -config PM - bool - depends on PPC_PMAC && ADB_PMU && PMAC_PBOOK - default y - config PMAC_APM_EMU tristate "APM emulation" depends on PMAC_PBOOK diff -u -Naur linux-2.6.10.orig/drivers/macintosh/therm_pm72.c linux-2.6.10/drivers/macintosh/therm_pm72.c --- linux-2.6.10.orig/drivers/macintosh/therm_pm72.c 2004-12-24 22:35:23.000000000 +0100 +++ linux-2.6.10/drivers/macintosh/therm_pm72.c 2005-01-04 14:21:32.000000000 +0100 @@ -100,6 +100,7 @@ #include <linux/spinlock.h> #include <linux/smp_lock.h> #include <linux/wait.h> +#include <linux/suspend.h> #include <linux/reboot.h> #include <linux/kmod.h> #include <linux/i2c.h> @@ -1318,6 +1319,11 @@ while (state == state_attached) { unsigned long elapsed, start; + if (current->flags & PF_FREEZE) { + printk(KERN_INFO "therm_pm72: freezing thermostat\n"); + refrigerator(PF_FREEZE); + } + start = jiffies; down(&driver_lock); diff -u -Naur linux-2.6.10.orig/drivers/macintosh/via-pmu.c linux-2.6.10/drivers/macintosh/via-pmu.c --- linux-2.6.10.orig/drivers/macintosh/via-pmu.c 2004-12-24 22:35:28.000000000 +0100 +++ linux-2.6.10/drivers/macintosh/via-pmu.c 2005-01-04 14:21:32.000000000 +0100 @@ -43,6 +43,7 @@ #include <linux/init.h> #include <linux/interrupt.h> #include <linux/device.h> +#include <linux/sysdev.h> #include <linux/suspend.h> #include <linux/syscalls.h> #include <asm/prom.h> @@ -2326,7 +2327,7 @@ /* 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 acheived using the refrigerator for processes + * could be achieved using the refrigerator for processes * that swsusp uses */ sys_sync(); @@ -2379,7 +2380,6 @@ /* Wait for completion of async backlight requests */ while (!bright_req_1.complete || !bright_req_2.complete || - !batt_req.complete) pmu_poll(); @@ -3048,6 +3048,88 @@ } #endif /* DEBUG_SLEEP */ + +/* FIXME: This is a temporary set of callbacks to enable us + * to do suspend-to-disk. + */ + +#ifdef CONFIG_PM + +static int pmu_sys_suspended = 0; + +static int pmu_sys_suspend(struct sys_device *sysdev, u32 state) +{ + if (state != PM_SUSPEND_DISK || pmu_sys_suspended) + return 0; + + /* Suspend PMU event interrupts */ + pmu_suspend(); + + pmu_sys_suspended = 1; + return 0; +} + +static int pmu_sys_resume(struct sys_device *sysdev) +{ + struct adb_request req; + + if (!pmu_sys_suspended) + return 0; + + /* Tell PMU we are ready */ + pmu_request(&req, NULL, 2, PMU_SYSTEM_READY, 2); + pmu_wait_complete(&req); + + /* Resume PMU event interrupts */ + pmu_resume(); + + pmu_sys_suspended = 0; + + return 0; +} + +#endif /* CONFIG_PM */ + +static struct sysdev_class pmu_sysclass = { + set_kset_name("pmu"), +}; + +static struct sys_device device_pmu = { + .id = 0, + .cls = &pmu_sysclass, +}; + +static struct sysdev_driver driver_pmu = { +#ifdef CONFIG_PM + .suspend = &pmu_sys_suspend, + .resume = &pmu_sys_resume, +#endif /* CONFIG_PM */ +}; + +static int __init init_pmu_sysfs(void) +{ + int rc; + + rc = sysdev_class_register(&pmu_sysclass); + if (rc) { + printk(KERN_ERR "Failed registering PMU sys class\n"); + return -ENODEV; + } + rc = sysdev_register(&device_pmu); + if (rc) { + printk(KERN_ERR "Failed registering PMU sys device\n"); + return -ENODEV; + } + rc = sysdev_driver_register(&pmu_sysclass, &driver_pmu); + if (rc) { + printk(KERN_ERR "Failed registering PMU sys driver\n"); + return -ENODEV; + } + return 0; +} + +subsys_initcall(init_pmu_sysfs); + EXPORT_SYMBOL(pmu_request); EXPORT_SYMBOL(pmu_poll); EXPORT_SYMBOL(pmu_poll_adb); diff -u -Naur linux-2.6.10.orig/drivers/net/pcnet32.c linux-2.6.10/drivers/net/pcnet32.c --- linux-2.6.10.orig/drivers/net/pcnet32.c 2004-12-24 22:34:29.000000000 +0100 +++ linux-2.6.10/drivers/net/pcnet32.c 2005-01-04 14:27:26.713281000 +0100 @@ -1429,26 +1429,33 @@ val |= 0x10; lp->a.write_csr (ioaddr, 124, val); - /* 24 Jun 2004 according AMD, in order to change the PHY, - * DANAS (or DISPM for 79C976) must be set; then select the speed, - * duplex, and/or enable auto negotiation, and clear DANAS */ - if (lp->mii && !(lp->options & PCNET32_PORT_ASEL)) { - lp->a.write_bcr(ioaddr, 32, lp->a.read_bcr(ioaddr, 32) | 0x0080); - /* disable Auto Negotiation, set 10Mpbs, HD */ - val = lp->a.read_bcr(ioaddr, 32) & ~0xb8; - if (lp->options & PCNET32_PORT_FD) - val |= 0x10; - if (lp->options & PCNET32_PORT_100) - val |= 0x08; - lp->a.write_bcr (ioaddr, 32, val); + /* Allied Telesyn AT 2701 FX looses the link, so skip that */ + if(lp->pci_dev->subsystem_vendor == PCI_VENDOR_ID_AT && + (lp->pci_dev->subsystem_device == PCI_SUBDEVICE_ID_AT_2700FX || + lp->pci_dev->subsystem_device == PCI_SUBDEVICE_ID_AT_2701FX )) { + printk(KERN_DEBUG "pcnet32: Skipping PHY selection.\n"); } else { - if (lp->options & PCNET32_PORT_ASEL) { - lp->a.write_bcr(ioaddr, 32, lp->a.read_bcr(ioaddr, 32) | 0x0080); - /* enable auto negotiate, setup, disable fd */ - val = lp->a.read_bcr(ioaddr, 32) & ~0x98; - val |= 0x20; - lp->a.write_bcr(ioaddr, 32, val); - } + /* 24 Jun 2004 according AMD, in order to change the PHY, + * DANAS (or DISPM for 79C976) must be set; then select the speed, + * duplex, and/or enable auto negotiation, and clear DANAS */ + if (lp->mii && !(lp->options & PCNET32_PORT_ASEL)) { + lp->a.write_bcr(ioaddr, 32, lp->a.read_bcr(ioaddr, 32) | 0x0080); + /* disable Auto Negotiation, set 10Mpbs, HD */ + val = lp->a.read_bcr(ioaddr, 32) & ~0xb8; + if (lp->options & PCNET32_PORT_FD) + val |= 0x10; + if (lp->options & PCNET32_PORT_100) + val |= 0x08; + lp->a.write_bcr (ioaddr, 32, val); + } else { + if (lp->options & PCNET32_PORT_ASEL) { + lp->a.write_bcr(ioaddr, 32, lp->a.read_bcr(ioaddr, 32) | 0x0080); + /* enable auto negotiate, setup, disable fd */ + val = lp->a.read_bcr(ioaddr, 32) & ~0x98; + val |= 0x20; + lp->a.write_bcr(ioaddr, 32, val); + } + } } #ifdef DO_DXSUFLO diff -u -Naur linux-2.6.10.orig/drivers/video/aty/radeon_pm.c linux-2.6.10/drivers/video/aty/radeon_pm.c --- linux-2.6.10.orig/drivers/video/aty/radeon_pm.c 2004-12-24 22:35:18.000000000 +0100 +++ linux-2.6.10/drivers/video/aty/radeon_pm.c 2005-01-04 14:21:32.000000000 +0100 @@ -860,7 +860,9 @@ * can properly take care of D3 ? Also, with swsusp, we * know we'll be rebooted, ... */ - +#ifdef CONFIG_SOFTWARE_SUSPEND /* ...until the dust has settled */ + return 0; +#endif printk(KERN_DEBUG "radeonfb: suspending to state: %d...\n", state); acquire_console_sem(); diff -u -Naur linux-2.6.10.orig/include/asm-ppc/param.h linux-2.6.10/include/asm-ppc/param.h --- linux-2.6.10.orig/include/asm-ppc/param.h 2004-12-24 22:34:32.000000000 +0100 +++ linux-2.6.10/include/asm-ppc/param.h 2005-01-04 14:21:32.000000000 +0100 @@ -2,7 +2,7 @@ #define _ASM_PPC_PARAM_H #ifdef __KERNEL__ -#define HZ 1000 /* internal timer frequency */ +#define HZ (CONFIG_PPC_HZ) /* internal timer frequency */ #define USER_HZ 100 /* for user interfaces in "ticks" */ #define CLOCKS_PER_SEC (USER_HZ) /* frequency at which times() counts */ #endif /* __KERNEL__ */ diff -u -Naur linux-2.6.10.orig/include/asm-ppc/suspend.h linux-2.6.10/include/asm-ppc/suspend.h --- linux-2.6.10.orig/include/asm-ppc/suspend.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.10/include/asm-ppc/suspend.h 2005-01-04 14:21:32.000000000 +0100 @@ -0,0 +1,12 @@ +static inline int arch_prepare_suspend(void) +{ + return 0; +} + +static inline void save_processor_state(void) +{ +} + +static inline void restore_processor_state(void) +{ +} diff -u -Naur linux-2.6.10.orig/include/asm-ppc/system.h linux-2.6.10/include/asm-ppc/system.h --- linux-2.6.10.orig/include/asm-ppc/system.h 2004-12-24 22:34:32.000000000 +0100 +++ linux-2.6.10/include/asm-ppc/system.h 2005-01-04 14:21:32.000000000 +0100 @@ -74,6 +74,7 @@ extern void pmac_find_display(void); extern void giveup_fpu(struct task_struct *); extern void enable_kernel_fp(void); +extern void enable_kernel_altivec(void); extern void giveup_altivec(struct task_struct *); extern void load_up_altivec(struct task_struct *); extern void giveup_spe(struct task_struct *); diff -u -Naur linux-2.6.10.orig/include/linux/pci_ids.h linux-2.6.10/include/linux/pci_ids.h --- linux-2.6.10.orig/include/linux/pci_ids.h 2004-12-24 22:35:50.000000000 +0100 +++ linux-2.6.10/include/linux/pci_ids.h 2005-01-04 14:26:39.543281000 +0100 @@ -1631,6 +1631,11 @@ #define PCI_DEVICE_ID_OPTIBASE_VPLEXCC 0x2120 #define PCI_DEVICE_ID_OPTIBASE_VQUEST 0x2130 +/* Allied Telesyn */ +#define PCI_VENDOR_ID_AT 0x1259 +#define PCI_SUBDEVICE_ID_AT_2701FX 0x2703 +#define PCI_SUBDEVICE_ID_AT_2700FX 0x2701 + #define PCI_VENDOR_ID_ESS 0x125d #define PCI_DEVICE_ID_ESS_ESS1968 0x1968 #define PCI_DEVICE_ID_ESS_AUDIOPCI 0x1969 diff -u -Naur linux-2.6.10.orig/include/linux/reboot.h linux-2.6.10/include/linux/reboot.h --- linux-2.6.10.orig/include/linux/reboot.h 2004-12-24 22:35:50.000000000 +0100 +++ linux-2.6.10/include/linux/reboot.h 2005-01-04 14:21:32.000000000 +0100 @@ -42,6 +42,8 @@ extern int register_reboot_notifier(struct notifier_block *); extern int unregister_reboot_notifier(struct notifier_block *); +/* For use by swsusp only */ +extern struct notifier_block *reboot_notifier_list; /* * Architecture-specific implementations of sys_reboot commands. diff -u -Naur linux-2.6.10.orig/include/linux/suspend.h linux-2.6.10/include/linux/suspend.h --- linux-2.6.10.orig/include/linux/suspend.h 2004-12-24 22:34:27.000000000 +0100 +++ linux-2.6.10/include/linux/suspend.h 2005-01-04 14:21:32.000000000 +0100 @@ -1,7 +1,7 @@ #ifndef _LINUX_SWSUSP_H #define _LINUX_SWSUSP_H -#ifdef CONFIG_X86 +#if defined(CONFIG_X86) || defined(CONFIG_PPC32) #include <asm/suspend.h> #endif #include <linux/swap.h> diff -u -Naur linux-2.6.10.orig/kernel/power/disk.c linux-2.6.10/kernel/power/disk.c --- linux-2.6.10.orig/kernel/power/disk.c 2004-12-24 22:33:50.000000000 +0100 +++ linux-2.6.10/kernel/power/disk.c 2005-01-04 14:21:32.000000000 +0100 @@ -17,6 +17,7 @@ #include <linux/delay.h> #include <linux/fs.h> #include <linux/device.h> +#include <linux/reboot.h> #include "power.h" @@ -48,14 +49,15 @@ unsigned long flags; int error = 0; - local_irq_save(flags); switch(mode) { case PM_DISK_PLATFORM: - device_power_down(PM_SUSPEND_DISK); + local_irq_save(flags); error = pm_ops->enter(PM_SUSPEND_DISK); + local_irq_restore(flags); break; case PM_DISK_SHUTDOWN: printk("Powering off system\n"); + notifier_call_chain(&reboot_notifier_list, SYS_POWER_OFF, NULL); device_shutdown(); machine_power_off(); break; diff -u -Naur linux-2.6.10.orig/kernel/power/swsusp.c linux-2.6.10/kernel/power/swsusp.c --- linux-2.6.10.orig/kernel/power/swsusp.c 2004-12-24 22:34:27.000000000 +0100 +++ linux-2.6.10/kernel/power/swsusp.c 2005-01-04 14:21:34.000000000 +0100 @@ -862,16 +862,18 @@ if ((error = arch_prepare_suspend())) return error; local_irq_disable(); + device_power_down(PM_SUSPEND_DISK); save_processor_state(); error = swsusp_arch_suspend(); /* Restore control flow magically appears here */ restore_processor_state(); restore_highmem(); + device_power_up(); local_irq_enable(); return error; } - +#if 0 asmlinkage int swsusp_restore(void) { BUG_ON (nr_copy_pages_check != nr_copy_pages); @@ -881,11 +883,13 @@ __flush_tlb_global(); return 0; } +#endif int swsusp_resume(void) { int error; local_irq_disable(); + device_power_down(PM_SUSPEND_DISK); /* We'll ignore saved state, but this gets preempt count (etc) right */ save_processor_state(); error = swsusp_arch_resume(); @@ -895,6 +899,7 @@ BUG_ON(!error); restore_processor_state(); restore_highmem(); + device_power_up(); local_irq_enable(); return error; } @@ -1186,7 +1191,7 @@ return -ENOMEM; pagedir_nosave = (struct pbe *)addr; - pr_debug("pmdisk: Reading pagedir (%d Pages)\n",n); + pr_debug("swsusp: Reading pagedir (%d Pages)\n",n); for (i = 0; i < n && !error; i++, addr += PAGE_SIZE) { unsigned long offset = swp_offset(swsusp_info.pagedir[i]); @@ -1216,7 +1221,7 @@ } /** - * pmdisk_read - Read saved image from swap. + * swsusp_read - Read saved image from swap. */ int __init swsusp_read(void) @@ -1240,6 +1245,6 @@ if (!error) pr_debug("Reading resume file was successful\n"); else - pr_debug("pmdisk: Error %d resuming\n", error); + pr_debug("swsusp: Error %d resuming\n", error); return error; } diff -u -Naur linux-2.6.10.orig/kernel/sys.c linux-2.6.10/kernel/sys.c --- linux-2.6.10.orig/kernel/sys.c 2004-12-24 22:33:59.000000000 +0100 +++ linux-2.6.10/kernel/sys.c 2005-01-04 14:21:34.000000000 +0100 @@ -87,7 +87,7 @@ * and the like. */ -static struct notifier_block *reboot_notifier_list; +struct notifier_block *reboot_notifier_list; rwlock_t notifier_lock = RW_LOCK_UNLOCKED; /** diff -u -Naur linux-2.6.10.orig/sound/ppc/pmac.c linux-2.6.10/sound/ppc/pmac.c --- linux-2.6.10.orig/sound/ppc/pmac.c 2004-12-24 22:35:49.000000000 +0100 +++ linux-2.6.10/sound/ppc/pmac.c 2005-01-04 14:21:34.000000000 +0100 @@ -50,8 +50,8 @@ 44100, 29400, 22050, 17640, 14700, 11025, 8820, 7350 }; /* fixed frequency table for tumbler */ -static int tumbler_freqs[1] = { - 44100 +static int tumbler_freqs[2] = { + 48000, 44100 }; /* @@ -488,12 +488,14 @@ snd_pcm_runtime_t *runtime = subs->runtime; int i, j, fflags; static int typical_freqs[] = { + 48000, 44100, 22050, 11025, 0, }; static int typical_freq_flags[] = { + SNDRV_PCM_RATE_48000, SNDRV_PCM_RATE_44100, SNDRV_PCM_RATE_22050, SNDRV_PCM_RATE_11025, @@ -647,7 +649,7 @@ pcm->private_data = chip; pcm->private_free = pmac_pcm_free; - pcm->info_flags = SNDRV_PCM_INFO_JOINT_DUPLEX; + pcm->info_flags = 0; strcpy(pcm->name, chip->card->shortname); chip->pcm = pcm; diff -u -Naur linux-2.6.10.orig/sound/ppc/tumbler.c linux-2.6.10/sound/ppc/tumbler.c --- linux-2.6.10.orig/sound/ppc/tumbler.c 2004-12-24 22:33:49.000000000 +0100 +++ linux-2.6.10/sound/ppc/tumbler.c 2005-01-04 14:21:34.000000000 +0100 @@ -767,6 +767,12 @@ DEFINE_MONO("Tone Control - Treble", treble), DEFINE_MONO("PCM Playback Volume", pcm), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "DRC Switch", + .info = snd_pmac_boolean_mono_info, + .get = tumbler_get_drc_switch, + .put = tumbler_put_drc_switch + }, + { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "DRC Range", .info = tumbler_info_drc_value, .get = tumbler_get_drc_value, @@ -793,6 +799,12 @@ DEFINE_SNAPPER_MONO("Tone Control - Bass", bass), DEFINE_SNAPPER_MONO("Tone Control - Treble", treble), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "DRC Switch", + .info = snd_pmac_boolean_mono_info, + .get = tumbler_get_drc_switch, + .put = tumbler_put_drc_switch + }, + { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "DRC Range", .info = tumbler_info_drc_value, .get = tumbler_get_drc_value, @@ -822,14 +834,6 @@ .put = tumbler_put_mute_switch, .private_value = TUMBLER_MUTE_AMP, }; -static snd_kcontrol_new_t tumbler_drc_sw __initdata = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "DRC Switch", - .info = snd_pmac_boolean_mono_info, - .get = tumbler_get_drc_switch, - .put = tumbler_put_drc_switch -}; - #ifdef PMAC_SUPPORT_AUTOMUTE /* @@ -851,29 +855,6 @@ } } -static struct work_struct device_change; - -static void -device_change_handler(void *self) -{ - pmac_t *chip = (pmac_t*) self; - pmac_tumbler_t *mix; - - if (!chip) - return; - - mix = chip->mixer_data; - - /* first set the DRC so the speaker do not explode -ReneR */ - if (chip->model == PMAC_TUMBLER) - tumbler_set_drc(mix); - else - snapper_set_drc(mix); - - /* reset the master volume so the correct amplification is applied */ - tumbler_set_master_volume(mix); -} - static void tumbler_update_automute(pmac_t *chip, int do_notify) { if (chip->auto_mute) { @@ -883,25 +864,14 @@ /* mute speaker */ check_mute(chip, &mix->amp_mute, 1, do_notify, chip->speaker_sw_ctl); check_mute(chip, &mix->hp_mute, 0, do_notify, chip->master_sw_ctl); - mix->drc_enable = 0; - } else { /* unmute speaker */ check_mute(chip, &mix->amp_mute, 0, do_notify, chip->speaker_sw_ctl); check_mute(chip, &mix->hp_mute, 1, do_notify, chip->master_sw_ctl); - mix->drc_enable = 1; } - if (do_notify) { + if (do_notify) snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &chip->hp_detect_ctl->id); - snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, - &chip->drc_sw_ctl->id); - } - - /* finally we need to schedule an update of the mixer values - (master and DRC are enough for now) -ReneR */ - schedule_work(&device_change); - } } #endif /* PMAC_SUPPORT_AUTOMUTE */ @@ -1028,7 +998,7 @@ } tumbler_set_master_volume(mix); if (chip->update_automute) - chip->update_automute(chip, 0); + chip->update_automute(chip, 1); } #endif @@ -1152,17 +1122,11 @@ chip->speaker_sw_ctl = snd_ctl_new1(&tumbler_speaker_sw, chip); if ((err = snd_ctl_add(chip->card, chip->speaker_sw_ctl)) < 0) return err; - chip->drc_sw_ctl = snd_ctl_new1(&tumbler_drc_sw, chip); - if ((err = snd_ctl_add(chip->card, chip->drc_sw_ctl)) < 0) - return err; - #ifdef CONFIG_PMAC_PBOOK chip->resume = tumbler_resume; #endif - INIT_WORK(&device_change, device_change_handler, (void *)chip); - #ifdef PMAC_SUPPORT_AUTOMUTE if (mix->headphone_irq >=0 && (err = snd_pmac_add_automute(chip)) < 0) return err;