Warning!

Notice: the grml team is migrating from Mercurial to Git.
Please visit git.grml.org instead!

Add ipw2200-1.1.4-inject.patch; update to 2.6.20.11.patch
authorMichael Prokop <mika@grml.org>
Thu May 03 19:05:17 2007 +0200 (19 months ago)
changeset 326d0a9e113229
manifest6d0a9e113229
parent 31d678459cafde
child 33994e41ee3a3f
Add ipw2200-1.1.4-inject.patch; update to 2.6.20.11.patch
2.6.20/x86/1000_2.6.20.11.patch
2.6.20/x86/1000_2.6.20.7.patch
2.6.20/x86/4200_ipw2200-1.1.4-inject.patch
config/config-2.6.20-grml
--- a/config/config-2.6.20-grml Sun Apr 22 15:48:09 2007 +0200
+++ b/config/config-2.6.20-grml Thu May 03 19:05:17 2007 +0200
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
# Linux kernel version: 2.6.20-grml
-# Sat Apr 7 00:01:41 2007
+# Sun Apr 22 13:06:31 2007
#
CONFIG_X86_32=y
CONFIG_GENERIC_TIME=y
@@ -3806,7 +3806,6 @@ CONFIG_DEBUG_MUTEXES=y
# CONFIG_PROVE_LOCKING is not set
# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
-CONFIG_STACKTRACE=y
# CONFIG_DEBUG_KOBJECT is not set
# CONFIG_DEBUG_HIGHMEM is not set
CONFIG_DEBUG_BUGVERBOSE=y
@@ -3817,9 +3816,6 @@ CONFIG_FORCED_INLINING=y
CONFIG_FORCED_INLINING=y
CONFIG_RCU_TORTURE_TEST=m
# CONFIG_FAULT_INJECTION is not set
-# CONFIG_FAILSLAB is not set
-# CONFIG_FAIL_PAGE_ALLOC is not set
-# CONFIG_FAIL_MAKE_REQUEST is not set
CONFIG_EARLY_PRINTK=y
# CONFIG_DEBUG_STACKOVERFLOW is not set
# CONFIG_DEBUG_STACK_USAGE is not set
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/2.6.20/x86/1000_2.6.20.11.patch Thu May 03 19:05:17 2007 +0200
@@ -0,0 +1,11911 @@
+diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt
+index a0f6842..713c283 100644
+--- a/Documentation/networking/ip-sysctl.txt
++++ b/Documentation/networking/ip-sysctl.txt
+@@ -825,6 +825,15 @@ accept_redirects - BOOLEAN
+ Functional default: enabled if local forwarding is disabled.
+ disabled if local forwarding is enabled.
+
++accept_source_route - INTEGER
++ Accept source routing (routing extension header).
++
++ > 0: Accept routing header.
++ = 0: Accept only routing header type 2.
++ < 0: Do not accept routing header.
++
++ Default: 0
++
+ autoconf - BOOLEAN
+ Autoconfigure addresses using Prefix Information in Router
+ Advertisements.
+diff --git a/Makefile b/Makefile
+index 7e2750f..f585e79 100644
+--- a/Makefile
++++ b/Makefile
+@@ -1,7 +1,7 @@
+ VERSION = 2
+ PATCHLEVEL = 6
+ SUBLEVEL = 20
+-EXTRAVERSION =
++EXTRAVERSION = .11
+ NAME = Homicidal Dwarf Hamster
+
+ # *DOCUMENTATION*
+diff --git a/arch/i386/boot/video.S b/arch/i386/boot/video.S
+index 2c5b5cc..8143c95 100644
+--- a/arch/i386/boot/video.S
++++ b/arch/i386/boot/video.S
+@@ -571,6 +571,16 @@ setr1: lodsw
+ jmp _m_s
+
+ check_vesa:
++#ifdef CONFIG_FIRMWARE_EDID
++ leaw modelist+1024, %di
++ movw $0x4f00, %ax
++ int $0x10
++ cmpw $0x004f, %ax
++ jnz setbad
++
++ movw 4(%di), %ax
++ movw %ax, vbe_version
++#endif
+ leaw modelist+1024, %di
+ subb $VIDEO_FIRST_VESA>>8, %bh
+ movw %bx, %cx # Get mode information structure
+@@ -1945,6 +1955,9 @@ store_edid:
+ rep
+ stosl
+
++ cmpw $0x0200, vbe_version # only do EDID on >= VBE2.0
++ jl no_edid
++
+ pushw %es # save ES
+ xorw %di, %di # Report Capability
+ pushw %di
+@@ -1987,6 +2000,7 @@ do_restore: .byte 0 # Screen contents altered during mode change
+ svga_prefix: .byte VIDEO_FIRST_BIOS>>8 # Default prefix for BIOS modes
+ graphic_mode: .byte 0 # Graphic mode with a linear frame buffer
+ dac_size: .byte 6 # DAC bit depth
++vbe_version: .word 0 # VBE bios version
+
+ # Status messages
+ keymsg: .ascii "Press <RETURN> to see video modes available, "
+diff --git a/arch/i386/kernel/cpu/mtrr/if.c b/arch/i386/kernel/cpu/mtrr/if.c
+index 5ae1705..590d99e 100644
+--- a/arch/i386/kernel/cpu/mtrr/if.c
++++ b/arch/i386/kernel/cpu/mtrr/if.c
+@@ -158,8 +158,9 @@ mtrr_ioctl(struct file *file, unsigned int cmd, unsigned long __arg)
+ struct mtrr_sentry sentry;
+ struct mtrr_gentry gentry;
+ void __user *arg = (void __user *) __arg;
++ unsigned int compat_cmd = cmd;
+
+- switch (cmd) {
++ switch (compat_cmd) {
+ case MTRRIOC_ADD_ENTRY:
+ case MTRRIOC_SET_ENTRY:
+ case MTRRIOC_DEL_ENTRY:
+@@ -177,14 +178,20 @@ mtrr_ioctl(struct file *file, unsigned int cmd, unsigned long __arg)
+ return -EFAULT;
+ break;
+ #ifdef CONFIG_COMPAT
+- case MTRRIOC32_ADD_ENTRY:
+- case MTRRIOC32_SET_ENTRY:
+- case MTRRIOC32_DEL_ENTRY:
+- case MTRRIOC32_KILL_ENTRY:
+- case MTRRIOC32_ADD_PAGE_ENTRY:
+- case MTRRIOC32_SET_PAGE_ENTRY:
+- case MTRRIOC32_DEL_PAGE_ENTRY:
+- case MTRRIOC32_KILL_PAGE_ENTRY: {
++#define MTRR_COMPAT_OP(op, type)\
++ case MTRRIOC32_##op: \
++ cmd = MTRRIOC_##op; \
++ goto compat_get_##type
++
++ MTRR_COMPAT_OP(ADD_ENTRY, sentry);
++ MTRR_COMPAT_OP(SET_ENTRY, sentry);
++ MTRR_COMPAT_OP(DEL_ENTRY, sentry);
++ MTRR_COMPAT_OP(KILL_ENTRY, sentry);
++ MTRR_COMPAT_OP(ADD_PAGE_ENTRY, sentry);
++ MTRR_COMPAT_OP(SET_PAGE_ENTRY, sentry);
++ MTRR_COMPAT_OP(DEL_PAGE_ENTRY, sentry);
++ MTRR_COMPAT_OP(KILL_PAGE_ENTRY, sentry);
++compat_get_sentry: {
+ struct mtrr_sentry32 __user *s32 = (struct mtrr_sentry32 __user *)__arg;
+ err = get_user(sentry.base, &s32->base);
+ err |= get_user(sentry.size, &s32->size);
+@@ -193,8 +200,9 @@ mtrr_ioctl(struct file *file, unsigned int cmd, unsigned long __arg)
+ return err;
+ break;
+ }
+- case MTRRIOC32_GET_ENTRY:
+- case MTRRIOC32_GET_PAGE_ENTRY: {
++ MTRR_COMPAT_OP(GET_ENTRY, gentry);
++ MTRR_COMPAT_OP(GET_PAGE_ENTRY, gentry);
++compat_get_gentry: {
+ struct mtrr_gentry32 __user *g32 = (struct mtrr_gentry32 __user *)__arg;
+ err = get_user(gentry.regnum, &g32->regnum);
+ err |= get_user(gentry.base, &g32->base);
+@@ -204,6 +212,7 @@ mtrr_ioctl(struct file *file, unsigned int cmd, unsigned long __arg)
+ return err;
+ break;
+ }
++#undef MTRR_COMPAT_OP
+ #endif
+ }
+
+@@ -287,7 +296,7 @@ mtrr_ioctl(struct file *file, unsigned int cmd, unsigned long __arg)
+ if (err)
+ return err;
+
+- switch(cmd) {
++ switch(compat_cmd) {
+ case MTRRIOC_GET_ENTRY:
+ case MTRRIOC_GET_PAGE_ENTRY:
+ if (copy_to_user(arg, &gentry, sizeof gentry))
+diff --git a/arch/i386/kernel/signal.c b/arch/i386/kernel/signal.c
+index 65d7620..f654505 100644
+--- a/arch/i386/kernel/signal.c
++++ b/arch/i386/kernel/signal.c
+@@ -21,6 +21,7 @@
+ #include <linux/suspend.h>
+ #include <linux/ptrace.h>
+ #include <linux/elf.h>
++#include <linux/binfmts.h>
+ #include <asm/processor.h>
+ #include <asm/ucontext.h>
+ #include <asm/uaccess.h>
+@@ -349,7 +350,10 @@ static int setup_frame(int sig, struct k_sigaction *ka,
+ goto give_sigsegv;
+ }
+
+- restorer = (void *)VDSO_SYM(&__kernel_sigreturn);
++ if (current->binfmt->hasvdso)
++ restorer = (void *)VDSO_SYM(&__kernel_sigreturn);
++ else
++ restorer = (void *)&frame->retcode;
+ if (ka->sa.sa_flags & SA_RESTORER)
+ restorer = ka->sa.sa_restorer;
+
+diff --git a/arch/i386/kernel/sysenter.c b/arch/i386/kernel/sysenter.c
+index 5da7442..666f70d 100644
+--- a/arch/i386/kernel/sysenter.c
++++ b/arch/i386/kernel/sysenter.c
+@@ -77,7 +77,7 @@ int __init sysenter_setup(void)
+ syscall_page = (void *)get_zeroed_page(GFP_ATOMIC);
+
+ #ifdef CONFIG_COMPAT_VDSO
+- __set_fixmap(FIX_VDSO, __pa(syscall_page), PAGE_READONLY);
++ __set_fixmap(FIX_VDSO, __pa(syscall_page), PAGE_READONLY_EXEC);
+ printk("Compat vDSO mapped to %08lx.\n", __fix_to_virt(FIX_VDSO));
+ #endif
+
+diff --git a/arch/i386/lib/usercopy.c b/arch/i386/lib/usercopy.c
+index d22cfc9..086b372 100644
+--- a/arch/i386/lib/usercopy.c
++++ b/arch/i386/lib/usercopy.c
+@@ -10,6 +10,7 @@
+ #include <linux/blkdev.h>
+ #include <linux/module.h>
+ #include <linux/backing-dev.h>
++#include <linux/interrupt.h>
+ #include <asm/uaccess.h>
+ #include <asm/mmx.h>
+
+@@ -719,6 +720,14 @@ unsigned long __copy_to_user_ll(void __user *to, const void *from,
+ #ifndef CONFIG_X86_WP_WORKS_OK
+ if (unlikely(boot_cpu_data.wp_works_ok == 0) &&
+ ((unsigned long )to) < TASK_SIZE) {
++ /*
++ * When we are in an atomic section (see
++ * mm/filemap.c:file_read_actor), return the full
++ * length to take the slow path.
++ */
++ if (in_atomic())
++ return n;
++
+ /*
+ * CPU does not honor the WP bit when writing
+ * from supervisory mode, and due to preemption or SMP,
+diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig
+index fcacfe2..c085199 100644
+--- a/arch/ia64/Kconfig
++++ b/arch/ia64/Kconfig
+@@ -11,6 +11,7 @@ menu "Processor type and features"
+
+ config IA64
+ bool
++ select ATA_NONSTANDARD if ATA
+ default y
+ help
+ The Itanium Processor Family is Intel's 64-bit successor to
+diff --git a/arch/ia64/kernel/crash.c b/arch/ia64/kernel/crash.c
+index bc2f64d..2018e62 100644
+--- a/arch/ia64/kernel/crash.c
++++ b/arch/ia64/kernel/crash.c
+@@ -79,6 +79,7 @@ crash_save_this_cpu()
+ final_note(buf);
+ }
+
++#ifdef CONFIG_SMP
+ static int
+ kdump_wait_cpu_freeze(void)
+ {
+@@ -91,6 +92,7 @@ kdump_wait_cpu_freeze(void)
+ }
+ return 1;
+ }
++#endif
+
+ void
+ machine_crash_shutdown(struct pt_regs *pt)
+@@ -132,11 +134,12 @@ kdump_cpu_freeze(struct unw_frame_info *info, void *arg)
+ atomic_inc(&kdump_cpu_freezed);
+ kdump_status[cpuid] = 1;
+ mb();
+- if (cpuid == 0) {
+- for (;;)
+- cpu_relax();
+- } else
++#ifdef CONFIG_HOTPLUG_CPU
++ if (cpuid != 0)
+ ia64_jump_to_sal(&sal_boot_rendez_state[cpuid]);
++#endif
++ for (;;)
++ cpu_relax();
+ }
+
+ static int
+diff --git a/arch/ia64/kernel/iosapic.c b/arch/ia64/kernel/iosapic.c
+index 0fc5fb7..02479e1 100644
+--- a/arch/ia64/kernel/iosapic.c
++++ b/arch/ia64/kernel/iosapic.c
+@@ -446,7 +446,7 @@ iosapic_end_level_irq (unsigned int irq)
+ #define iosapic_disable_level_irq mask_irq
+ #define iosapic_ack_level_irq nop
+
+-struct hw_interrupt_type irq_type_iosapic_level = {
++struct irq_chip irq_type_iosapic_level = {
+ .name = "IO-SAPIC-level",
+ .startup = iosapic_startup_level_irq,
+ .shutdown = iosapic_shutdown_level_irq,
+@@ -454,6 +454,8 @@ struct hw_interrupt_type irq_type_iosapic_level = {
+ .disable = iosapic_disable_level_irq,
+ .ack = iosapic_ack_level_irq,
+ .end = iosapic_end_level_irq,
++ .mask = mask_irq,
++ .unmask = unmask_irq,
+ .set_affinity = iosapic_set_affinity
+ };
+
+@@ -493,7 +495,7 @@ iosapic_ack_edge_irq (unsigned int irq)
+ #define iosapic_disable_edge_irq nop
+ #define iosapic_end_edge_irq nop
+
+-struct hw_interrupt_type irq_type_iosapic_edge = {
++struct irq_chip irq_type_iosapic_edge = {
+ .name = "IO-SAPIC-edge",
+ .startup = iosapic_startup_edge_irq,
+ .shutdown = iosapic_disable_edge_irq,
+@@ -501,6 +503,8 @@ struct hw_interrupt_type irq_type_iosapic_edge = {
+ .disable = iosapic_disable_edge_irq,
+ .ack = iosapic_ack_edge_irq,
+ .end = iosapic_end_edge_irq,
++ .mask = mask_irq,
++ .unmask = unmask_irq,
+ .set_affinity = iosapic_set_affinity
+ };
+
+diff --git a/arch/ia64/kernel/machine_kexec.c b/arch/ia64/kernel/machine_kexec.c
+index e2ccc9f..7141795 100644
+--- a/arch/ia64/kernel/machine_kexec.c
++++ b/arch/ia64/kernel/machine_kexec.c
+@@ -70,12 +70,14 @@ void machine_kexec_cleanup(struct kimage *image)
+
+ void machine_shutdown(void)
+ {
++#ifdef CONFIG_HOTPLUG_CPU
+ int cpu;
+
+ for_each_online_cpu(cpu) {
+ if (cpu != smp_processor_id())
+ cpu_down(cpu);
+ }
++#endif
+ kexec_disable_iosapic();
+ }
+
+diff --git a/arch/ia64/sn/kernel/irq.c b/arch/ia64/sn/kernel/irq.c
+index 8c5bee0..8d2a1bf 100644
+--- a/arch/ia64/sn/kernel/irq.c
++++ b/arch/ia64/sn/kernel/irq.c
+@@ -205,7 +205,17 @@ static void sn_set_affinity_irq(unsigned int irq, cpumask_t mask)
+ (void)sn_retarget_vector(sn_irq_info, nasid, slice);
+ }
+
+-struct hw_interrupt_type irq_type_sn = {
++static void
++sn_mask_irq(unsigned int irq)
++{
++}
++
++static void
++sn_unmask_irq(unsigned int irq)
++{
++}
++
++struct irq_chip irq_type_sn = {
+ .name = "SN hub",
+ .startup = sn_startup_irq,
+ .shutdown = sn_shutdown_irq,
+@@ -213,6 +223,8 @@ struct hw_interrupt_type irq_type_sn = {
+ .disable = sn_disable_irq,
+ .ack = sn_ack_irq,
+ .end = sn_end_irq,
++ .mask = sn_mask_irq,
++ .unmask = sn_unmask_irq,
+ .set_affinity = sn_set_affinity_irq
+ };
+
+diff --git a/arch/m32r/kernel/process.c b/arch/m32r/kernel/process.c
+index 44cbe0c..a689e29 100644
+--- a/arch/m32r/kernel/process.c
++++ b/arch/m32r/kernel/process.c
+@@ -174,7 +174,7 @@ void show_regs(struct pt_regs * regs)
+ regs->acc1h, regs->acc1l);
+ #elif defined(CONFIG_ISA_M32R2) || defined(CONFIG_ISA_M32R)
+ printk("ACCH[%08lx]:ACCL[%08lx]\n", \
+- regs->acch, regs->accl);
++ regs->acc0h, regs->acc0l);
+ #else
+ #error unknown isa configuration
+ #endif
+diff --git a/arch/m32r/kernel/signal.c b/arch/m32r/kernel/signal.c
+index 092ea86..4b15605 100644
+--- a/arch/m32r/kernel/signal.c
++++ b/arch/m32r/kernel/signal.c
+@@ -109,19 +109,10 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc,
+ COPY(r10);
+ COPY(r11);
+ COPY(r12);
+-#if defined(CONFIG_ISA_M32R2) && defined(CONFIG_ISA_DSP_LEVEL2)
+ COPY(acc0h);
+ COPY(acc0l);
+- COPY(acc1h);
+- COPY(acc1l);
+-#elif defined(CONFIG_ISA_M32R2) || defined(CONFIG_ISA_M32R)
+- COPY(acch);
+- COPY(accl);
+- COPY(dummy_acc1h);
+- COPY(dummy_acc1l);
+-#else
+-#error unknown isa configuration
+-#endif
++ COPY(acc1h); /* ISA_DSP_LEVEL2 only */
++ COPY(acc1l); /* ISA_DSP_LEVEL2 only */
+ COPY(psw);
+ COPY(bpc);
+ COPY(bbpsw);
+@@ -196,19 +187,10 @@ setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs,
+ COPY(r10);
+ COPY(r11);
+ COPY(r12);
+-#if defined(CONFIG_ISA_M32R2) && defined(CONFIG_ISA_DSP_LEVEL2)
+ COPY(acc0h);
+ COPY(acc0l);
+- COPY(acc1h);
+- COPY(acc1l);
+-#elif defined(CONFIG_ISA_M32R2) || defined(CONFIG_ISA_M32R)
+- COPY(acch);
+- COPY(accl);
+- COPY(dummy_acc1h);
+- COPY(dummy_acc1l);
+-#else
+-#error unknown isa configuration
+-#endif
++ COPY(acc1h); /* ISA_DSP_LEVEL2 only */
++ COPY(acc1l); /* ISA_DSP_LEVEL2 only */
+ COPY(psw);
+ COPY(bpc);
+ COPY(bbpsw);
+diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S
+index 71b1fe5..97cedcd 100644
+--- a/arch/powerpc/kernel/head_64.S
++++ b/arch/powerpc/kernel/head_64.S
+@@ -613,7 +613,7 @@ system_call_pSeries:
+ /*** pSeries interrupt support ***/
+
+ /* moved from 0xf00 */
+- MASKABLE_EXCEPTION_PSERIES(., performance_monitor)
++ STD_EXCEPTION_PSERIES(., performance_monitor)
+
+ /*
+ * An interrupt came in while soft-disabled; clear EE in SRR1,
+diff --git a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c
+index c8b65ca..6d9857c 100644
+--- a/arch/ppc/kernel/ppc_ksyms.c
++++ b/arch/ppc/kernel/ppc_ksyms.c
+@@ -270,7 +270,7 @@ EXPORT_SYMBOL(mmu_hash_lock); /* For MOL */
+ extern long *intercept_table;
+ EXPORT_SYMBOL(intercept_table);
+ #endif /* CONFIG_PPC_STD_MMU */
+-#if defined(CONFIG_40x) || defined(CONFIG_BOOKE)
++#ifdef CONFIG_PPC_DCR_NATIVE
+ EXPORT_SYMBOL(__mtdcr);
+ EXPORT_SYMBOL(__mfdcr);
+ #endif
+diff --git a/arch/sparc/kernel/of_device.c b/arch/sparc/kernel/of_device.c
+index dab6169..798b140 100644
+--- a/arch/sparc/kernel/of_device.c
++++ b/arch/sparc/kernel/of_device.c
+@@ -495,7 +495,7 @@ static void __init build_device_resources(struct of_device *op,
+ u32 *reg = (preg + (index * ((na + ns) * 4)));
+ struct device_node *dp = op->node;
+ struct device_node *pp = p_op->node;
+- struct of_bus *pbus;
++ struct of_bus *pbus, *dbus;
+ u64 size, result = OF_BAD_ADDR;
+ unsigned long flags;
+ int dna, dns;
+@@ -516,6 +516,7 @@ static void __init build_device_resources(struct of_device *op,
+
+ dna = na;
+ dns = ns;
++ dbus = bus;
+
+ while (1) {
+ dp = pp;
+@@ -528,13 +529,13 @@ static void __init build_device_resources(struct of_device *op,
+ pbus = of_match_bus(pp);
+ pbus->count_cells(dp, &pna, &pns);
+
+- if (build_one_resource(dp, bus, pbus, addr,
++ if (build_one_resource(dp, dbus, pbus, addr,
+ dna, dns, pna))
+ break;
+
+ dna = pna;
+ dns = pns;
+- bus = pbus;
++ dbus = pbus;
+ }
+
+ build_res:
+diff --git a/arch/sparc64/kernel/ktlb.S b/arch/sparc64/kernel/ktlb.S
+index e492db8..d4024ac 100644
+--- a/arch/sparc64/kernel/ktlb.S
++++ b/arch/sparc64/kernel/ktlb.S
+@@ -138,9 +138,15 @@ kvmap_dtlb_4v:
+ brgez,pn %g4, kvmap_dtlb_nonlinear
+ nop
+
++#ifdef CONFIG_DEBUG_PAGEALLOC
++ /* Index through the base page size TSB even for linear
++ * mappings when using page allocation debugging.
++ */
++ KERN_TSB_LOOKUP_TL1(%g4, %g6, %g5, %g1, %g2, %g3, kvmap_dtlb_load)
++#else
+ /* Correct TAG_TARGET is already in %g6, check 4mb TSB. */
+ KERN_TSB4M_LOOKUP_TL1(%g6, %g5, %g1, %g2, %g3, kvmap_dtlb_load)
+-
++#endif
+ /* TSB entry address left in %g1, lookup linear PTE.
+ * Must preserve %g1 and %g6 (TAG).
+ */
+diff --git a/arch/sparc64/kernel/of_device.c b/arch/sparc64/kernel/of_device.c
+index b0f3e00..1f45985 100644
+--- a/arch/sparc64/kernel/of_device.c
++++ b/arch/sparc64/kernel/of_device.c
+@@ -581,7 +581,7 @@ static void __init build_device_resources(struct of_device *op,
+ u32 *reg = (preg + (index * ((na + ns) * 4)));
+ struct device_node *dp = op->node;
+ struct device_node *pp = p_op->node;
+- struct of_bus *pbus;
++ struct of_bus *pbus, *dbus;
+ u64 size, result = OF_BAD_ADDR;
+ unsigned long flags;
+ int dna, dns;
+@@ -599,6 +599,7 @@ static void __init build_device_resources(struct of_device *op,
+
+ dna = na;
+ dns = ns;
++ dbus = bus;
+
+ while (1) {
+ dp = pp;
+@@ -611,13 +612,13 @@ static void __init build_device_resources(struct of_device *op,
+ pbus = of_match_bus(pp);
+ pbus->count_cells(dp, &pna, &pns);
+
+- if (build_one_resource(dp, bus, pbus, addr,
++ if (build_one_resource(dp, dbus, pbus, addr,
+ dna, dns, pna))
+ break;
+
+ dna = pna;
+ dns = pns;
+- bus = pbus;
++ dbus = pbus;
+ }
+
+ build_res:
+@@ -708,7 +709,7 @@ static unsigned int __init pci_irq_swizzle(struct device_node *dp,
+ unsigned int irq)
+ {
+ struct linux_prom_pci_registers *regs;
+- unsigned int devfn, slot, ret;
++ unsigned int bus, devfn, slot, ret;
+
+ if (irq < 1 || irq > 4)
+ return irq;
+@@ -717,10 +718,46 @@ static unsigned int __init pci_irq_swizzle(struct device_node *dp,
+ if (!regs)
+ return irq;
+
++ bus = (regs->phys_hi >> 16) & 0xff;
+ devfn = (regs->phys_hi >> 8) & 0xff;
+ slot = (devfn >> 3) & 0x1f;
+
+- ret = ((irq - 1 + (slot & 3)) & 3) + 1;
++ if (pp->irq_trans) {
++ /* Derived from Table 8-3, U2P User's Manual. This branch
++ * is handling a PCI controller that lacks a proper set of
++ * interrupt-map and interrupt-map-mask properties. The
++ * Ultra-E450 is one example.
++ *
++ * The bit layout is BSSLL, where:
++ * B: 0 on bus A, 1 on bus B
++ * D: 2-bit slot number, derived from PCI device number as
++ * (dev - 1) for bus A, or (dev - 2) for bus B
++ * L: 2-bit line number
++ *
++ * Actually, more "portable" way to calculate the funky
++ * slot number is to subtract pbm->pci_first_slot from the
++ * device number, and that's exactly what the pre-OF
++ * sparc64 code did, but we're building this stuff generically
++ * using the OBP tree, not in the PCI controller layer.
++ */
++ if (bus & 0x80) {
++ /* PBM-A */
++ bus = 0x00;
++ slot = (slot - 1) << 2;
++ } else {
++ /* PBM-B */
++ bus = 0x10;
++ slot = (slot - 2) << 2;
++ }
++ irq -= 1;
++
++ ret = (bus | slot | irq);
++ } else {
++ /* Going through a PCI-PCI bridge that lacks a set of
++ * interrupt-map and interrupt-map-mask properties.
++ */
++ ret = ((irq - 1 + (slot & 3)) & 3) + 1;
++ }
+
+ return ret;
+ }
+diff --git a/arch/sparc64/kernel/pci_iommu.c b/arch/sparc64/kernel/pci_iommu.c
+index 2e7f142..7aca0f3 100644
+--- a/arch/sparc64/kernel/pci_iommu.c
++++ b/arch/sparc64/kernel/pci_iommu.c
+@@ -64,7 +64,7 @@ static void __iommu_flushall(struct pci_iommu *iommu)
+ #define IOPTE_IS_DUMMY(iommu, iopte) \
+ ((iopte_val(*iopte) & IOPTE_PAGE) == (iommu)->dummy_page_pa)
+
+-static void inline iopte_make_dummy(struct pci_iommu *iommu, iopte_t *iopte)
++static inline void iopte_make_dummy(struct pci_iommu *iommu, iopte_t *iopte)
+ {
+ unsigned long val = iopte_val(*iopte);
+
+diff --git a/arch/sparc64/kernel/sbus.c b/arch/sparc64/kernel/sbus.c
+index 01d6d86..14f78fb 100644
+--- a/arch/sparc64/kernel/sbus.c
++++ b/arch/sparc64/kernel/sbus.c
+@@ -24,48 +24,25 @@
+
+ #include "iommu_common.h"
+
+-/* These should be allocated on an SMP_CACHE_BYTES
+- * aligned boundary for optimal performance.
+- *
+- * On SYSIO, using an 8K page size we have 1GB of SBUS
+- * DMA space mapped. We divide this space into equally
+- * sized clusters. We allocate a DMA mapping from the
+- * cluster that matches the order of the allocation, or
+- * if the order is greater than the number of clusters,
+- * we try to allocate from the last cluster.
+- */
+-
+-#define NCLUSTERS 8UL
+-#define ONE_GIG (1UL * 1024UL * 1024UL * 1024UL)
+-#define CLUSTER_SIZE (ONE_GIG / NCLUSTERS)
+-#define CLUSTER_MASK (CLUSTER_SIZE - 1)
+-#define CLUSTER_NPAGES (CLUSTER_SIZE >> IO_PAGE_SHIFT)
+ #define MAP_BASE ((u32)0xc0000000)
+
++struct sbus_iommu_arena {
++ unsigned long *map;
++ unsigned int hint;
++ unsigned int limit;
++};
++
+ struct sbus_iommu {
+-/*0x00*/spinlock_t lock;
++ spinlock_t lock;
+
+-/*0x08*/iopte_t *page_table;
+-/*0x10*/unsigned long strbuf_regs;
+-/*0x18*/unsigned long iommu_regs;
+-/*0x20*/unsigned long sbus_control_reg;
++ struct sbus_iommu_arena arena;
+
+-/*0x28*/volatile unsigned long strbuf_flushflag;
++ iopte_t *page_table;
++ unsigned long strbuf_regs;
++ unsigned long iommu_regs;
++ unsigned long sbus_control_reg;
+
+- /* If NCLUSTERS is ever decresed to 4 or lower,
+- * you must increase the size of the type of
+- * these counters. You have been duly warned. -DaveM
+- */
+-/*0x30*/struct {
+- u16 next;
+- u16 flush;
+- } alloc_info[NCLUSTERS];
+-
+- /* The lowest used consistent mapping entry. Since
+- * we allocate consistent maps out of cluster 0 this
+- * is relative to the beginning of closter 0.
+- */
+-/*0x50*/u32 lowest_consistent_map;
++ volatile unsigned long strbuf_flushflag;
+ };
+
+ /* Offsets from iommu_regs */
+@@ -91,19 +68,6 @@ static void __iommu_flushall(struct sbus_iommu *iommu)
+ tag += 8UL;
+ }
+ upa_readq(iommu->sbus_control_reg);
+-
+- for (entry = 0; entry < NCLUSTERS; entry++) {
+- iommu->alloc_info[entry].flush =
+- iommu->alloc_info[entry].next;
+- }
+-}
+-
+-static void iommu_flush(struct sbus_iommu *iommu, u32 base, unsigned long npages)
+-{
+- while (npages--)
+- upa_writeq(base + (npages << IO_PAGE_SHIFT),
+- iommu->iommu_regs + IOMMU_FLUSH);
+- upa_readq(iommu->sbus_control_reg);
+ }
+
+ /* Offsets from strbuf_regs */
+@@ -156,178 +120,115 @@ static void sbus_strbuf_flush(struct sbus_iommu *iommu, u32 base, unsigned long
+ base, npages);
+ }
+
+-static iopte_t *alloc_streaming_cluster(struct sbus_iommu *iommu, unsigned long npages)
++/* Based largely upon the ppc64 iommu allocator. */
++static long sbus_arena_alloc(struct sbus_iommu *iommu, unsigned long npages)
+ {
+- iopte_t *iopte, *limit, *first, *cluster;
+- unsigned long cnum, ent, nent, flush_point, found;
+-
+- cnum = 0;
+- nent = 1;
+- while ((1UL << cnum) < npages)
+- cnum++;
+- if(cnum >= NCLUSTERS) {
+- nent = 1UL << (cnum - NCLUSTERS);
+- cnum = NCLUSTERS - 1;
+- }
+- iopte = iommu->page_table + (cnum * CLUSTER_NPAGES);
+-
+- if (cnum == 0)
+- limit = (iommu->page_table +
+- iommu->lowest_consistent_map);
+- else
+- limit = (iopte + CLUSTER_NPAGES);
+-
+- iopte += ((ent = iommu->alloc_info[cnum].next) << cnum);
+- flush_point = iommu->alloc_info[cnum].flush;
+-
+- first = iopte;
+- cluster = NULL;
+- found = 0;
+- for (;;) {
+- if (iopte_val(*iopte) == 0UL) {
+- found++;
+- if (!cluster)
+- cluster = iopte;
++ struct sbus_iommu_arena *arena = &iommu->arena;
++ unsigned long n, i, start, end, limit;
++ int pass;
++
++ limit = arena->limit;
++ start = arena->hint;
++ pass = 0;
++
++again:
++ n = find_next_zero_bit(arena->map, limit, start);
++ end = n + npages;
++ if (unlikely(end >= limit)) {
++ if (likely(pass < 1)) {
++ limit = start;
++ start = 0;
++ __iommu_flushall(iommu);
++ pass++;
++ goto again;
+ } else {
+- /* Used cluster in the way */
+- cluster = NULL;
+- found = 0;
++ /* Scanned the whole thing, give up. */
++ return -1;
+ }
++ }
+
+- if (found == nent)
+- break;
+-
+- iopte += (1 << cnum);
+- ent++;
+- if (iopte >= limit) {
+- iopte = (iommu->page_table + (cnum * CLUSTER_NPAGES));
+- ent = 0;
+-
+- /* Multiple cluster allocations must not wrap */
+- cluster = NULL;
+- found = 0;
++ for (i = n; i < end; i++) {
++ if (test_bit(i, arena->map)) {
++ start = i + 1;
++ goto again;
+ }
+- if (ent == flush_point)
+- __iommu_flushall(iommu);
+- if (iopte == first)
+- goto bad;
+ }
+
+- /* ent/iopte points to the last cluster entry we're going to use,
+- * so save our place for the next allocation.
+- */
+- if ((iopte + (1 << cnum)) >= limit)
+- ent = 0;
+- else
+- ent = ent + 1;
+- iommu->alloc_info[cnum].next = ent;
+- if (ent == flush_point)
+- __iommu_flushall(iommu);
+-
+- /* I've got your streaming cluster right here buddy boy... */
+- return cluster;
+-
+-bad:
+- printk(KERN_EMERG "sbus: alloc_streaming_cluster of npages(%ld) failed!\n",
+- npages);
+- return NULL;
++ for (i = n; i < end; i++)
++ __set_bit(i, arena->map);
++
++ arena->hint = end;
++
++ return n;
+ }
+
+-static void free_streaming_cluster(struct sbus_iommu *iommu, u32 base, unsigned long npages)
++static void sbus_arena_free(struct sbus_iommu_arena *arena, unsigned long base, unsigned long npages)
+ {
+- unsigned long cnum, ent, nent;
+- iopte_t *iopte;
++ unsigned long i;
+
+- cnum = 0;
+- nent = 1;
+- while ((1UL << cnum) < npages)
+- cnum++;
+- if(cnum >= NCLUSTERS) {
+- nent = 1UL << (cnum - NCLUSTERS);
+- cnum = NCLUSTERS - 1;
+- }
+- ent = (base & CLUSTER_MASK) >> (IO_PAGE_SHIFT + cnum);
+- iopte = iommu->page_table + ((base - MAP_BASE) >> IO_PAGE_SHIFT);
+- do {
+- iopte_val(*iopte) = 0UL;
+- iopte += 1 << cnum;
+- } while(--nent);
+-
+- /* If the global flush might not have caught this entry,
+- * adjust the flush point such that we will flush before
+- * ever trying to reuse it.
+- */
+-#define between(X,Y,Z) (((Z) - (Y)) >= ((X) - (Y)))
+- if (between(ent, iommu->alloc_info[cnum].next, iommu->alloc_info[cnum].flush))
+- iommu->alloc_info[cnum].flush = ent;
+-#undef between
++ for (i = base; i < (base + npages); i++)
++ __clear_bit(i, arena->map);
+ }
+
+-/* We allocate consistent mappings from the end of cluster zero. */
+-static iopte_t *alloc_consistent_cluster(struct sbus_iommu *iommu, unsigned long npages)
++static void sbus_iommu_table_init(struct sbus_iommu *iommu, unsigned int tsbsize)
+ {
+- iopte_t *iopte;
++ unsigned long tsbbase, order, sz, num_tsb_entries;
+
+- iopte = iommu->page_table + (1 * CLUSTER_NPAGES);
+- while (iopte > iommu->page_table) {
+- iopte--;
+- if (!(iopte_val(*iopte) & IOPTE_VALID)) {
+- unsigned long tmp = npages;
++ num_tsb_entries = tsbsize / sizeof(iopte_t);
+
+- while (--tmp) {
+- iopte--;
+- if (iopte_val(*iopte) & IOPTE_VALID)
+- break;
+- }
+- if (tmp == 0) {
+- u32 entry = (iopte - iommu->page_table);
++ /* Setup initial software IOMMU state. */
++ spin_lock_init(&iommu->lock);
+
+- if (entry < iommu->lowest_consistent_map)
+- iommu->lowest_consistent_map = entry;
+- return iopte;
+- }
+- }
++ /* Allocate and initialize the free area map. */
++ sz = num_tsb_entries / 8;
++ sz = (sz + 7UL) & ~7UL;
++ iommu->arena.map = kzalloc(sz, GFP_KERNEL);
++ if (!iommu->arena.map) {
++ prom_printf("PCI_IOMMU: Error, kmalloc(arena.map) failed.\n");
++ prom_halt();
++ }
++ iommu->arena.limit = num_tsb_entries;
++
++ /* Now allocate and setup the IOMMU page table itself. */
++ order = get_order(tsbsize);
++ tsbbase = __get_free_pages(GFP_KERNEL, order);
++ if (!tsbbase) {
++ prom_printf("IOMMU: Error, gfp(tsb) failed.\n");
++ prom_halt();
+ }
+- return NULL;
++ iommu->page_table = (iopte_t *)tsbbase;
++ memset(iommu->page_table, 0, tsbsize);
+ }
+
+-static void free_consistent_cluster(struct sbus_iommu *iommu, u32 base, unsigned long npages)
++static inline iopte_t *alloc_npages(struct sbus_iommu *iommu, unsigned long npages)
+ {
+- iopte_t *iopte = iommu->page_table + ((base - MAP_BASE) >> IO_PAGE_SHIFT);
++ long entry;
+
+- if ((iopte - iommu->page_table) == iommu->lowest_consistent_map) {
+- iopte_t *walk = iopte + npages;
+- iopte_t *limit;
++ entry = sbus_arena_alloc(iommu, npages);
++ if (unlikely(entry < 0))
++ return NULL;
+
+- limit = iommu->page_table + CLUSTER_NPAGES;
+- while (walk < limit) {
+- if (iopte_val(*walk) != 0UL)
+- break;
+- walk++;
+- }
+- iommu->lowest_consistent_map =
+- (walk - iommu->page_table);
+- }
++ return iommu->page_table + entry;
++}
+
+- while (npages--)
+- *iopte++ = __iopte(0UL);
++static inline void free_npages(struct sbus_iommu *iommu, dma_addr_t base, unsigned long npages)
++{
++ sbus_arena_free(&iommu->arena, base >> IO_PAGE_SHIFT, npages);
+ }
+
+ void *sbus_alloc_consistent(struct sbus_dev *sdev, size_t size, dma_addr_t *dvma_addr)
+ {
+- unsigned long order, first_page, flags;
+ struct sbus_iommu *iommu;
+ iopte_t *iopte;
++ unsigned long flags, order, first_page;
+ void *ret;
+ int npages;
+
+- if (size <= 0 || sdev == NULL || dvma_addr == NULL)
+- return NULL;
+-
+ size = IO_PAGE_ALIGN(size);
+ order = get_order(size);
+ if (order >= 10)
+ return NULL;
++
+ first_page = __get_free_pages(GFP_KERNEL|__GFP_COMP, order);
+ if (first_page == 0UL)
+ return NULL;
+@@ -336,108 +237,121 @@ void *sbus_alloc_consistent(struct sbus_dev *sdev, size_t size, dma_addr_t *dvma
+ iommu = sdev->bus->iommu;
+
+ spin_lock_irqsave(&iommu->lock, flags);
+- iopte = alloc_consistent_cluster(iommu, size >> IO_PAGE_SHIFT);
+- if (iopte == NULL) {
+- spin_unlock_irqrestore(&iommu->lock, flags);
++ iopte = alloc_npages(iommu, size >> IO_PAGE_SHIFT);
++ spin_unlock_irqrestore(&iommu->lock, flags);
++
++ if (unlikely(iopte == NULL)) {
+ free_pages(first_page, order);
+ return NULL;
+ }
+
+- /* Ok, we're committed at this point. */
+- *dvma_addr = MAP_BASE + ((iopte - iommu->page_table) << IO_PAGE_SHIFT);
++ *dvma_addr = (MAP_BASE +
++ ((iopte - iommu->page_table) << IO_PAGE_SHIFT));
+ ret = (void *) first_page;
+ npages = size >> IO_PAGE_SHIFT;
++ first_page = __pa(first_page);
+ while (npages--) {
+- *iopte++ = __iopte(IOPTE_VALID | IOPTE_CACHE | IOPTE_WRITE |
+- (__pa(first_page) & IOPTE_PAGE));
++ iopte_val(*iopte) = (IOPTE_VALID | IOPTE_CACHE |
++ IOPTE_WRITE |
++ (first_page & IOPTE_PAGE));
++ iopte++;
+ first_page += IO_PAGE_SIZE;
+ }
+- iommu_flush(iommu, *dvma_addr, size >> IO_PAGE_SHIFT);
+- spin_unlock_irqrestore(&iommu->lock, flags);
+
+ return ret;
+ }
+
+ void sbus_free_consistent(struct sbus_dev *sdev, size_t size, void *cpu, dma_addr_t dvma)
+ {
+- unsigned long order, npages;
+ struct sbus_iommu *iommu;
+-
+- if (size <= 0 || sdev == NULL || cpu == NULL)
+- return;
++ iopte_t *iopte;
++ unsigned long flags, order, npages;
+
+ npages = IO_PAGE_ALIGN(size) >> IO_PAGE_SHIFT;
+ iommu = sdev->bus->iommu;
++ iopte = iommu->page_table +
++ ((dvma - MAP_BASE) >> IO_PAGE_SHIFT);
++
++ spin_lock_irqsave(&iommu->lock, flags);
++
++ free_npages(iommu, dvma - MAP_BASE, npages);
+
+- spin_lock_irq(&iommu->lock);
+- free_consistent_cluster(iommu, dvma, npages);
+- iommu_flush(iommu, dvma, npages);
+- spin_unlock_irq(&iommu->lock);
++ spin_unlock_irqrestore(&iommu->lock, flags);
+
+ order = get_order(size);
+ if (order < 10)
+ free_pages((unsigned long)cpu, order);
+ }
+
+-dma_addr_t sbus_map_single(struct sbus_dev *sdev, void *ptr, size_t size, int dir)
++dma_addr_t sbus_map_single(struct sbus_dev *sdev, void *ptr, size_t sz, int direction)
+ {
+- struct sbus_iommu *iommu = sdev->bus->iommu;
+- unsigned long npages, pbase, flags;
+- iopte_t *iopte;
+- u32 dma_base, offset;
+- unsigned long iopte_bits;
++ struct sbus_iommu *iommu;
++ iopte_t *base;
++ unsigned long flags, npages, oaddr;
++ unsigned long i, base_paddr;
++ u32 bus_addr, ret;
++ unsigned long iopte_protection;
++
++ iommu = sdev->bus->iommu;
+
+- if (dir == SBUS_DMA_NONE)
++ if (unlikely(direction == SBUS_DMA_NONE))
+ BUG();
+
+- pbase = (unsigned long) ptr;
+- offset = (u32) (pbase & ~IO_PAGE_MASK);
+- size = (IO_PAGE_ALIGN(pbase + size) - (pbase & IO_PAGE_MASK));
+- pbase = (unsigned long) __pa(pbase & IO_PAGE_MASK);
++ oaddr = (unsigned long)ptr;
++ npages = IO_PAGE_ALIGN(oaddr + sz) - (oaddr & IO_PAGE_MASK);
++ npages >>= IO_PAGE_SHIFT;
+
+ spin_lock_irqsave(&iommu->lock, flags);
+- npages = size >> IO_PAGE_SHIFT;
+- iopte = alloc_streaming_cluster(iommu, npages);
+- if (iopte == NULL)
+- goto bad;
+- dma_base = MAP_BASE + ((iopte - iommu->page_table) << IO_PAGE_SHIFT);
+- npages = size >> IO_PAGE_SHIFT;
+- iopte_bits = IOPTE_VALID | IOPTE_STBUF | IOPTE_CACHE;
+- if (dir != SBUS_DMA_TODEVICE)
+- iopte_bits |= IOPTE_WRITE;
+- while (npages--) {
+- *iopte++ = __iopte(iopte_bits | (pbase & IOPTE_PAGE));
+- pbase += IO_PAGE_SIZE;
+- }
+- npages = size >> IO_PAGE_SHIFT;
++ base = alloc_npages(iommu, npages);
+ spin_unlock_irqrestore(&iommu->lock, flags);
+
+- return (dma_base | offset);
++ if (unlikely(!base))
++ BUG();
+
+-bad:
+- spin_unlock_irqrestore(&iommu->lock, flags);
+- BUG();
+- return 0;
++ bus_addr = (MAP_BASE +
++ ((base - iommu->page_table) << IO_PAGE_SHIFT));
++ ret = bus_addr | (oaddr & ~IO_PAGE_MASK);
++ base_paddr = __pa(oaddr & IO_PAGE_MASK);
++
++ iopte_protection = IOPTE_VALID | IOPTE_STBUF | IOPTE_CACHE;
++ if (direction != SBUS_DMA_TODEVICE)
++ iopte_protection |= IOPTE_WRITE;
++
++ for (i = 0; i < npages; i++, base++, base_paddr += IO_PAGE_SIZE)
++ iopte_val(*base) = iopte_protection | base_paddr;
++
++ return ret;
+ }
+
+-void sbus_unmap_single(struct sbus_dev *sdev, dma_addr_t dma_addr, size_t size, int direction)
++void sbus_unmap_single(struct sbus_dev *sdev, dma_addr_t bus_addr, size_t sz, int direction)
+ {
+ struct sbus_iommu *iommu = sdev->bus->iommu;
+- u32 dma_base = dma_addr & IO_PAGE_MASK;
+- unsigned long flags;
++ iopte_t *base;
++ unsigned long flags, npages, i;
++
++ if (unlikely(direction == SBUS_DMA_NONE))
++ BUG();
++
++ npages = IO_PAGE_ALIGN(bus_addr + sz) - (bus_addr & IO_PAGE_MASK);
++ npages >>= IO_PAGE_SHIFT;
++ base = iommu->page_table +
++ ((bus_addr - MAP_BASE) >> IO_PAGE_SHIFT);
+
+- size = (IO_PAGE_ALIGN(dma_addr + size) - dma_base);
++ bus_addr &= IO_PAGE_MASK;
+
+ spin_lock_irqsave(&iommu->lock, flags);
+- free_streaming_cluster(iommu, dma_base, size >> IO_PAGE_SHIFT);
+- sbus_strbuf_flush(iommu, dma_base, size >> IO_PAGE_SHIFT, direction);
++ sbus_strbuf_flush(iommu, bus_addr, npages, direction);
++ for (i = 0; i < npages; i++)
++ iopte_val(base[i]) = 0UL;
++ free_npages(iommu, bus_addr - MAP_BASE, npages);
+ spin_unlock_irqrestore(&iommu->lock, flags);
+ }
+
+ #define SG_ENT_PHYS_ADDRESS(SG) \
+ (__pa(page_address((SG)->page)) + (SG)->offset)
+
+-static inline void fill_sg(iopte_t *iopte, struct scatterlist *sg, int nused, int nelems, unsigned long iopte_bits)
++static inline void fill_sg(iopte_t *iopte, struct scatterlist *sg,
++ int nused, int nelems, unsigned long iopte_protection)
+ {
+ struct scatterlist *dma_sg = sg;
+ struct scatterlist *sg_end = sg + nelems;
+@@ -462,7 +376,7 @@ static inline void fill_sg(iopte_t *iopte, struct scatterlist *sg, int nused, in
+ for (;;) {
+ unsigned long tmp;
+
+- tmp = (unsigned long) SG_ENT_PHYS_ADDRESS(sg);
++ tmp = SG_ENT_PHYS_ADDRESS(sg);
+ len = sg->length;
+ if (((tmp ^ pteval) >> IO_PAGE_SHIFT) != 0UL) {
+ pteval = tmp & IO_PAGE_MASK;
+@@ -478,7 +392,7 @@ static inline void fill_sg(iopte_t *iopte, struct scatterlist *sg, int nused, in
+ sg++;
+ }
+
+- pteval = ((pteval & IOPTE_PAGE) | iopte_bits);
++ pteval = iopte_protection | (pteval & IOPTE_PAGE);
+ while (len > 0) {
+ *iopte++ = __iopte(pteval);
+ pteval += IO_PAGE_SIZE;
+@@ -509,103 +423,111 @@ static inline void fill_sg(iopte_t *iopte, struct scatterlist *sg, int nused, in
+ }
+ }
+
+-int sbus_map_sg(struct sbus_dev *sdev, struct scatterlist *sg, int nents, int dir)
++int sbus_map_sg(struct sbus_dev *sdev, struct scatterlist *sglist, int nelems, int direction)
+ {
+- struct sbus_iommu *iommu = sdev->bus->iommu;
+- unsigned long flags, npages;
+- iopte_t *iopte;
++ struct sbus_iommu *iommu;
++ unsigned long flags, npages, iopte_protection;
++ iopte_t *base;
+ u32 dma_base;
+ struct scatterlist *sgtmp;
+ int used;
+- unsigned long iopte_bits;
+-
+- if (dir == SBUS_DMA_NONE)
+- BUG();
+
+ /* Fast path single entry scatterlists. */
+- if (nents == 1) {
+- sg->dma_address =
++ if (nelems == 1) {
++ sglist->dma_address =
+ sbus_map_single(sdev,
+- (page_address(sg->page) + sg->offset),
+- sg->length, dir);
+- sg->dma_length = sg->length;
++ (page_address(sglist->page) + sglist->offset),
++ sglist->length, direction);
++ sglist->dma_length = sglist->length;
+ return 1;
+ }
+
+- npages = prepare_sg(sg, nents);
++ iommu = sdev->bus->iommu;
++
++ if (unlikely(direction == SBUS_DMA_NONE))
++ BUG();
++
++ npages = prepare_sg(sglist, nelems);
+
+ spin_lock_irqsave(&iommu->lock, flags);
+- iopte = alloc_streaming_cluster(iommu, npages);
+- if (iopte == NULL)
+- goto bad;
+- dma_base = MAP_BASE + ((iopte - iommu->page_table) << IO_PAGE_SHIFT);
++ base = alloc_npages(iommu, npages);
++ spin_unlock_irqrestore(&iommu->lock, flags);
++
++ if (unlikely(base == NULL))
++ BUG();
++
++ dma_base = MAP_BASE +
++ ((base - iommu->page_table) << IO_PAGE_SHIFT);
+
+ /* Normalize DVMA addresses. */
+- sgtmp = sg;
+- used = nents;
++ used = nelems;
+
++ sgtmp = sglist;
+ while (used && sgtmp->dma_length) {
+ sgtmp->dma_address += dma_base;
+ sgtmp++;
+ used--;
+ }
+- used = nents - used;
++ used = nelems - used;
+
+- iopte_bits = IOPTE_VALID | IOPTE_STBUF | IOPTE_CACHE;
+- if (dir != SBUS_DMA_TODEVICE)
+- iopte_bits |= IOPTE_WRITE;
++ iopte_protection = IOPTE_VALID | IOPTE_STBUF | IOPTE_CACHE;
++ if (direction != SBUS_DMA_TODEVICE)
++ iopte_protection |= IOPTE_WRITE;
++
++ fill_sg(base, sglist, used, nelems, iopte_protection);
+
+- fill_sg(iopte, sg, used, nents, iopte_bits);
+ #ifdef VERIFY_SG
+- verify_sglist(sg, nents, iopte, npages);
++ verify_sglist(sglist, nelems, base, npages);
+ #endif
+- spin_unlock_irqrestore(&iommu->lock, flags);
+
+ return used;
+-
+-bad:
+- spin_unlock_irqrestore(&iommu->lock, flags);
+- BUG();
+- return 0;
+ }
+
+-void sbus_unmap_sg(struct sbus_dev *sdev, struct scatterlist *sg, int nents, int direction)
++void sbus_unmap_sg(struct sbus_dev *sdev, struct scatterlist *sglist, int nelems, int direction)
+ {
+- unsigned long size, flags;
+ struct sbus_iommu *iommu;
+- u32 dvma_base;
+- int i;
++ iopte_t *base;
++ unsigned long flags, i, npages;
++ u32 bus_addr;
+
+- /* Fast path single entry scatterlists. */
+- if (nents == 1) {
+- sbus_unmap_single(sdev, sg->dma_address, sg->dma_length, direction);
+- return;
+- }
++ if (unlikely(direction == SBUS_DMA_NONE))
++ BUG();
++
++ iommu = sdev->bus->iommu;
++
++ bus_addr = sglist->dma_address & IO_PAGE_MASK;
+
+- dvma_base = sg[0].dma_address & IO_PAGE_MASK;
+- for (i = 0; i < nents; i++) {
+- if (sg[i].dma_length == 0)
++ for (i = 1; i < nelems; i++)
++ if (sglist[i].dma_length == 0)
+ break;
+- }
+ i--;
+- size = IO_PAGE_ALIGN(sg[i].dma_address + sg[i].dma_length) - dvma_base;
++ npages = (IO_PAGE_ALIGN(sglist[i].dma_address + sglist[i].dma_length) -
++ bus_addr) >> IO_PAGE_SHIFT;
++
++ base = iommu->page_table +
++ ((bus_addr - MAP_BASE) >> IO_PAGE_SHIFT);
+
+- iommu = sdev->bus->iommu;
+ spin_lock_irqsave(&iommu->lock, flags);
+- free_streaming_cluster(iommu, dvma_base, size >> IO_PAGE_SHIFT);
+- sbus_strbuf_flush(iommu, dvma_base, size >> IO_PAGE_SHIFT, direction);
++ sbus_strbuf_flush(iommu, bus_addr, npages, direction);
++ for (i = 0; i < npages; i++)
++ iopte_val(base[i]) = 0UL;
++ free_npages(iommu, bus_addr - MAP_BASE, npages);
+ spin_unlock_irqrestore(&iommu->lock, flags);
+ }
+
+-void sbus_dma_sync_single_for_cpu(struct sbus_dev *sdev, dma_addr_t base, size_t size, int direction)
++void sbus_dma_sync_single_for_cpu(struct sbus_dev *sdev, dma_addr_t bus_addr, size_t sz, int direction)
+ {
+- struct sbus_iommu *iommu = sdev->bus->iommu;
+- unsigned long flags;
++ struct sbus_iommu *iommu;
++ unsigned long flags, npages;
++
++ iommu = sdev->bus->iommu;
+
+- size = (IO_PAGE_ALIGN(base + size) - (base & IO_PAGE_MASK));
++ npages = IO_PAGE_ALIGN(bus_addr + sz) - (bus_addr & IO_PAGE_MASK);
++ npages >>= IO_PAGE_SHIFT;
++ bus_addr &= IO_PAGE_MASK;
+
+ spin_lock_irqsave(&iommu->lock, flags);
+- sbus_strbuf_flush(iommu, base & IO_PAGE_MASK, size >> IO_PAGE_SHIFT, direction);
++ sbus_strbuf_flush(iommu, bus_addr, npages, direction);
+ spin_unlock_irqrestore(&iommu->lock, flags);
+ }
+
+@@ -613,23 +535,25 @@ void sbus_dma_sync_single_for_device(struct sbus_dev *sdev, dma_addr_t base, siz
+ {
+ }
+
+-void sbus_dma_sync_sg_for_cpu(struct sbus_dev *sdev, struct scatterlist *sg, int nents, int direction)
++void sbus_dma_sync_sg_for_cpu(struct sbus_dev *sdev, struct scatterlist *sglist, int nelems, int direction)
+ {
+- struct sbus_iommu *iommu = sdev->bus->iommu;
+- unsigned long flags, size;
+- u32 base;
+- int i;
++ struct sbus_iommu *iommu;
++ unsigned long flags, npages, i;
++ u32 bus_addr;
++
++ iommu = sdev->bus->iommu;
+
+- base = sg[0].dma_address & IO_PAGE_MASK;
+- for (i = 0; i < nents; i++) {
+- if (sg[i].dma_length == 0)
++ bus_addr = sglist[0].dma_address & IO_PAGE_MASK;
++ for (i = 0; i < nelems; i++) {
++ if (!sglist[i].dma_length)
+ break;
+ }
+ i--;
+- size = IO_PAGE_ALIGN(sg[i].dma_address + sg[i].dma_length) - base;
++ npages = (IO_PAGE_ALIGN(sglist[i].dma_address + sglist[i].dma_length)
++ - bus_addr) >> IO_PAGE_SHIFT;
+
+ spin_lock_irqsave(&iommu->lock, flags);
+- sbus_strbuf_flush(iommu, base, size >> IO_PAGE_SHIFT, direction);
++ sbus_strbuf_flush(iommu, bus_addr, npages, direction);
+ spin_unlock_irqrestore(&iommu->lock, flags);
+ }
+
+@@ -1104,7 +1028,7 @@ static void __init sbus_iommu_init(int __node, struct sbus_bus *sbus)
+ struct linux_prom64_registers *pr;
+ struct device_node *dp;
+ struct sbus_iommu *iommu;
+- unsigned long regs, tsb_base;
++ unsigned long regs;
+ u64 control;
+ int i;
+
+@@ -1132,14 +1056,6 @@ static void __init sbus_iommu_init(int __node, struct sbus_bus *sbus)
+
+ memset(iommu, 0, sizeof(*iommu));
+
+- /* We start with no consistent mappings. */
+- iommu->lowest_consistent_map = CLUSTER_NPAGES;
+-
+- for (i = 0; i < NCLUSTERS; i++) {
+- iommu->alloc_info[i].flush = 0;
+- iommu->alloc_info[i].next = 0;
+- }
+-
+ /* Setup spinlock. */
+ spin_lock_init(&iommu->lock);
+
+@@ -1159,25 +1075,13 @@ static void __init sbus_iommu_init(int __node, struct sbus_bus *sbus)
+ sbus->portid, regs);
+
+ /* Setup for TSB_SIZE=7, TBW_SIZE=0, MMU_DE=1, MMU_EN=1 */
++ sbus_iommu_table_init(iommu, IO_TSB_SIZE);
++
+ control = upa_readq(iommu->iommu_regs + IOMMU_CONTROL);
+ control = ((7UL << 16UL) |
+ (0UL << 2UL) |
+ (1UL << 1UL) |
+ (1UL << 0UL));
+-
+- /* Using the above configuration we need 1MB iommu page
+- * table (128K ioptes * 8 bytes per iopte). This is
+- * page order 7 on UltraSparc.
+- */
+- tsb_base = __get_free_pages(GFP_ATOMIC, get_order(IO_TSB_SIZE));
+- if (tsb_base == 0UL) {
+- prom_printf("sbus_iommu_init: Fatal error, cannot alloc TSB table.\n");
+- prom_halt();
+- }
+-
+- iommu->page_table = (iopte_t *) tsb_base;
+- memset(iommu->page_table, 0, IO_TSB_SIZE);
+-
+ upa_writeq(control, iommu->iommu_regs + IOMMU_CONTROL);
+
+ /* Clean out any cruft in the IOMMU using
+@@ -1195,7 +1099,7 @@ static void __init sbus_iommu_init(int __node, struct sbus_bus *sbus)
+ upa_readq(iommu->sbus_control_reg);
+
+ /* Give the TSB to SYSIO. */
+- upa_writeq(__pa(tsb_base), iommu->iommu_regs + IOMMU_TSBBASE);
++ upa_writeq(__pa(iommu->page_table), iommu->iommu_regs + IOMMU_TSBBASE);
+
+ /* Setup streaming buffer, DE=1 SB_EN=1 */
+ control = (1UL << 1UL) | (1UL << 0UL);
+diff --git a/arch/sparc64/kernel/sys32.S b/arch/sparc64/kernel/sys32.S
+index c09ab4b..010a737 100644
+--- a/arch/sparc64/kernel/sys32.S
++++ b/arch/sparc64/kernel/sys32.S
+@@ -91,7 +91,6 @@ SIGN1(sys32_select, compat_sys_select, %o0)
+ SIGN1(sys32_mkdir, sys_mkdir, %o1)
+ SIGN3(sys32_futex, compat_sys_futex, %o1, %o2, %o5)
+ SIGN1(sys32_sysfs, compat_sys_sysfs, %o0)
+-SIGN3(sys32_ipc, compat_sys_ipc, %o1, %o2, %o3)
+ SIGN2(sys32_sendfile, compat_sys_sendfile, %o0, %o1)
+ SIGN2(sys32_sendfile64, compat_sys_sendfile64, %o0, %o1)
+ SIGN1(sys32_prctl, sys_prctl, %o0)
+diff --git a/arch/sparc64/kernel/systbls.S b/arch/sparc64/kernel/systbls.S
+index 9a80267..46f870b 100644
+--- a/arch/sparc64/kernel/systbls.S
++++ b/arch/sparc64/kernel/systbls.S
+@@ -62,7 +62,7 @@ sys_call_table32:
+ /*200*/ .word sys32_ssetmask, sys_sigsuspend, compat_sys_newlstat, sys_uselib, compat_sys_old_readdir
+ .word sys32_readahead, sys32_socketcall, sys32_syslog, sys32_lookup_dcookie, sys32_fadvise64
+ /*210*/ .word sys32_fadvise64_64, sys32_tgkill, sys32_waitpid, sys_swapoff, sys32_sysinfo
+- .word sys32_ipc, sys32_sigreturn, sys_clone, sys32_ioprio_get, compat_sys_adjtimex
++ .word compat_sys_ipc, sys32_sigreturn, sys_clone, sys32_ioprio_get, compat_sys_adjtimex
+ /*220*/ .word sys32_sigprocmask, sys_ni_syscall, sys32_delete_module, sys_ni_syscall, sys32_getpgid
+ .word sys32_bdflush, sys32_sysfs, sys_nis_syscall, sys32_setfsuid16, sys32_setfsgid16
+ /*230*/ .word sys32_select, compat_sys_time, sys32_splice, compat_sys_stime, compat_sys_statfs64
+diff --git a/arch/sparc64/kernel/tsb.S b/arch/sparc64/kernel/tsb.S
+index eedf94f..10adb2f 100644
+--- a/arch/sparc64/kernel/tsb.S
++++ b/arch/sparc64/kernel/tsb.S
+@@ -546,6 +546,7 @@ NGtsb_init:
+ subcc %o1, 0x100, %o1
+ bne,pt %xcc, 1b
+ add %o0, 0x100, %o0
++ membar #Sync
+ retl
+ wr %g2, 0x0, %asi
+ .size NGtsb_init, .-NGtsb_init
+diff --git a/arch/sparc64/lib/NGbzero.S b/arch/sparc64/lib/NGbzero.S
+index e86baec..f10e452 100644
+--- a/arch/sparc64/lib/NGbzero.S
++++ b/arch/sparc64/lib/NGbzero.S
+@@ -88,6 +88,7 @@ NGbzero_loop:
+ bne,pt %xcc, NGbzero_loop
+ add %o0, 64, %o0
+
++ membar #Sync
+ wr %o4, 0x0, %asi
+ brz,pn %o1, NGbzero_done
+ NGbzero_medium:
+diff --git a/arch/sparc64/lib/NGmemcpy.S b/arch/sparc64/lib/NGmemcpy.S
+index 8e522b3..66063a9 100644
+--- a/arch/sparc64/lib/NGmemcpy.S
++++ b/arch/sparc64/lib/NGmemcpy.S
+@@ -247,6 +247,8 @@ FUNC_NAME: /* %o0=dst, %o1=src, %o2=len */
+ /* fall through */
+
+ 60:
++ membar #Sync
++
+ /* %o2 contains any final bytes still needed to be copied
+ * over. If anything is left, we copy it one byte at a time.
+ */
+diff --git a/arch/sparc64/lib/NGpage.S b/arch/sparc64/lib/NGpage.S
+index 7d7c3bb..8ce3a0c 100644
+--- a/arch/sparc64/lib/NGpage.S
++++ b/arch/sparc64/lib/NGpage.S
+@@ -41,6 +41,7 @@ NGcopy_user_page: /* %o0=dest, %o1=src, %o2=vaddr */
+ subcc %g7, 64, %g7
+ bne,pt %xcc, 1b
+ add %o0, 32, %o0
++ membar #Sync
+ retl
+ nop
+
+@@ -63,6 +64,7 @@ NGclear_user_page: /* %o0=dest, %o1=vaddr */
+ subcc %g7, 64, %g7
+ bne,pt %xcc, 1b
+ add %o0, 32, %o0
++ membar #Sync
+ retl
+ nop
+
+diff --git a/arch/sparc64/mm/hugetlbpage.c b/arch/sparc64/mm/hugetlbpage.c
+index 33fd0b2..00677b5 100644
+--- a/arch/sparc64/mm/hugetlbpage.c
++++ b/arch/sparc64/mm/hugetlbpage.c
+@@ -248,6 +248,7 @@ void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
+ if (!pte_present(*ptep) && pte_present(entry))
+ mm->context.huge_pte_count++;
+
++ addr &= HPAGE_MASK;
+ for (i = 0; i < (1 << HUGETLB_PAGE_ORDER); i++) {
+ set_pte_at(mm, addr, ptep, entry);
+ ptep++;
+@@ -266,6 +267,8 @@ pte_t huge_ptep_get_and_clear(struct mm_struct *mm, unsigned long addr,
+ if (pte_present(entry))
+ mm->context.huge_pte_count--;
+
++ addr &= HPAGE_MASK;
++
+ for (i = 0; i < (1 << HUGETLB_PAGE_ORDER); i++) {
+ pte_clear(mm, addr, ptep);
+ addr += PAGE_SIZE;
+diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c
+index 054822a..5391cd5 100644
+--- a/arch/sparc64/mm/init.c
++++ b/arch/sparc64/mm/init.c
+@@ -59,8 +59,10 @@ unsigned long kern_linear_pte_xor[2] __read_mostly;
+ */
+ unsigned long kpte_linear_bitmap[KPTE_BITMAP_BYTES / sizeof(unsigned long)];
+
++#ifndef CONFIG_DEBUG_PAGEALLOC
+ /* A special kernel TSB for 4MB and 256MB linear mappings. */
+ struct tsb swapper_4m_tsb[KERNEL_TSB4M_NENTRIES];
++#endif
+
+ #define MAX_BANKS 32
+
+@@ -1301,7 +1303,12 @@ static void __init tsb_phys_patch(void)
+ }
+
+ /* Don't mark as init, we give this to the Hypervisor. */
+-static struct hv_tsb_descr ktsb_descr[2];
++#ifndef CONFIG_DEBUG_PAGEALLOC
++#define NUM_KTSB_DESCR 2
++#else
++#define NUM_KTSB_DESCR 1
++#endif
++static struct hv_tsb_descr ktsb_descr[NUM_KTSB_DESCR];
+ extern struct tsb swapper_tsb[KERNEL_TSB_NENTRIES];
+
+ static void __init sun4v_ktsb_init(void)
+@@ -1340,6 +1347,7 @@ static void __init sun4v_ktsb_init(void)
+ ktsb_descr[0].tsb_base = ktsb_pa;
+ ktsb_descr[0].resv = 0;
+
++#ifndef CONFIG_DEBUG_PAGEALLOC
+ /* Second KTSB for 4MB/256MB mappings. */
+ ktsb_pa = (kern_base +
+ ((unsigned long)&swapper_4m_tsb[0] - KERNBASE));
+@@ -1352,6 +1360,7 @@ static void __init sun4v_ktsb_init(void)
+ ktsb_descr[1].ctx_idx = 0;
+ ktsb_descr[1].tsb_base = ktsb_pa;
+ ktsb_descr[1].resv = 0;
++#endif
+ }
+
+ void __cpuinit sun4v_ktsb_register(void)
+@@ -1364,7 +1373,7 @@ void __cpuinit sun4v_ktsb_register(void)
+ pa = kern_base + ((unsigned long)&ktsb_descr[0] - KERNBASE);
+
+ func = HV_FAST_MMU_TSB_CTX0;
+- arg0 = 2;
++ arg0 = NUM_KTSB_DESCR;
+ arg1 = pa;
+ __asm__ __volatile__("ta %6"
+ : "=&r" (func), "=&r" (arg0), "=&r" (arg1)
+@@ -1393,7 +1402,9 @@ void __init paging_init(void)
+
+ /* Invalidate both kernel TSBs. */
+ memset(swapper_tsb, 0x40, sizeof(swapper_tsb));
++#ifndef CONFIG_DEBUG_PAGEALLOC
+ memset(swapper_4m_tsb, 0x40, sizeof(swapper_4m_tsb));
++#endif
+
+ if (tlb_type == hypervisor)
+ sun4v_pgprot_init();
+@@ -1725,8 +1736,13 @@ static void __init sun4u_pgprot_init(void)
+ pg_iobits = (_PAGE_VALID | _PAGE_PRESENT_4U | __DIRTY_BITS_4U |
+ __ACCESS_BITS_4U | _PAGE_E_4U);
+
++#ifdef CONFIG_DEBUG_PAGEALLOC
++ kern_linear_pte_xor[0] = (_PAGE_VALID | _PAGE_SZBITS_4U) ^
++ 0xfffff80000000000;
++#else
+ kern_linear_pte_xor[0] = (_PAGE_VALID | _PAGE_SZ4MB_4U) ^
+ 0xfffff80000000000;
++#endif
+ kern_linear_pte_xor[0] |= (_PAGE_CP_4U | _PAGE_CV_4U |
+ _PAGE_P_4U | _PAGE_W_4U);
+
+@@ -1769,13 +1785,23 @@ static void __init sun4v_pgprot_init(void)
+ _PAGE_E = _PAGE_E_4V;
+ _PAGE_CACHE = _PAGE_CACHE_4V;
+
++#ifdef CONFIG_DEBUG_PAGEALLOC
++ kern_linear_pte_xor[0] = (_PAGE_VALID | _PAGE_SZBITS_4V) ^
++ 0xfffff80000000000;
++#else
+ kern_linear_pte_xor[0] = (_PAGE_VALID | _PAGE_SZ4MB_4V) ^
+ 0xfffff80000000000;
++#endif
+ kern_linear_pte_xor[0] |= (_PAGE_CP_4V | _PAGE_CV_4V |
+ _PAGE_P_4V | _PAGE_W_4V);
+
++#ifdef CONFIG_DEBUG_PAGEALLOC
++ kern_linear_pte_xor[1] = (_PAGE_VALID | _PAGE_SZBITS_4V) ^
++ 0xfffff80000000000;
++#else
+ kern_linear_pte_xor[1] = (_PAGE_VALID | _PAGE_SZ256MB_4V) ^
+ 0xfffff80000000000;
++#endif
+ kern_linear_pte_xor[1] |= (_PAGE_CP_4V | _PAGE_CV_4V |
+ _PAGE_P_4V | _PAGE_W_4V);
+
+diff --git a/arch/um/include/os.h b/arch/um/include/os.h
+index 13a86bd..4e9a13e 100644
+--- a/arch/um/include/os.h
++++ b/arch/um/include/os.h
+@@ -341,4 +341,6 @@ extern void maybe_sigio_broken(int fd, int read);
+ extern void sig_handler_common_skas(int sig, void *sc_ptr);
+ extern void user_signal(int sig, union uml_pt_regs *regs, int pid);
+
++extern int os_arch_prctl(int pid, int code, unsigned long *addr);
++
+ #endif
+diff --git a/arch/um/include/sysdep-x86_64/ptrace.h b/arch/um/include/sysdep-x86_64/ptrace.h
+index 66cb400..62403bd 100644
+--- a/arch/um/include/sysdep-x86_64/ptrace.h
++++ b/arch/um/include/sysdep-x86_64/ptrace.h
+@@ -104,10 +104,6 @@ union uml_pt_regs {
+ #endif
+ #ifdef UML_CONFIG_MODE_SKAS
+ struct skas_regs {
+- /* x86_64 ptrace uses sizeof(user_regs_struct) as its register
+- * file size, while i386 uses FRAME_SIZE. Therefore, we need
+- * to use UM_FRAME_SIZE here instead of HOST_FRAME_SIZE.
+- */
+ unsigned long regs[MAX_REG_NR];
+ unsigned long fp[HOST_FP_SIZE];
+ struct faultinfo faultinfo;
+diff --git a/arch/um/os-Linux/elf_aux.c b/arch/um/os-Linux/elf_aux.c
+index 5a99dd3..13c6cb5 100644
+--- a/arch/um/os-Linux/elf_aux.c
++++ b/arch/um/os-Linux/elf_aux.c
+@@ -40,6 +40,9 @@ __init void scan_elf_aux( char **envp)
+ switch ( auxv->a_type ) {
+ case AT_SYSINFO:
+ __kernel_vsyscall = auxv->a_un.a_val;
++ /* See if the page is under TASK_SIZE */
++ if (__kernel_vsyscall < (unsigned long) envp)
++ __kernel_vsyscall = 0;
+ break;
+ case AT_SYSINFO_EHDR:
+ vsyscall_ehdr = auxv->a_un.a_val;
+diff --git a/arch/um/os-Linux/sigio.c b/arch/um/os-Linux/sigio.c
+index 925a652..b2e1fd8 100644
+--- a/arch/um/os-Linux/sigio.c
++++ b/arch/um/os-Linux/sigio.c
+@@ -97,20 +97,22 @@ static int write_sigio_thread(void *unused)
+
+ static int need_poll(struct pollfds *polls, int n)
+ {
+- if(n <= polls->size){
+- polls->used = n;
++ struct pollfd *new;
++
++ if(n <= polls->size)
+ return 0;
+- }
+- kfree(polls->poll);
+- polls->poll = um_kmalloc_atomic(n * sizeof(struct pollfd));
+- if(polls->poll == NULL){
++
++ new = um_kmalloc_atomic(n * sizeof(struct pollfd));
++ if(new == NULL){
+ printk("need_poll : failed to allocate new pollfds\n");
+- polls->size = 0;
+- polls->used = 0;
+ return -ENOMEM;
+ }
++
++ memcpy(new, polls->poll, polls->used * sizeof(struct pollfd));
++ kfree(polls->poll);
++
++ polls->poll = new;
+ polls->size = n;
+- polls->used = n;
+ return 0;
+ }
+
+@@ -171,15 +173,15 @@ int add_sigio_fd(int fd)
+ goto out;
+ }
+
+- n = current_poll.used + 1;
+- err = need_poll(&next_poll, n);
++ n = current_poll.used;
++ err = need_poll(&next_poll, n + 1);
+ if(err)
+ goto out;
+
+- for(i = 0; i < current_poll.used; i++)
+- next_poll.poll[i] = current_poll.poll[i];
+-
+- next_poll.poll[n - 1] = *p;
++ memcpy(next_poll.poll, current_poll.poll,
++ current_poll.used * sizeof(struct pollfd));
++ next_poll.poll[n] = *p;
++ next_poll.used = n + 1;
+ update_thread();
+ out:
+ sigio_unlock();
+@@ -214,6 +216,7 @@ int ignore_sigio_fd(int fd)
+ if(p->fd != fd)